initial commit

This commit is contained in:
Gitea
2020-11-13 14:27:50 -05:00
commit e2015fd9bb
581 changed files with 101308 additions and 0 deletions

File diff suppressed because it is too large Load Diff

397
Modules/ActionBars/Bind.lua Normal file
View File

@@ -0,0 +1,397 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local AB = E:GetModule('ActionBars')
local Skins = E:GetModule('Skins')
local _G = _G
local tonumber, format = tonumber, format
local select, pairs, floor = select, pairs, floor
local CreateFrame = CreateFrame
local HideUIPanel = HideUIPanel
local GameTooltip_Hide = GameTooltip_Hide
local GameTooltip_ShowCompareItem = GameTooltip_ShowCompareItem
local GetBindingKey = GetBindingKey
local GetCurrentBindingSet = GetCurrentBindingSet
local GetMacroInfo = GetMacroInfo
local GetSpellBookItemName = GetSpellBookItemName
local InCombatLockdown = InCombatLockdown
local IsAddOnLoaded = IsAddOnLoaded
local IsAltKeyDown, IsControlKeyDown = IsAltKeyDown, IsControlKeyDown
local IsShiftKeyDown, IsModifiedClick = IsShiftKeyDown, IsModifiedClick
local LoadBindings, SaveBindings = LoadBindings, SaveBindings
local SecureActionButton_OnClick = SecureActionButton_OnClick
local SetBinding = SetBinding
local GameTooltip = GameTooltip
local SpellBook_GetSpellBookSlot = SpellBook_GetSpellBookSlot
local MAX_ACCOUNT_MACROS = MAX_ACCOUNT_MACROS
local CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP = CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP
local CHARACTER_SPECIFIC_KEYBINDINGS = CHARACTER_SPECIFIC_KEYBINDINGS
-- GLOBALS: ElvUIBindPopupWindow, ElvUIBindPopupWindowCheckButton
local bind = CreateFrame('Frame', 'ElvUI_KeyBinder', E.UIParent)
function AB:ActivateBindMode()
if InCombatLockdown() then return end
bind.active = true
E:StaticPopupSpecial_Show(ElvUIBindPopupWindow)
AB:RegisterEvent('PLAYER_REGEN_DISABLED', 'DeactivateBindMode', false)
end
function AB:DeactivateBindMode(save)
if save then
SaveBindings(GetCurrentBindingSet())
E:Print(L["Binds Saved"])
else
LoadBindings(GetCurrentBindingSet())
E:Print(L["Binds Discarded"])
end
bind.active = false
self:BindHide()
self:UnregisterEvent('PLAYER_REGEN_DISABLED')
E:StaticPopupSpecial_Hide(ElvUIBindPopupWindow)
AB.bindingsChanged = false
end
function AB:BindHide()
bind:ClearAllPoints()
bind:Hide()
if not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:Hide()
end
end
function AB:BindListener(key)
AB.bindingsChanged = true
if key == 'ESCAPE' then
if bind.button.bindings then
for i = 1, #bind.button.bindings do
SetBinding(bind.button.bindings[i])
end
end
E:Print(format(L["All keybindings cleared for |cff00ff00%s|r."], bind.name))
self:BindUpdate(bind.button, bind.spellmacro)
if bind.spellmacro~='MACRO' and not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:Hide()
end
return
end
--Check if this button can open a flyout menu
local isFlyout = (bind.button.FlyoutArrow and bind.button.FlyoutArrow:IsShown())
if key == 'LSHIFT' or key == 'RSHIFT' or key == 'LCTRL' or key == 'RCTRL'
or key == 'LALT' or key == 'RALT' or key == 'UNKNOWN' then return end
--Redirect LeftButton click to open flyout
if key == 'LeftButton' and isFlyout then
SecureActionButton_OnClick(bind.button)
end
if key == 'MiddleButton' then key = 'BUTTON3' end
if key:find('Button%d') then key = key:upper() end
local allowBinding = not isFlyout or (key ~= 'LeftButton') --Don't attempt to bind left mouse button for flyout buttons
if allowBinding and bind.button.bindstring then
local alt = IsAltKeyDown() and 'ALT-' or ''
local ctrl = IsControlKeyDown() and 'CTRL-' or ''
local shift = IsShiftKeyDown() and 'SHIFT-' or ''
SetBinding(alt..ctrl..shift..key, bind.button.bindstring)
E:Print(alt..ctrl..shift..key..L[" |cff00ff00bound to |r"]..bind.name..'.')
end
self:BindUpdate(bind.button, bind.spellmacro)
if bind.spellmacro~='MACRO' and bind.spellmacro~='FLYOUT' and not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:Hide()
end
end
function AB:DisplayBindsTooltip()
GameTooltip:SetOwner(bind, 'ANCHOR_TOP')
GameTooltip:Point('BOTTOM', bind, 'TOP', 0, 1)
GameTooltip:AddLine(bind.name, 1, 1, 1)
end
function AB:DisplayBindings()
if #bind.button.bindings == 0 then
GameTooltip:AddLine(L["No bindings set."], .6, .6, .6)
else
GameTooltip:AddDoubleLine(L["Binding"], L["Key"], .6, .6, .6, .6, .6, .6)
for i = 1, #bind.button.bindings do
GameTooltip:AddDoubleLine(L["Binding"]..i, bind.button.bindings[i], 1, 1, 1)
end
end
end
function AB:BindTooltip(triggerTooltip)
if GameTooltip:IsForbidden() then return end
if triggerTooltip then -- this is needed for some tooltip magic, also it helps show a tooltip when a spell isnt there
AB:DisplayBindsTooltip()
GameTooltip:AddLine(L["Trigger"])
GameTooltip:Show()
GameTooltip:SetScript('OnHide', function(tt)
AB:DisplayBindsTooltip()
AB:DisplayBindings()
tt:Show()
tt:SetScript('OnHide', nil)
end)
else
AB:DisplayBindsTooltip()
AB:DisplayBindings()
GameTooltip:Show()
end
end
function AB:BindUpdate(button, spellmacro)
if not bind.active or InCombatLockdown() then return end
local triggerTooltip = false
bind.button = button
bind.spellmacro = spellmacro
bind.name = nil
bind:ClearAllPoints()
bind:SetAllPoints(button)
bind:Show()
_G.ShoppingTooltip1:Hide()
button.bindstring = nil -- keep this clean
if spellmacro == 'FLYOUT' then
bind.name = button.spellName
button.bindstring = spellmacro..' '..bind.name
elseif spellmacro == 'SPELL' then
button.id = SpellBook_GetSpellBookSlot(button)
bind.name = GetSpellBookItemName(button.id, _G.SpellBookFrame.bookType)
button.bindstring = spellmacro..' '..bind.name
elseif spellmacro == 'MACRO' then
button.id = button:GetID()
-- no clue what this is, leaving it alone tho lol
if floor(.5+select(2,_G.MacroFrameTab1Text:GetTextColor())*10)/10==.8 then
button.id = button.id + MAX_ACCOUNT_MACROS
end
bind.name = GetMacroInfo(button.id)
button.bindstring = spellmacro..' '..bind.name
elseif spellmacro == 'MICRO' then
bind.name = button.tooltipText
button.bindstring = button.commandName
triggerTooltip = true
elseif spellmacro == 'BAG' then
if button.itemID then
bind.name = button.name
button.bindstring = 'ITEM item:'..button.itemID
triggerTooltip = true
end
else
bind.name = button:GetName()
if not bind.name then return end
triggerTooltip = true
if button.keyBoundTarget then
button.bindstring = button.keyBoundTarget
elseif button.commandName then
button.bindstring = button.commandName
elseif button.action then
local action = tonumber(button.action)
local modact = 1+(action-1)%12
if bind.name == 'ExtraActionButton1' then
button.bindstring = 'EXTRAACTIONBUTTON1'
elseif action < 25 or action > 72 then
button.bindstring = 'ACTIONBUTTON'..modact
elseif action < 73 and action > 60 then
button.bindstring = 'MULTIACTIONBAR1BUTTON'..modact
elseif action < 61 and action > 48 then
button.bindstring = 'MULTIACTIONBAR2BUTTON'..modact
elseif action < 49 and action > 36 then
button.bindstring = 'MULTIACTIONBAR4BUTTON'..modact
elseif action < 37 and action > 24 then
button.bindstring = 'MULTIACTIONBAR3BUTTON'..modact
end
end
end
if button.bindstring then
button.bindings = {GetBindingKey(button.bindstring)}
AB:BindTooltip(triggerTooltip)
end
end
local elapsed = 0
function AB:Tooltip_OnUpdate(tooltip, e)
if tooltip:IsForbidden() then return end
elapsed = elapsed + e
if elapsed < .2 then return else elapsed = 0 end
local compareItems = IsModifiedClick('COMPAREITEMS')
if not tooltip.comparing and compareItems and tooltip:GetItem() then
GameTooltip_ShowCompareItem(tooltip)
tooltip.comparing = true
elseif tooltip.comparing and not compareItems then
for _, frame in pairs(tooltip.shoppingTooltips) do frame:Hide() end
tooltip.comparing = false
end
end
function AB:RegisterMacro(addon)
if addon == 'Blizzard_MacroUI' then
for i=1, MAX_ACCOUNT_MACROS do
_G['MacroButton'..i]:HookScript('OnEnter', function(btn) AB:BindUpdate(btn, 'MACRO') end)
end
end
end
function AB:ChangeBindingProfile()
if ElvUIBindPopupWindowCheckButton:GetChecked() then
LoadBindings(2)
SaveBindings(2)
else
LoadBindings(1)
SaveBindings(1)
end
end
local function keybindButtonClick()
if InCombatLockdown() then return end
AB:ActivateBindMode()
HideUIPanel(_G.KeyBindingFrame)
HideUIPanel(_G.GameMenuFrame)
end
function AB:SwapKeybindButton(event, addon)
if event and addon ~= 'Blizzard_BindingUI' then return end
local parent = _G.KeyBindingFrame
parent.quickKeybindButton:Hide()
local frame = CreateFrame('Button', 'ElvUI_KeybindButton', parent, 'OptionsButtonTemplate, BackdropTemplate')
frame:Width(150)
frame:Point('TOPLEFT', parent.quickKeybindButton)
frame:SetScript('OnClick', keybindButtonClick)
frame:SetText('ElvUI Keybind')
Skins:HandleButton(frame)
end
function AB:LoadKeyBinder()
bind:SetFrameStrata('DIALOG')
bind:SetFrameLevel(99)
bind:EnableMouse(true)
bind:EnableKeyboard(true)
bind:EnableMouseWheel(true)
bind.texture = bind:CreateTexture()
bind.texture:SetAllPoints(bind)
bind.texture:SetColorTexture(0, 0, 0, .25)
bind:Hide()
self:SecureHookScript(_G.GameTooltip, 'OnUpdate', 'Tooltip_OnUpdate')
bind:SetScript('OnEnter', function(b) local db = b.button:GetParent().db if db and db.mouseover then AB:Button_OnEnter(b.button) end end)
bind:SetScript('OnLeave', function(b) AB:BindHide() local db = b.button:GetParent().db if db and db.mouseover then AB:Button_OnLeave(b.button) end end)
bind:SetScript('OnKeyUp', function(_, key) self:BindListener(key) end)
bind:SetScript('OnMouseUp', function(_, key) self:BindListener(key) end)
bind:SetScript('OnMouseWheel', function(_, delta) if delta>0 then self:BindListener('MOUSEWHEELUP') else self:BindListener('MOUSEWHEELDOWN') end end)
for i = 1, 12 do
local b = _G['SpellButton'..i]
b:HookScript('OnEnter', function(s) AB:BindUpdate(s, 'SPELL') end)
end
local function buttonOnEnter(b) AB:BindUpdate(b) end
for b in pairs(self.handledbuttons) do
if b:IsProtected() and b:IsObjectType('CheckButton') and not b.isFlyout then
b:HookScript('OnEnter', buttonOnEnter)
end
end
if not IsAddOnLoaded('Blizzard_MacroUI') then
self:SecureHook('LoadAddOn', 'RegisterMacro')
else
self:RegisterMacro('Blizzard_MacroUI')
end
--Special Popup
local Popup = CreateFrame('Frame', 'ElvUIBindPopupWindow', _G.UIParent, 'BackdropTemplate')
Popup:SetFrameStrata('DIALOG')
Popup:EnableMouse(true)
Popup:SetMovable(true)
Popup:SetFrameLevel(99)
Popup:SetClampedToScreen(true)
Popup:Size(360, 130)
Popup:SetTemplate('Transparent')
Popup:RegisterForDrag('AnyUp', 'AnyDown')
Popup:SetScript('OnMouseDown', Popup.StartMoving)
Popup:SetScript('OnMouseUp', Popup.StopMovingOrSizing)
Popup:Hide()
Popup.header = CreateFrame('Button', nil, Popup, 'OptionsButtonTemplate, BackdropTemplate')
Popup.header:Size(100, 25)
Popup.header:Point('CENTER', Popup, 'TOP')
Popup.header:RegisterForClicks('AnyUp', 'AnyDown')
Popup.header:SetScript('OnMouseDown', function() Popup:StartMoving() end)
Popup.header:SetScript('OnMouseUp', function() Popup:StopMovingOrSizing() end)
Popup.header:SetText('Key Binds')
Popup.desc = Popup:CreateFontString(nil, 'ARTWORK')
Popup.desc:SetFontObject('GameFontHighlight')
Popup.desc:SetJustifyV('TOP')
Popup.desc:SetJustifyH('LEFT')
Popup.desc:Point('TOPLEFT', 18, -32)
Popup.desc:Point('BOTTOMRIGHT', -18, 48)
Popup.desc:SetText(L["Hover your mouse over any |cFF1784d1action|r, |cFF1784d1micro|r, |cFF1784d1macro|r, or |cFF1784d1spellbook|r button to bind it. This also works for items in your |cFF1784d1bag|r. Press the |cfd9b9b9bESC|r key to |cfd9b9b9bclear|r the current bindings."])
Popup.save = CreateFrame('Button', Popup:GetName()..'SaveButton', Popup, 'OptionsButtonTemplate, BackdropTemplate')
Popup.save:SetText(L["Save"])
Popup.save:Width(150)
Popup.save:SetScript('OnClick', function() AB:DeactivateBindMode(true) end)
Popup.discard = CreateFrame('Button', Popup:GetName()..'DiscardButton', Popup, 'OptionsButtonTemplate, BackdropTemplate')
Popup.discard:Width(150)
Popup.discard:SetText(L["Discard"])
Popup.discard:SetScript('OnClick', function() AB:DeactivateBindMode(false) end)
Popup.perCharCheck = CreateFrame('CheckButton', Popup:GetName()..'CheckButton', Popup, 'OptionsCheckButtonTemplate, BackdropTemplate')
_G[Popup.perCharCheck:GetName()..'Text']:SetText(CHARACTER_SPECIFIC_KEYBINDINGS)
Popup.perCharCheck:SetScript('OnLeave', GameTooltip_Hide)
Popup.perCharCheck:SetScript('OnShow', function(checkBtn) checkBtn:SetChecked(GetCurrentBindingSet() == 2) end)
Popup.perCharCheck:SetScript('OnClick', function()
if AB.bindingsChanged then
E:StaticPopup_Show('CONFIRM_LOSE_BINDING_CHANGES')
else
AB:ChangeBindingProfile()
end
end)
Popup.perCharCheck:SetScript('OnEnter', function(checkBtn)
_G.GameTooltip:SetOwner(checkBtn, 'ANCHOR_RIGHT')
_G.GameTooltip:SetText(CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP, nil, nil, nil, nil, 1)
end)
--position buttons
Popup.perCharCheck:Point('BOTTOMLEFT', Popup.discard, 'TOPLEFT', 0, 2)
Popup.save:Point('BOTTOMRIGHT', -14, 10)
Popup.discard:Point('BOTTOMLEFT', 14, 10)
Skins:HandleCheckBox(Popup.perCharCheck)
Skins:HandleButton(Popup.discard)
Skins:HandleButton(Popup.header)
Skins:HandleButton(Popup.save)
Popup.discard.backdrop:SetFrameLevel(Popup.discard:GetFrameLevel())
Popup.header.backdrop:SetFrameLevel(Popup.header:GetFrameLevel())
Popup.save.backdrop:SetFrameLevel(Popup.save:GetFrameLevel())
end

View File

@@ -0,0 +1,190 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local AB = E:GetModule('ActionBars')
local _G = _G
local pairs = pairs
local unpack = unpack
local tinsert = tinsert
local CreateFrame = CreateFrame
local GetBindingKey = GetBindingKey
local hooksecurefunc = hooksecurefunc
local ExtraActionBarHolder, ZoneAbilityHolder
local ExtraButtons = {}
function AB:ExtraButtons_BossStyle(button)
if not button.style then return end
button.style:SetAlpha(not E.db.actionbar.extraActionButton.clean and E.db.actionbar.extraActionButton.alpha or 0)
end
function AB:ExtraButtons_ZoneStyle()
local zoneAlpha = E.db.actionbar.zoneActionButton.alpha
_G.ZoneAbilityFrame.Style:SetAlpha(not E.db.actionbar.zoneActionButton.clean and zoneAlpha or 0)
for button in _G.ZoneAbilityFrame.SpellButtonContainer:EnumerateActive() do
button:SetAlpha(zoneAlpha)
end
end
function AB:ExtraButtons_OnEnter()
if self.holder and self.holder:GetParent() == AB.fadeParent and not AB.fadeParent.mouseLock then
E:UIFrameFadeIn(AB.fadeParent, 0.2, AB.fadeParent:GetAlpha(), 1)
end
end
function AB:ExtraButtons_OnLeave()
if self.holder and self.holder:GetParent() == AB.fadeParent and not AB.fadeParent.mouseLock then
E:UIFrameFadeOut(AB.fadeParent, 0.2, AB.fadeParent:GetAlpha(), 1 - AB.db.globalFadeAlpha)
end
end
function AB:ExtraButtons_GlobalFade()
ExtraActionBarHolder:SetParent(E.db.actionbar.extraActionButton.inheritGlobalFade and AB.fadeParent or E.UIParent)
ZoneAbilityHolder:SetParent(E.db.actionbar.zoneActionButton.inheritGlobalFade and AB.fadeParent or E.UIParent)
end
function AB:ExtraButtons_UpdateAlpha()
if not E.private.actionbar.enable then return end
local bossAlpha = E.db.actionbar.extraActionButton.alpha
for i = 1, _G.ExtraActionBarFrame:GetNumChildren() do
local button = _G['ExtraActionButton'..i]
if button then
button:SetAlpha(bossAlpha)
AB:ExtraButtons_BossStyle(button)
end
end
AB:ExtraButtons_ZoneStyle()
end
function AB:ExtraButtons_UpdateScale()
if not E.private.actionbar.enable then return end
AB:ExtraButtons_ZoneScale()
local scale = E.db.actionbar.extraActionButton.scale
_G.ExtraActionBarFrame:SetScale(scale)
local width, height = _G.ExtraActionBarFrame.button:GetSize()
ExtraActionBarHolder:SetSize(width * scale, height * scale)
end
function AB:ExtraButtons_ZoneScale()
if not E.private.actionbar.enable then return end
local scale = E.db.actionbar.zoneActionButton.scale
_G.ZoneAbilityFrame.Style:SetScale(scale)
_G.ZoneAbilityFrame.SpellButtonContainer:SetScale(scale)
local width, height = _G.ZoneAbilityFrame.SpellButtonContainer:GetSize()
ZoneAbilityHolder:SetSize(width * scale, height * scale)
end
function AB:SetupExtraButton()
local ExtraActionBarFrame = _G.ExtraActionBarFrame
local ZoneAbilityFrame = _G.ZoneAbilityFrame
ExtraActionBarHolder = CreateFrame('Frame', nil, E.UIParent)
ExtraActionBarHolder:Point('BOTTOM', E.UIParent, 'BOTTOM', -150, 300)
ZoneAbilityHolder = CreateFrame('Frame', nil, E.UIParent)
ZoneAbilityHolder:Point('BOTTOM', E.UIParent, 'BOTTOM', 150, 300)
ZoneAbilityFrame.SpellButtonContainer.holder = ZoneAbilityHolder
ZoneAbilityFrame.SpellButtonContainer:HookScript('OnEnter', AB.ExtraButtons_OnEnter)
ZoneAbilityFrame.SpellButtonContainer:HookScript('OnLeave', AB.ExtraButtons_OnLeave)
-- try to shutdown the container movement and taints
_G.UIPARENT_MANAGED_FRAME_POSITIONS.ExtraAbilityContainer = nil
_G.ExtraAbilityContainer.SetSize = E.noop
ZoneAbilityFrame:SetParent(ZoneAbilityHolder)
ZoneAbilityFrame:ClearAllPoints()
ZoneAbilityFrame:SetAllPoints()
ZoneAbilityFrame.ignoreInLayout = true
ExtraActionBarFrame:SetParent(ExtraActionBarHolder)
ExtraActionBarFrame:ClearAllPoints()
ExtraActionBarFrame:SetAllPoints()
ExtraActionBarFrame.ignoreInLayout = true
hooksecurefunc(ZoneAbilityFrame.SpellButtonContainer, 'SetSize', AB.ExtraButtons_ZoneScale)
hooksecurefunc(ZoneAbilityFrame, 'UpdateDisplayedZoneAbilities', function(frame)
AB:ExtraButtons_ZoneStyle()
for spellButton in frame.SpellButtonContainer:EnumerateActive() do
if spellButton and not spellButton.IsSkinned then
spellButton.NormalTexture:SetAlpha(0)
spellButton:GetHighlightTexture():SetColorTexture(1, 1, 1, .25)
spellButton:StyleButton(nil, true)
spellButton:CreateBackdrop()
spellButton.backdrop:SetAllPoints()
spellButton.Icon:SetDrawLayer('ARTWORK')
spellButton.Icon:SetTexCoord(unpack(E.TexCoords))
spellButton.Icon:SetInside()
--check these
--spellButton.HotKey:SetText(GetBindingKey(spellButton:GetName()))
--tinsert(ExtraButtons, spellButton)
spellButton.holder = ZoneAbilityHolder
spellButton:HookScript('OnEnter', AB.ExtraButtons_OnEnter)
spellButton:HookScript('OnLeave', AB.ExtraButtons_OnLeave)
if spellButton.Cooldown then
spellButton.Cooldown.CooldownOverride = 'actionbar'
E:RegisterCooldown(spellButton.Cooldown)
spellButton.Cooldown:SetInside(spellButton)
end
spellButton.IsSkinned = true
end
end
end)
for i = 1, ExtraActionBarFrame:GetNumChildren() do
local button = _G['ExtraActionButton'..i]
if button then
button.pushed = true
button.checked = true
self:StyleButton(button, true) -- registers cooldown too
button.icon:SetDrawLayer('ARTWORK')
button:CreateBackdrop()
button.backdrop:SetAllPoints()
button.backdrop:SetFrameLevel(button:GetFrameLevel())
AB:ExtraButtons_BossStyle(button)
button.holder = ExtraActionBarHolder
button:HookScript('OnEnter', AB.ExtraButtons_OnEnter)
button:HookScript('OnLeave', AB.ExtraButtons_OnLeave)
local tex = button:CreateTexture(nil, 'OVERLAY')
tex:SetColorTexture(0.9, 0.8, 0.1, 0.3)
tex:SetInside()
button:SetCheckedTexture(tex)
button.HotKey:SetText(GetBindingKey('ExtraActionButton'..i))
tinsert(ExtraButtons, button)
end
end
AB:ExtraButtons_UpdateAlpha()
AB:ExtraButtons_UpdateScale()
AB:ExtraButtons_GlobalFade()
E:CreateMover(ExtraActionBarHolder, 'BossButton', L["Boss Button"], nil, nil, nil, 'ALL,ACTIONBARS', nil, 'actionbar,extraActionButton')
E:CreateMover(ZoneAbilityHolder, 'ZoneAbility', L["Zone Ability"], nil, nil, nil, 'ALL,ACTIONBARS')
-- Spawn the mover before its available.
ZoneAbilityHolder:Size(52 * E.db.actionbar.zoneActionButton.scale)
end
function AB:UpdateExtraBindings()
for _, button in pairs(ExtraButtons) do
button.HotKey:SetText(_G.GetBindingKey(button:GetName()))
AB:FixKeybindText(button)
end
end

View File

@@ -0,0 +1,8 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Script file='ActionBars.lua'/>
<Script file='ExtraAB.lua'/>
<Script file='PetBar.lua'/>
<Script file='StanceBar.lua'/>
<Script file='Bind.lua'/>
<Script file='MicroBar.lua'/>
</Ui>

View File

@@ -0,0 +1,219 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local AB = E:GetModule('ActionBars')
local _G = _G
local gsub = gsub
local pairs = pairs
local assert = assert
local unpack = unpack
local CreateFrame = CreateFrame
local C_StorePublic_IsEnabled = C_StorePublic.IsEnabled
local UpdateMicroButtonsParent = UpdateMicroButtonsParent
local GetCurrentRegionName = GetCurrentRegionName
local RegisterStateDriver = RegisterStateDriver
local InCombatLockdown = InCombatLockdown
local microBar = CreateFrame('Frame', 'ElvUI_MicroBar', E.UIParent)
microBar:SetSize(100, 100)
local function onLeaveBar()
if AB.db.microbar.mouseover then
E:UIFrameFadeOut(microBar, 0.2, microBar:GetAlpha(), 0)
end
end
local watcher = 0
local function onUpdate(self, elapsed)
if watcher > 0.1 then
if not self:IsMouseOver() then
self.IsMouseOvered = nil
self:SetScript('OnUpdate', nil)
onLeaveBar()
end
watcher = 0
else
watcher = watcher + elapsed
end
end
local function onEnter(button)
if AB.db.microbar.mouseover and not microBar.IsMouseOvered then
microBar.IsMouseOvered = true
microBar:SetScript('OnUpdate', onUpdate)
E:UIFrameFadeIn(microBar, 0.2, microBar:GetAlpha(), AB.db.microbar.alpha)
end
if button.backdrop and button:IsEnabled() then
button.backdrop:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
end
-- bag keybind support from actionbar module
if E.private.actionbar.enable then
AB:BindUpdate(button, 'MICRO')
end
end
local function onLeave(button)
if button.backdrop and button:IsEnabled() then
button.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
end
end
function AB:HandleMicroButton(button)
assert(button, 'Invalid micro button name.')
local pushed = button:GetPushedTexture()
local normal = button:GetNormalTexture()
local disabled = button:GetDisabledTexture()
button:CreateBackdrop()
button.backdrop:SetAllPoints()
button:SetParent(microBar)
button:GetHighlightTexture():Kill()
button:HookScript('OnEnter', onEnter)
button:HookScript('OnLeave', onLeave)
button:SetHitRectInsets(0, 0, 0, 0)
if button.Flash then
button.Flash:SetInside()
button.Flash:SetTexture()
end
pushed:SetTexCoord(0.22, 0.81, 0.26, 0.82)
pushed:SetInside(button.backdrop)
normal:SetTexCoord(0.22, 0.81, 0.21, 0.82)
normal:SetInside(button.backdrop)
if disabled then
disabled:SetTexCoord(0.22, 0.81, 0.21, 0.82)
disabled:SetInside(button.backdrop)
end
end
function AB:MainMenuMicroButton_SetNormal()
_G.MainMenuBarPerformanceBar:Point('TOPLEFT', _G.MainMenuMicroButton, 'TOPLEFT', 9, -36)
end
function AB:MainMenuMicroButton_SetPushed()
_G.MainMenuBarPerformanceBar:Point('TOPLEFT', _G.MainMenuMicroButton, 'TOPLEFT', 8, -37)
end
function AB:UpdateMicroButtonsParent()
for _, x in pairs(_G.MICRO_BUTTONS) do
_G[x]:SetParent(microBar)
end
end
-- we use this table to sort the micro buttons on our bar to match Blizzard's button placements.
local __buttonIndex = {
[8] = 'CollectionsMicroButton',
[9] = 'EJMicroButton',
[10] = (not C_StorePublic_IsEnabled() and GetCurrentRegionName() == 'CN') and 'HelpMicroButton' or 'StoreMicroButton',
[11] = 'MainMenuMicroButton'
}
function AB:UpdateMicroBarVisibility()
if InCombatLockdown() then
AB.NeedsUpdateMicroBarVisibility = true
AB:RegisterEvent('PLAYER_REGEN_ENABLED')
return
end
local visibility = AB.db.microbar.visibility
visibility = gsub(visibility, '[\n\r]','')
RegisterStateDriver(microBar.visibility, 'visibility', (AB.db.microbar.enabled and visibility) or 'hide')
end
function AB:UpdateMicroPositionDimensions()
local db = AB.db.microbar
microBar.db = db
microBar.backdrop:SetShown(db.backdrop)
microBar.backdrop:ClearAllPoints()
AB:MoverMagic(microBar)
db.buttons = #_G.MICRO_BUTTONS-1
local backdropSpacing = db.backdropSpacing
local _, horizontal, anchorUp, anchorLeft = AB:GetGrowth(db.point)
local lastButton, anchorRowButton = microBar
for i = 1, #_G.MICRO_BUTTONS-1 do
local button = _G[__buttonIndex[i]] or _G[_G.MICRO_BUTTONS[i]]
local lastColumnButton = i - db.buttonsPerRow
lastColumnButton = _G[__buttonIndex[lastColumnButton]] or _G[_G.MICRO_BUTTONS[lastColumnButton]]
button.db = db
if i == 1 or i == db.buttonsPerRow then
anchorRowButton = button
end
button.handleBackdrop = true -- keep over HandleButton
AB:HandleButton(microBar, button, i, lastButton, lastColumnButton)
lastButton = button
end
microBar:SetAlpha((db.mouseover and not microBar.IsMouseOvered and 0) or db.alpha)
AB:HandleBackdropMultiplier(microBar, backdropSpacing, db.buttonSpacing, db.widthMult, db.heightMult, anchorUp, anchorLeft, horizontal, lastButton, anchorRowButton)
AB:HandleBackdropMover(microBar, backdropSpacing)
if microBar.mover then
if AB.db.microbar.enabled then
E:EnableMover(microBar.mover:GetName())
else
E:DisableMover(microBar.mover:GetName())
end
end
AB:UpdateMicroBarVisibility()
end
function AB:UpdateMicroButtons()
local GuildMicroButton = _G.GuildMicroButton
local GuildMicroButtonTabard = _G.GuildMicroButtonTabard
GuildMicroButtonTabard:SetInside(GuildMicroButton)
GuildMicroButtonTabard.background:SetInside(GuildMicroButton)
GuildMicroButtonTabard.background:SetTexCoord(0.17, 0.87, 0.5, 0.908)
GuildMicroButtonTabard.emblem:ClearAllPoints()
GuildMicroButtonTabard.emblem:Point('TOPLEFT', GuildMicroButton, 'TOPLEFT', 4, -4)
GuildMicroButtonTabard.emblem:Point('BOTTOMRIGHT', GuildMicroButton, 'BOTTOMRIGHT', -4, 8)
AB:UpdateMicroPositionDimensions()
end
function AB:SetupMicroBar()
microBar:CreateBackdrop(AB.db.transparent and 'Transparent')
microBar.backdrop:SetFrameLevel(0)
microBar:Point('TOPLEFT', E.UIParent, 'TOPLEFT', 4, -48)
microBar:EnableMouse(false)
microBar.visibility = CreateFrame('Frame', nil, E.UIParent, 'SecureHandlerStateTemplate')
microBar.visibility:SetScript('OnShow', function() microBar:Show() end)
microBar.visibility:SetScript('OnHide', function() microBar:Hide() end)
for _, x in pairs(_G.MICRO_BUTTONS) do
AB:HandleMicroButton(_G[x])
end
_G.MicroButtonPortrait:SetInside(_G.CharacterMicroButton.backdrop)
AB:SecureHook('UpdateMicroButtonsParent')
AB:SecureHook('MoveMicroButtons', 'UpdateMicroPositionDimensions')
AB:SecureHook('UpdateMicroButtons')
UpdateMicroButtonsParent(microBar)
AB:MainMenuMicroButton_SetNormal()
AB:UpdateMicroPositionDimensions()
-- With this method we might don't taint anything. Instead of using :Kill()
_G.MainMenuBarPerformanceBar:SetAlpha(0)
_G.MainMenuBarPerformanceBar:SetScale(0.00001)
E:CreateMover(microBar, 'MicrobarMover', L["Micro Bar"], nil, nil, nil, 'ALL,ACTIONBARS', nil, 'actionbar,microbar')
end

View File

@@ -0,0 +1,258 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local AB = E:GetModule('ActionBars')
local _G = _G
local gsub = gsub
local ipairs = ipairs
local CreateFrame = CreateFrame
local RegisterStateDriver = RegisterStateDriver
local GetBindingKey = GetBindingKey
local PetHasActionBar = PetHasActionBar
local GetPetActionInfo = GetPetActionInfo
local IsPetAttackAction = IsPetAttackAction
local PetActionButton_StartFlash = PetActionButton_StartFlash
local PetActionButton_StopFlash = PetActionButton_StopFlash
local AutoCastShine_AutoCastStart = AutoCastShine_AutoCastStart
local AutoCastShine_AutoCastStop = AutoCastShine_AutoCastStop
local PetActionBar_ShowGrid = PetActionBar_ShowGrid
local PetActionBar_UpdateCooldowns = PetActionBar_UpdateCooldowns
local NUM_PET_ACTION_SLOTS = NUM_PET_ACTION_SLOTS
local Masque = E.Masque
local MasqueGroup = Masque and Masque:Group('ElvUI', 'Pet Bar')
local bar = CreateFrame('Frame', 'ElvUI_BarPet', E.UIParent, 'SecureHandlerStateTemplate')
bar:SetFrameStrata('LOW')
bar.buttons = {}
function AB:UpdatePet(event, unit)
if event == 'UNIT_AURA' and unit ~= 'pet' then return end
for i = 1, NUM_PET_ACTION_SLOTS, 1 do
local name, texture, isToken, isActive, autoCastAllowed, autoCastEnabled, spellID = GetPetActionInfo(i)
local buttonName = 'PetActionButton'..i
local autoCast = _G[buttonName..'AutoCastable']
local button = _G[buttonName]
button:SetAlpha(1)
button.isToken = isToken
button.icon:Show()
if not isToken then
button.icon:SetTexture(texture)
button.tooltipName = name
else
button.icon:SetTexture(_G[texture])
button.tooltipName = _G[name]
end
if spellID then
local spell = _G.Spell:CreateFromSpellID(spellID)
button.spellDataLoadedCancelFunc = spell:ContinueWithCancelOnSpellLoad(function()
button.tooltipSubtext = spell:GetSpellSubtext()
end)
end
if isActive and name ~= 'PET_ACTION_FOLLOW' then
button:SetChecked(true)
if IsPetAttackAction(i) then
PetActionButton_StartFlash(button)
end
else
button:SetChecked(false)
if IsPetAttackAction(i) then
PetActionButton_StopFlash(button)
end
end
if autoCastAllowed then
autoCast:Show()
else
autoCast:Hide()
end
if autoCastEnabled then
AutoCastShine_AutoCastStart(button.AutoCastShine)
else
AutoCastShine_AutoCastStop(button.AutoCastShine)
end
if not PetHasActionBar() and texture and name ~= 'PET_ACTION_FOLLOW' then
PetActionButton_StopFlash(button)
button.icon:SetDesaturation(true)
button:SetChecked(false)
end
end
end
function AB:PositionAndSizeBarPet()
local db = AB.db.barPet
local buttonSpacing = db.buttonspacing
local backdropSpacing = db.backdropSpacing
local buttonsPerRow = db.buttonsPerRow
local numButtons = db.buttons
local buttonWidth = db.buttonsize
local buttonHeight = db.keepSizeRatio and db.buttonsize or db.buttonHeight
local point = db.point
local visibility = db.visibility
local autoCastWidth = (buttonWidth / 2) - (buttonWidth / 7.5)
local autoCastHeight = (buttonHeight / 2) - (buttonHeight / 7.5)
bar.db = db
bar.mouseover = db.mouseover
if numButtons < buttonsPerRow then buttonsPerRow = numButtons end
if db.enabled then
bar:SetScale(1)
bar:SetAlpha(bar.db.alpha)
E:EnableMover(bar.mover:GetName())
else
bar:SetScale(0.0001)
bar:SetAlpha(0)
E:DisableMover(bar.mover:GetName())
end
bar:SetParent(db.inheritGlobalFade and AB.fadeParent or E.UIParent)
bar:EnableMouse(not db.clickThrough)
bar:SetAlpha(bar.mouseover and 0 or db.alpha)
AB:FadeBarBlings(bar, bar.mouseover and 0 or db.alpha)
bar.backdrop:SetShown(db.backdrop)
bar.backdrop:ClearAllPoints()
AB:MoverMagic(bar)
local _, horizontal, anchorUp, anchorLeft = AB:GetGrowth(point)
local button, lastButton, lastColumnButton, anchorRowButton, lastShownButton, autoCast
for i = 1, NUM_PET_ACTION_SLOTS do
button = _G['PetActionButton'..i]
lastButton = _G['PetActionButton'..i-1]
autoCast = _G['PetActionButton'..i..'AutoCastable']
lastColumnButton = _G['PetActionButton'..i-buttonsPerRow]
button.db = db
bar.buttons[i] = button
if i == 1 or i == buttonsPerRow then
anchorRowButton = button
end
if i > numButtons then
button:SetScale(0.0001)
button:SetAlpha(0)
button.handleBackdrop = nil
else
button:SetScale(1)
button:SetAlpha(bar.db.alpha)
lastShownButton = button
button.handleBackdrop = true -- keep over HandleButton
end
autoCast:SetOutside(button, autoCastWidth, autoCastHeight)
AB:HandleButton(bar, button, i, lastButton, lastColumnButton)
AB:StyleButton(button, nil, MasqueGroup and E.private.actionbar.masque.petBar)
end
AB:HandleBackdropMultiplier(bar, backdropSpacing, buttonSpacing, db.widthMult, db.heightMult, anchorUp, anchorLeft, horizontal, lastShownButton, anchorRowButton)
AB:HandleBackdropMover(bar, backdropSpacing)
visibility = gsub(visibility, '[\n\r]','')
RegisterStateDriver(bar, 'show', visibility)
if MasqueGroup and E.private.actionbar.masque.petBar then
MasqueGroup:ReSkin()
for _, btn in ipairs(bar.buttons) do
AB:TrimIcon(btn, true)
end
end
end
function AB:UpdatePetCooldownSettings()
for i = 1, NUM_PET_ACTION_SLOTS do
local button = _G['PetActionButton'..i]
if button and button.cooldown then
button.cooldown:SetDrawBling(not AB.db.hideCooldownBling)
end
end
end
function AB:UpdatePetBindings()
for i = 1, NUM_PET_ACTION_SLOTS do
if AB.db.hotkeytext then
local key = GetBindingKey('BONUSACTIONBUTTON'..i)
_G['PetActionButton'..i..'HotKey']:Show()
_G['PetActionButton'..i..'HotKey']:SetText(key)
AB:FixKeybindText(_G['PetActionButton'..i])
else
_G['PetActionButton'..i..'HotKey']:Hide()
end
end
end
function AB:CreateBarPet()
bar.backdrop = CreateFrame('Frame', nil, bar, 'BackdropTemplate')
bar.backdrop:SetTemplate(AB.db.transparent and 'Transparent')
bar.backdrop:SetFrameLevel(0)
if AB.db.bar4.enabled then
bar:Point('RIGHT', _G.ElvUI_Bar4, 'LEFT', -4, 0)
else
bar:Point('RIGHT', E.UIParent, 'RIGHT', -4, 0)
end
bar:SetAttribute('_onstate-show', [[
if newstate == 'hide' then
self:Hide()
else
self:Show()
end
]])
bar:SetScript('OnHide', function()
for i = 1, NUM_PET_ACTION_SLOTS, 1 do
local button = _G['PetActionButton'..i]
if button.spellDataLoadedCancelFunc then
button.spellDataLoadedCancelFunc()
button.spellDataLoadedCancelFunc = nil
end
end
end)
_G.PetActionBarFrame.showgrid = 1
PetActionBar_ShowGrid()
AB:RegisterEvent('PET_BAR_UPDATE', 'UpdatePet')
AB:RegisterEvent('PLAYER_CONTROL_GAINED', 'UpdatePet')
AB:RegisterEvent('PLAYER_CONTROL_LOST', 'UpdatePet')
AB:RegisterEvent('PLAYER_ENTERING_WORLD', 'UpdatePet')
AB:RegisterEvent('PLAYER_FARSIGHT_FOCUS_CHANGED', 'UpdatePet')
AB:RegisterEvent('SPELLS_CHANGED', 'UpdatePet')
AB:RegisterEvent('UNIT_FLAGS', 'UpdatePet')
AB:RegisterEvent('UNIT_PET', 'UpdatePet')
AB:RegisterEvent('PET_BAR_UPDATE_COOLDOWN', PetActionBar_UpdateCooldowns)
E:CreateMover(bar, 'PetAB', L["Pet Bar"], nil, nil, nil, 'ALL,ACTIONBARS', nil, 'actionbar,barPet')
AB:PositionAndSizeBarPet()
AB:UpdatePetBindings()
AB:HookScript(bar, 'OnEnter', 'Bar_OnEnter')
AB:HookScript(bar, 'OnLeave', 'Bar_OnLeave')
for i = 1, NUM_PET_ACTION_SLOTS do
local button = _G['PetActionButton'..i]
AB:HookScript(button, 'OnEnter', 'Button_OnEnter')
AB:HookScript(button, 'OnLeave', 'Button_OnLeave')
if MasqueGroup and E.private.actionbar.masque.petBar then
MasqueGroup:AddButton(button)
end
end
end

View File

@@ -0,0 +1,270 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local AB = E:GetModule('ActionBars')
local _G = _G
local gsub = gsub
local format, ipairs = format, ipairs
local CooldownFrame_Set = CooldownFrame_Set
local CreateFrame = CreateFrame
local GetBindingKey = GetBindingKey
local GetNumShapeshiftForms = GetNumShapeshiftForms
local GetShapeshiftForm = GetShapeshiftForm
local GetShapeshiftFormCooldown = GetShapeshiftFormCooldown
local GetShapeshiftFormInfo = GetShapeshiftFormInfo
local GetSpellInfo = GetSpellInfo
local InCombatLockdown = InCombatLockdown
local RegisterStateDriver = RegisterStateDriver
local NUM_STANCE_SLOTS = NUM_STANCE_SLOTS
local Masque = E.Masque
local MasqueGroup = Masque and Masque:Group('ElvUI', 'Stance Bar')
local WispSplode = [[Interface\Icons\Spell_Nature_WispSplode]]
local bar = CreateFrame('Frame', 'ElvUI_StanceBar', E.UIParent, 'SecureHandlerStateTemplate')
bar.buttons = {}
function AB:UPDATE_SHAPESHIFT_COOLDOWN()
local numForms = GetNumShapeshiftForms()
local start, duration, enable, cooldown
for i = 1, NUM_STANCE_SLOTS do
if i <= numForms then
cooldown = _G['ElvUI_StanceBarButton'..i..'Cooldown']
start, duration, enable = GetShapeshiftFormCooldown(i)
CooldownFrame_Set(cooldown, start, duration, enable)
cooldown:SetDrawBling(cooldown:GetEffectiveAlpha() > 0.5) --Cooldown Bling Fix
end
end
AB:StyleShapeShift('UPDATE_SHAPESHIFT_COOLDOWN')
end
function AB:StyleShapeShift()
local numForms = GetNumShapeshiftForms()
local stance = GetShapeshiftForm()
local darkenInactive = AB.db.stanceBar.style == 'darkenInactive'
for i = 1, NUM_STANCE_SLOTS do
local buttonName = 'ElvUI_StanceBarButton'..i
local button = _G[buttonName]
local cooldown = _G[buttonName..'Cooldown']
if i <= numForms then
local texture, isActive, isCastable, spellID, _ = GetShapeshiftFormInfo(i)
if darkenInactive then
_, _, texture = GetSpellInfo(spellID)
end
if not texture then texture = WispSplode end
button.icon:SetTexture(texture)
if not button.useMasque then
cooldown:SetAlpha(1)
if isActive then
_G.StanceBarFrame.lastSelected = button:GetID()
if numForms == 1 then
button.checked:SetColorTexture(1, 1, 1, 0.5)
button:SetChecked(true)
else
button.checked:SetColorTexture(1, 1, 1, 0.5)
button:SetChecked(not darkenInactive)
end
else
if numForms == 1 or stance == 0 then
button:SetChecked(false)
else
button:SetChecked(darkenInactive)
button.checked:SetAlpha(1)
if darkenInactive then
button.checked:SetColorTexture(0, 0, 0, 0.5)
else
button.checked:SetColorTexture(1, 1, 1, 0.5)
end
end
end
else
if isActive then
button:SetChecked(true)
else
button:SetChecked(false)
end
end
if isCastable then
button.icon:SetVertexColor(1.0, 1.0, 1.0)
else
button.icon:SetVertexColor(0.4, 0.4, 0.4)
end
end
end
end
function AB:PositionAndSizeBarShapeShift()
local db = AB.db.stanceBar
local buttonSpacing = db.buttonspacing
local backdropSpacing = db.backdropSpacing
local buttonsPerRow = db.buttonsPerRow
local numButtons = db.buttons
local point = db.point
local visibility = db.visibility
bar.db = db
bar.mouseover = db.mouseover
if bar.LastButton then
if numButtons > bar.LastButton then numButtons = bar.LastButton end
if buttonsPerRow > bar.LastButton then buttonsPerRow = bar.LastButton end
end
if numButtons < buttonsPerRow then
buttonsPerRow = numButtons
end
bar:SetParent(db.inheritGlobalFade and AB.fadeParent or E.UIParent)
bar:EnableMouse(not db.clickThrough)
bar:SetAlpha(bar.mouseover and 0 or db.alpha)
AB:FadeBarBlings(bar, bar.mouseover and 0 or db.alpha)
bar.backdrop:SetShown(db.backdrop)
bar.backdrop:ClearAllPoints()
AB:MoverMagic(bar)
local _, horizontal, anchorUp, anchorLeft = AB:GetGrowth(point)
local button, lastButton, lastColumnButton, anchorRowButton, lastShownButton
local useMasque = MasqueGroup and E.private.actionbar.masque.stanceBar
for i = 1, NUM_STANCE_SLOTS do
button = _G['ElvUI_StanceBarButton'..i]
lastButton = _G['ElvUI_StanceBarButton'..i-1]
lastColumnButton = _G['ElvUI_StanceBarButton'..i-buttonsPerRow]
button.db = db
if i == 1 or i == buttonsPerRow then
anchorRowButton = button
end
if i > numButtons then
button:SetAlpha(0)
button.handleBackdrop = nil
else
button:SetAlpha(db.alpha)
lastShownButton = button
button.handleBackdrop = true -- keep over HandleButton
end
AB:HandleButton(bar, button, i, lastButton, lastColumnButton)
if useMasque then
MasqueGroup:AddButton(bar.buttons[i])
end
if not button.FlyoutUpdateFunc then
AB:StyleButton(button, nil, useMasque, true)
if not useMasque then
if db.style == 'darkenInactive' then
button.checked:SetBlendMode('BLEND')
else
button.checked:SetBlendMode('ADD')
end
end
end
end
AB:HandleBackdropMultiplier(bar, backdropSpacing, buttonSpacing, db.widthMult, db.heightMult, anchorUp, anchorLeft, horizontal, lastShownButton, anchorRowButton)
AB:HandleBackdropMover(bar, backdropSpacing)
if db.enabled then
visibility = gsub(visibility,'[\n\r]','')
RegisterStateDriver(bar, 'visibility', (GetNumShapeshiftForms() == 0 and 'hide') or visibility)
E:EnableMover(bar.mover:GetName())
else
RegisterStateDriver(bar, 'visibility', 'hide')
E:DisableMover(bar.mover:GetName())
end
if useMasque then
MasqueGroup:ReSkin()
for _, btn in ipairs(bar.buttons) do
AB:TrimIcon(btn, true)
end
end
end
function AB:AdjustMaxStanceButtons(event)
if InCombatLockdown() then
AB.NeedsAdjustMaxStanceButtons = event or true
AB:RegisterEvent('PLAYER_REGEN_ENABLED')
return
end
for _, button in ipairs(bar.buttons) do
button:Hide()
end
local numButtons = GetNumShapeshiftForms()
for i = 1, NUM_STANCE_SLOTS do
if not bar.buttons[i] then
bar.buttons[i] = CreateFrame('CheckButton', format(bar:GetName()..'Button%d', i), bar, 'StanceButtonTemplate')
bar.buttons[i]:SetID(i)
AB:HookScript(bar.buttons[i], 'OnEnter', 'Button_OnEnter')
AB:HookScript(bar.buttons[i], 'OnLeave', 'Button_OnLeave')
end
local blizz = _G[format('StanceButton%d', i)]
if blizz and blizz.commandName then
bar.buttons[i].commandName = blizz.commandName
end
if i <= numButtons then
bar.buttons[i]:Show()
bar.LastButton = i
end
end
AB:PositionAndSizeBarShapeShift()
-- sometimes after combat lock down `event` may be true because of passing it back with `AB.NeedsAdjustMaxStanceButtons`
if event == 'UPDATE_SHAPESHIFT_FORMS' or event == 'PLAYER_ENTERING_WORLD' then
AB:StyleShapeShift()
end
end
function AB:UpdateStanceBindings()
for i = 1, NUM_STANCE_SLOTS do
local button = _G['ElvUI_StanceBarButton'..i]
if not button then break end
if AB.db.hotkeytext then
button.HotKey:Show()
button.HotKey:SetText(GetBindingKey('SHAPESHIFTBUTTON'..i))
AB:FixKeybindText(button)
else
button.HotKey:Hide()
end
end
end
function AB:CreateBarShapeShift()
bar:CreateBackdrop(AB.db.transparent and 'Transparent')
bar.backdrop:SetFrameLevel(0)
bar:Point('TOPLEFT', E.UIParent, 'BOTTOMLEFT', 4, -769)
AB:HookScript(bar, 'OnEnter', 'Bar_OnEnter')
AB:HookScript(bar, 'OnLeave', 'Bar_OnLeave')
AB:RegisterEvent('UPDATE_SHAPESHIFT_COOLDOWN')
AB:RegisterEvent('UPDATE_SHAPESHIFT_FORMS', 'AdjustMaxStanceButtons')
AB:RegisterEvent('UPDATE_SHAPESHIFT_FORM', 'StyleShapeShift')
AB:RegisterEvent('UPDATE_SHAPESHIFT_USABLE', 'StyleShapeShift')
AB:RegisterEvent('ACTIONBAR_PAGE_CHANGED', 'StyleShapeShift')
E:CreateMover(bar, 'ShiftAB', L["Stance Bar"], nil, -3, nil, 'ALL,ACTIONBARS', nil, 'actionbar,stanceBar', true)
end

419
Modules/Auras/Auras.lua Normal file
View File

@@ -0,0 +1,419 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local A = E:GetModule('Auras')
local LSM = E.Libs.LSM
local _G = _G
local format, tinsert = format, tinsert
local select, unpack, strmatch = select, unpack, strmatch
local GetInventoryItemQuality = GetInventoryItemQuality
local GetInventoryItemTexture = GetInventoryItemTexture
local GetItemQualityColor = GetItemQualityColor
local GetWeaponEnchantInfo = GetWeaponEnchantInfo
local RegisterAttributeDriver = RegisterAttributeDriver
local RegisterStateDriver = RegisterStateDriver
local CreateFrame = CreateFrame
local UnitAura = UnitAura
local GetTime = GetTime
local Masque = E.Masque
local MasqueGroupBuffs = Masque and Masque:Group('ElvUI', 'Buffs')
local MasqueGroupDebuffs = Masque and Masque:Group('ElvUI', 'Debuffs')
local DIRECTION_TO_POINT = {
DOWN_RIGHT = 'TOPLEFT',
DOWN_LEFT = 'TOPRIGHT',
UP_RIGHT = 'BOTTOMLEFT',
UP_LEFT = 'BOTTOMRIGHT',
RIGHT_DOWN = 'TOPLEFT',
RIGHT_UP = 'BOTTOMLEFT',
LEFT_DOWN = 'TOPRIGHT',
LEFT_UP = 'BOTTOMRIGHT',
}
local DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER = {
DOWN_RIGHT = 1,
DOWN_LEFT = -1,
UP_RIGHT = 1,
UP_LEFT = -1,
RIGHT_DOWN = 1,
RIGHT_UP = 1,
LEFT_DOWN = -1,
LEFT_UP = -1,
}
local DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER = {
DOWN_RIGHT = -1,
DOWN_LEFT = -1,
UP_RIGHT = 1,
UP_LEFT = 1,
RIGHT_DOWN = -1,
RIGHT_UP = 1,
LEFT_DOWN = -1,
LEFT_UP = 1,
}
local IS_HORIZONTAL_GROWTH = {
RIGHT_DOWN = true,
RIGHT_UP = true,
LEFT_DOWN = true,
LEFT_UP = true,
}
local MasqueButtonData = {
-- ones we update:
Icon = nil,
Highlight = nil,
-- ones we dont update:
FloatingBG = nil,
Cooldown = nil,
Flash = nil,
Pushed = nil,
Normal = nil,
Disabled = nil,
Checked = nil,
Border = nil,
AutoCastable = nil,
HotKey = nil,
Count = false,
Name = nil,
Duration = false,
AutoCast = nil,
}
function A:MasqueData(texture, highlight)
local btnData = E:CopyTable({}, MasqueButtonData)
btnData.Icon = texture
btnData.Highlight = highlight
return btnData
end
function A:UpdateStatusBar(button)
local db = A.db[button.auraType]
button.statusBar:SetValue(button.timeLeft)
local threshold = db.fadeThreshold
if threshold == -1 then
return
elseif button.timeLeft > threshold then
E:StopFlash(button)
else
E:Flash(button, 1)
end
end
function A:CreateIcon(button)
local header = button:GetParent()
local auraType = header.filter
button.auraType = auraType == 'HELPFUL' and 'buffs' or 'debuffs' -- used to update cooldown text
button.filter = auraType
button.texture = button:CreateTexture(nil, 'ARTWORK')
button.texture:SetInside()
button.texture:SetTexCoord(unpack(E.TexCoords))
button.count = button:CreateFontString(nil, 'OVERLAY')
button.count:FontTemplate()
button.text = button:CreateFontString(nil, 'OVERLAY')
button.text:FontTemplate()
button.highlight = button:CreateTexture(nil, 'HIGHLIGHT')
button.highlight:SetColorTexture(1, 1, 1, .45)
button.highlight:SetInside()
button.statusBar = CreateFrame('StatusBar', nil, button)
button.statusBar:SetFrameLevel(button:GetFrameLevel())
button.statusBar:SetFrameStrata(button:GetFrameStrata())
button.statusBar:CreateBackdrop()
A:UpdateIcon(button)
E:SetSmoothing(button.statusBar)
E:SetUpAnimGroup(button)
-- support cooldown override
if not button.isRegisteredCooldown then
button.CooldownOverride = 'auras'
button.isRegisteredCooldown = true
button.forceEnabled = true
button.showSeconds = true
if not E.RegisteredCooldowns.auras then E.RegisteredCooldowns.auras = {} end
tinsert(E.RegisteredCooldowns.auras, button)
end
button:SetScript('OnAttributeChanged', A.OnAttributeChanged)
A:Update_CooldownOptions(button)
if auraType == 'HELPFUL' and MasqueGroupBuffs and E.private.auras.masque.buffs then
MasqueGroupBuffs:AddButton(button, A:MasqueData(button.texture, button.highlight))
if button.__MSQ_BaseFrame then button.__MSQ_BaseFrame:SetFrameLevel(2) end --Lower the framelevel to fix issue with buttons created during combat
MasqueGroupBuffs:ReSkin()
elseif auraType == 'HARMFUL' and MasqueGroupDebuffs and E.private.auras.masque.debuffs then
MasqueGroupDebuffs:AddButton(button, A:MasqueData(button.texture, button.highlight))
if button.__MSQ_BaseFrame then button.__MSQ_BaseFrame:SetFrameLevel(2) end --Lower the framelevel to fix issue with buttons created during combat
MasqueGroupDebuffs:ReSkin()
else
button:SetTemplate()
end
end
function A:UpdateIcon(button)
local db = A.db[button.auraType]
button.count:ClearAllPoints()
button.count:Point('BOTTOMRIGHT', db.countXOffset, db.countYOffset)
button.count:FontTemplate(LSM:Fetch('font', db.countFont), db.countFontSize, db.countFontOutline)
button.text:ClearAllPoints()
button.text:Point('TOP', button, 'BOTTOM', db.timeXOffset, db.timeYOffset)
button.text:FontTemplate(LSM:Fetch('font', db.timeFont), db.timeFontSize, db.timeFontOutline)
local pos, spacing, iconSize = db.barPosition, db.barSpacing, db.size - (E.Border * 2)
local isOnTop, isOnBottom, isOnLeft = pos == 'TOP', pos == 'BOTTOM', pos == 'LEFT'
local isHorizontal = isOnTop or isOnBottom
button.statusBar:ClearAllPoints()
button.statusBar:Size(isHorizontal and iconSize or (db.barSize + (E.PixelMode and 0 or 2)), isHorizontal and (db.barSize + (E.PixelMode and 0 or 2)) or iconSize)
button.statusBar:Point(E.InversePoints[pos], button, pos, isHorizontal and 0 or ((isOnLeft and -((E.PixelMode and 1 or 3) + spacing)) or ((E.PixelMode and 1 or 3) + spacing)), not isHorizontal and 0 or ((isOnTop and ((E.PixelMode and 1 or 3) + spacing) or -((E.PixelMode and 1 or 3) + spacing))))
button.statusBar:SetStatusBarTexture(LSM:Fetch('statusbar', db.barTexture))
button.statusBar:SetOrientation(isHorizontal and 'HORIZONTAL' or 'VERTICAL')
button.statusBar:SetRotatesTexture(not isHorizontal)
end
function A:SetAuraTime(button, expiration, duration)
button.timeLeft = E:Round(expiration - GetTime(), 3)
-- this keeps enchants from derping out when they expire
if button.timeLeft <= 0.05 then
A:ClearAuraTime(button, true)
return
end
A:UpdateStatusBar(button)
local oldEnd = button.endTime
button.endTime = expiration
if oldEnd ~= button.endTime then
button.nextUpdate = 0
button.statusBar:SetMinMaxValues(0, duration)
button:SetScript('OnUpdate', E.Cooldown_OnUpdate)
end
end
function A:ClearAuraTime(button, expired)
if not expired then
button.statusBar:SetValue(1)
button.statusBar:SetMinMaxValues(0, 1)
end
button.endTime = nil
button.timeLeft = nil
button.text:SetText('')
button:SetScript('OnUpdate', nil)
end
function A:UpdateAura(button, index)
local unit = button:GetParent():GetAttribute('unit')
local name, texture, count, dtype, duration, expiration = UnitAura(unit, index, button.filter)
local DebuffType = dtype or 'none'
if name then
local db = A.db[button.auraType]
if duration > 0 and expiration then
A:SetAuraTime(button, expiration, duration)
else
A:ClearAuraTime(button)
end
local r, g, b = db.barColor.r, db.barColor.g, db.barColor.b
if button.timeLeft and db.barColorGradient then
r, g, b = E.oUF:ColorGradient(button.timeLeft, duration or 0, .8, 0, 0, .8, .8, 0, 0, .8, 0)
end
button.count:SetText(count > 1 and count)
button.text:SetShown(db.showDuration)
button.statusBar:SetShown((db.barShow and duration > 0) or (db.barShow and db.barNoDuration and duration == 0))
button.statusBar:SetStatusBarColor(r, g, b)
button.texture:SetTexture(texture)
if button.debuffType ~= DebuffType then
local color = button.filter == 'HARMFUL' and _G.DebuffTypeColor[DebuffType] or E.db.general.bordercolor
button:SetBackdropBorderColor(color.r, color.g, color.b)
button.statusBar.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
end
end
button.debuffType = DebuffType
end
function A:UpdateTempEnchant(button, index)
local offset = (strmatch(button:GetName(), '2$') and 6) or 2
local db = A.db[button.auraType]
local duration, remaining = 600, 0
local expiration = select(offset, GetWeaponEnchantInfo())
if expiration then
button.texture:SetTexture(GetInventoryItemTexture('player', index))
local quality = GetInventoryItemQuality('player', index)
if quality and quality > 1 then
button:SetBackdropBorderColor(GetItemQualityColor(quality))
else
button:SetBackdropBorderColor(unpack(E.media.bordercolor))
end
remaining = expiration / 1000
if remaining <= 3600 and remaining > 1800 then
duration = 3600
elseif remaining <= 1800 and remaining > 600 then
duration = 1800
end
A:SetAuraTime(button, E:Round(remaining + GetTime(), 3), duration)
else
A:ClearAuraTime(button)
end
local r, g, b = db.barColor.r, db.barColor.g, db.barColor.b
if expiration and db.barColorGradient then
r, g, b = E.oUF:ColorGradient(remaining, duration, .8, 0, 0, .8, .8, 0, 0, .8, 0)
end
button.text:SetShown(db.showDuration)
button.statusBar:SetShown((db.barShow and remaining > 0) or (db.barShow and db.barNoDuration and not expiration))
button.statusBar:SetStatusBarColor(r, g, b)
end
function A:Update_CooldownOptions(button)
E:Cooldown_Options(button, A.db.cooldown, button)
end
function A:OnAttributeChanged(attribute, value)
A:Update_CooldownOptions(self)
if attribute == 'index' then
A:UpdateAura(self, value)
elseif attribute == 'target-slot' then
A:UpdateTempEnchant(self, value)
end
end
function A:UpdateHeader(header)
if not E.private.auras.enable then return end
local db = A.db[header.auraType]
local template = format('ElvUIAuraTemplate%d', db.size)
local colors = db.barColor
if E:CheckClassColor(colors.r, colors.g, colors.b) then
local classColor = E:ClassColor(E.myclass, true)
colors.r, colors.g, colors.b = classColor.r, classColor.g, classColor.b
end
if header.filter == 'HELPFUL' then
header:SetAttribute('consolidateTo', 0)
header:SetAttribute('weaponTemplate', template)
end
header:SetAttribute('template', template)
header:SetAttribute('separateOwn', db.seperateOwn)
header:SetAttribute('sortMethod', db.sortMethod)
header:SetAttribute('sortDirection', db.sortDir)
header:SetAttribute('maxWraps', db.maxWraps)
header:SetAttribute('wrapAfter', db.wrapAfter)
header:SetAttribute('point', DIRECTION_TO_POINT[db.growthDirection])
if IS_HORIZONTAL_GROWTH[db.growthDirection] then
header:SetAttribute('minWidth', ((db.wrapAfter == 1 and 0 or db.horizontalSpacing) + db.size) * db.wrapAfter)
header:SetAttribute('minHeight', (db.verticalSpacing + db.size) * db.maxWraps)
header:SetAttribute('xOffset', DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER[db.growthDirection] * (db.horizontalSpacing + db.size))
header:SetAttribute('yOffset', 0)
header:SetAttribute('wrapXOffset', 0)
header:SetAttribute('wrapYOffset', DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER[db.growthDirection] * (db.verticalSpacing + db.size))
else
header:SetAttribute('minWidth', (db.horizontalSpacing + db.size) * db.maxWraps)
header:SetAttribute('minHeight', ((db.wrapAfter == 1 and 0 or db.verticalSpacing) + db.size) * db.wrapAfter)
header:SetAttribute('xOffset', 0)
header:SetAttribute('yOffset', DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER[db.growthDirection] * (db.verticalSpacing + db.size))
header:SetAttribute('wrapXOffset', DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER[db.growthDirection] * (db.horizontalSpacing + db.size))
header:SetAttribute('wrapYOffset', 0)
end
local index = 1
local child = select(index, header:GetChildren())
while child do
child.db = db
child.auraType = header.auraType -- used to update cooldown text
child:Size(db.size, db.size)
A:UpdateIcon(child)
--Blizzard bug fix, icons arent being hidden when you reduce the amount of maximum buttons
if index > (db.maxWraps * db.wrapAfter) and child:IsShown() then
child:Hide()
end
index = index + 1
child = select(index, header:GetChildren())
end
if MasqueGroupBuffs and E.private.auras.buffsHeader and E.private.auras.masque.buffs then MasqueGroupBuffs:ReSkin() end
if MasqueGroupDebuffs and E.private.auras.debuffsHeader and E.private.auras.masque.debuffs then MasqueGroupDebuffs:ReSkin() end
end
function A:CreateAuraHeader(filter)
local name, auraType = filter == 'HELPFUL' and 'ElvUIPlayerBuffs' or 'ElvUIPlayerDebuffs', filter == 'HELPFUL' and 'buffs' or 'debuffs'
local header = CreateFrame('Frame', name, E.UIParent, 'SecureAuraHeaderTemplate')
header:SetClampedToScreen(true)
header:SetAttribute('unit', 'player')
header:SetAttribute('filter', filter)
header.filter = filter
header.auraType = auraType
RegisterStateDriver(header, 'visibility', '[petbattle] hide; show')
RegisterAttributeDriver(header, 'unit', '[vehicleui] vehicle; player')
if filter == 'HELPFUL' then
header:SetAttribute('consolidateDuration', -1)
header:SetAttribute('includeWeapons', 1)
end
A:UpdateHeader(header)
header:Show()
return header
end
function A:Initialize()
if E.private.auras.disableBlizzard then
_G.BuffFrame:Kill()
_G.TemporaryEnchantFrame:Kill()
end
if not E.private.auras.enable then return end
A.Initialized = true
A.db = E.db.auras
local xoffset = -(6 + E.Border)
if E.private.auras.buffsHeader then
A.BuffFrame = A:CreateAuraHeader('HELPFUL')
A.BuffFrame:ClearAllPoints()
A.BuffFrame:SetPoint('TOPRIGHT', _G.MMHolder or _G.MinimapCluster, 'TOPLEFT', xoffset, -E.Spacing)
E:CreateMover(A.BuffFrame, 'BuffsMover', L["Player Buffs"], nil, nil, nil, nil, nil, 'auras,buffs')
if Masque and MasqueGroupBuffs then A.BuffsMasqueGroup = MasqueGroupBuffs end
end
if E.private.auras.debuffsHeader then
A.DebuffFrame = A:CreateAuraHeader('HARMFUL')
A.DebuffFrame:ClearAllPoints()
A.DebuffFrame:SetPoint('BOTTOMRIGHT', _G.MMHolder or _G.MinimapCluster, 'BOTTOMLEFT', xoffset, E.Spacing)
E:CreateMover(A.DebuffFrame, 'DebuffsMover', L["Player Debuffs"], nil, nil, nil, nil, nil, 'auras,debuffs')
if Masque and MasqueGroupDebuffs then A.DebuffsMasqueGroup = MasqueGroupDebuffs end
end
end
E:RegisterModule(A:GetName())

View File

@@ -0,0 +1,52 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Button name='ElvUIAuraTemplate' inherits='SecureActionButtonTemplate, BackdropTemplate' virtual='true' framelevel='4'>
<!-- framelevel 4 for Masque support -->
<Size x='26' y='26'/>
<Attributes>
<Attribute name='type' value='cancelaura'/>
</Attributes>
<Scripts>
<OnLoad>
ElvUI[1]:GetModule('Auras'):CreateIcon(self)
self:RegisterForClicks('RightButtonUp')
</OnLoad>
<OnEnter>
GameTooltip:SetOwner(self, 'ANCHOR_BOTTOMLEFT', -5, -5)
if self:GetAttribute('index') then
GameTooltip:SetUnitAura(SecureButton_GetUnit(self:GetParent()), self:GetID(), self:GetParent():GetAttribute('filter'))
elseif self:GetAttribute('target-slot') then
GameTooltip:SetInventoryItem('player', self:GetID())
end
</OnEnter>
<OnLeave function='GameTooltip_Hide'/>
</Scripts>
</Button>
<!-- Theres gotta be a better way to do this.. -->
<Button name='ElvUIAuraTemplate16' inherits='ElvUIAuraTemplate' virtual='true'><Size x='16' y='16'/></Button>
<Button name='ElvUIAuraTemplate18' inherits='ElvUIAuraTemplate' virtual='true'><Size x='18' y='18'/></Button>
<Button name='ElvUIAuraTemplate20' inherits='ElvUIAuraTemplate' virtual='true'><Size x='20' y='20'/></Button>
<Button name='ElvUIAuraTemplate22' inherits='ElvUIAuraTemplate' virtual='true'><Size x='22' y='22'/></Button>
<Button name='ElvUIAuraTemplate24' inherits='ElvUIAuraTemplate' virtual='true'><Size x='24' y='24'/></Button>
<Button name='ElvUIAuraTemplate26' inherits='ElvUIAuraTemplate' virtual='true'><Size x='26' y='26'/></Button>
<Button name='ElvUIAuraTemplate28' inherits='ElvUIAuraTemplate' virtual='true'><Size x='28' y='28'/></Button>
<Button name='ElvUIAuraTemplate30' inherits='ElvUIAuraTemplate' virtual='true'><Size x='30' y='30'/></Button>
<Button name='ElvUIAuraTemplate32' inherits='ElvUIAuraTemplate' virtual='true'><Size x='32' y='32'/></Button>
<Button name='ElvUIAuraTemplate34' inherits='ElvUIAuraTemplate' virtual='true'><Size x='34' y='34'/></Button>
<Button name='ElvUIAuraTemplate36' inherits='ElvUIAuraTemplate' virtual='true'><Size x='36' y='36'/></Button>
<Button name='ElvUIAuraTemplate38' inherits='ElvUIAuraTemplate' virtual='true'><Size x='38' y='38'/></Button>
<Button name='ElvUIAuraTemplate40' inherits='ElvUIAuraTemplate' virtual='true'><Size x='40' y='40'/></Button>
<Button name='ElvUIAuraTemplate42' inherits='ElvUIAuraTemplate' virtual='true'><Size x='42' y='42'/></Button>
<Button name='ElvUIAuraTemplate44' inherits='ElvUIAuraTemplate' virtual='true'><Size x='44' y='44'/></Button>
<Button name='ElvUIAuraTemplate46' inherits='ElvUIAuraTemplate' virtual='true'><Size x='46' y='46'/></Button>
<Button name='ElvUIAuraTemplate48' inherits='ElvUIAuraTemplate' virtual='true'><Size x='48' y='48'/></Button>
<Button name='ElvUIAuraTemplate50' inherits='ElvUIAuraTemplate' virtual='true'><Size x='50' y='50'/></Button>
<Button name='ElvUIAuraTemplate52' inherits='ElvUIAuraTemplate' virtual='true'><Size x='52' y='52'/></Button>
<Button name='ElvUIAuraTemplate54' inherits='ElvUIAuraTemplate' virtual='true'><Size x='54' y='54'/></Button>
<Button name='ElvUIAuraTemplate56' inherits='ElvUIAuraTemplate' virtual='true'><Size x='56' y='56'/></Button>
<Button name='ElvUIAuraTemplate58' inherits='ElvUIAuraTemplate' virtual='true'><Size x='58' y='58'/></Button>
<Button name='ElvUIAuraTemplate60' inherits='ElvUIAuraTemplate' virtual='true'><Size x='60' y='60'/></Button>
<!-- Oh, Look! A file we need to load.. -->
<Script file='Auras.lua'/>
</Ui>

180
Modules/Bags/BagBar.lua Normal file
View File

@@ -0,0 +1,180 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Bags')
local _G = _G
local ipairs = ipairs
local unpack = unpack
local tinsert = tinsert
local CreateFrame = CreateFrame
local GetBagSlotFlag = GetBagSlotFlag
local RegisterStateDriver = RegisterStateDriver
local NUM_BAG_FRAMES = NUM_BAG_FRAMES
local LE_BAG_FILTER_FLAG_EQUIPMENT = LE_BAG_FILTER_FLAG_EQUIPMENT
local NUM_LE_BAG_FILTER_FLAGS = NUM_LE_BAG_FILTER_FLAGS
local function OnEnter()
if not E.db.bags.bagBar.mouseover then return; end
E:UIFrameFadeIn(B.BagBar, 0.2, B.BagBar:GetAlpha(), 1)
end
local function OnLeave()
if not E.db.bags.bagBar.mouseover then return; end
E:UIFrameFadeOut(B.BagBar, 0.2, B.BagBar:GetAlpha(), 0)
end
function B:SkinBag(bag)
local icon = _G[bag:GetName()..'IconTexture']
bag.oldTex = icon:GetTexture()
bag:StripTextures()
bag:CreateBackdrop()
bag:StyleButton(true)
bag.IconBorder:Kill()
bag.backdrop:SetAllPoints()
icon:SetInside()
icon:SetTexture(bag.oldTex)
icon:SetTexCoord(unpack(E.TexCoords))
end
function B:SizeAndPositionBagBar()
if not B.BagBar then return; end
local buttonSpacing = E.db.bags.bagBar.spacing
local backdropSpacing = E.db.bags.bagBar.backdropSpacing
local bagBarSize = E.db.bags.bagBar.size
local showBackdrop = E.db.bags.bagBar.showBackdrop
local growthDirection = E.db.bags.bagBar.growthDirection
local sortDirection = E.db.bags.bagBar.sortDirection
local visibility = E.db.bags.bagBar.visibility
if visibility and visibility:match('[\n\r]') then
visibility = visibility:gsub('[\n\r]','')
end
RegisterStateDriver(B.BagBar, 'visibility', visibility)
B.BagBar:SetAlpha(E.db.bags.bagBar.mouseover and 0 or 1)
B.BagBar.backdrop:SetShown(showBackdrop)
local bdpSpacing = (showBackdrop and backdropSpacing + E.Border) or 0
local btnSpacing = (buttonSpacing + E.Border)
for i, button in ipairs(B.BagBar.buttons) do
local prevButton = B.BagBar.buttons[i-1]
button:Size(bagBarSize, bagBarSize)
button:ClearAllPoints()
if growthDirection == 'HORIZONTAL' and sortDirection == 'ASCENDING' then
if i == 1 then
button:Point('LEFT', B.BagBar, 'LEFT', bdpSpacing, 0)
elseif prevButton then
button:Point('LEFT', prevButton, 'RIGHT', btnSpacing, 0)
end
elseif growthDirection == 'VERTICAL' and sortDirection == 'ASCENDING' then
if i == 1 then
button:Point('TOP', B.BagBar, 'TOP', 0, -bdpSpacing)
elseif prevButton then
button:Point('TOP', prevButton, 'BOTTOM', 0, -btnSpacing)
end
elseif growthDirection == 'HORIZONTAL' and sortDirection == 'DESCENDING' then
if i == 1 then
button:Point('RIGHT', B.BagBar, 'RIGHT', -bdpSpacing, 0)
elseif prevButton then
button:Point('RIGHT', prevButton, 'LEFT', -btnSpacing, 0)
end
else
if i == 1 then
button:Point('BOTTOM', B.BagBar, 'BOTTOM', 0, bdpSpacing)
elseif prevButton then
button:Point('BOTTOM', prevButton, 'TOP', 0, btnSpacing)
end
end
for j = LE_BAG_FILTER_FLAG_EQUIPMENT, NUM_LE_BAG_FILTER_FLAGS do
local active = GetBagSlotFlag(i - 1, j)
if active then
button.ElvUIFilterIcon:SetTexture(B.BAG_FILTER_ICONS[j])
button.ElvUIFilterIcon:SetShown(E.db.bags.showAssignedIcon)
local r, g, b, a = unpack(B.AssignmentColors[j])
button.forcedBorderColors = {r, g, b, a}
button.backdrop:SetBackdropBorderColor(r, g, b, a)
break -- this loop
else
button.ElvUIFilterIcon:SetShown(false)
button.forcedBorderColors = nil
button.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
end
end
end
local btnSize = bagBarSize * (NUM_BAG_FRAMES + 1)
local btnSpace = btnSpacing * NUM_BAG_FRAMES
local bdpDoubled = bdpSpacing * 2
if growthDirection == 'HORIZONTAL' then
B.BagBar:Width(btnSize + btnSpace + bdpDoubled)
B.BagBar:Height(bagBarSize + bdpDoubled)
else
B.BagBar:Height(btnSize + btnSpace + bdpDoubled)
B.BagBar:Width(bagBarSize + bdpDoubled)
end
end
function B:LoadBagBar()
if not E.private.bags.bagBar then return end
B.BagBar = CreateFrame('Frame', 'ElvUIBags', E.UIParent)
B.BagBar:Point('TOPRIGHT', _G.RightChatPanel, 'TOPLEFT', -4, 0)
B.BagBar.buttons = {}
B.BagBar:CreateBackdrop(E.db.bags.transparent and 'Transparent')
B.BagBar.backdrop:SetAllPoints()
B.BagBar:EnableMouse(true)
B.BagBar:SetScript('OnEnter', OnEnter)
B.BagBar:SetScript('OnLeave', OnLeave)
_G.MainMenuBarBackpackButton:SetParent(B.BagBar)
_G.MainMenuBarBackpackButton:ClearAllPoints()
_G.MainMenuBarBackpackButtonCount:FontTemplate(nil, 10)
_G.MainMenuBarBackpackButtonCount:ClearAllPoints()
_G.MainMenuBarBackpackButtonCount:Point('BOTTOMRIGHT', _G.MainMenuBarBackpackButton, 'BOTTOMRIGHT', -1, 4)
_G.MainMenuBarBackpackButton:HookScript('OnEnter', OnEnter)
_G.MainMenuBarBackpackButton:HookScript('OnLeave', OnLeave)
tinsert(B.BagBar.buttons, _G.MainMenuBarBackpackButton)
B:SkinBag(_G.MainMenuBarBackpackButton)
for i = 0, NUM_BAG_FRAMES-1 do
local b = _G['CharacterBag'..i..'Slot']
b:SetParent(B.BagBar)
b:HookScript('OnEnter', OnEnter)
b:HookScript('OnLeave', OnLeave)
B:SkinBag(b)
tinsert(B.BagBar.buttons, b)
end
--Item assignment
for i, bagButton in ipairs(B.BagBar.buttons) do
B:CreateFilterIcon(bagButton)
bagButton.id = (i - 1)
bagButton:SetScript('OnClick', function(holder, button)
if button == 'RightButton' then
B.AssignBagDropdown.holder = holder
_G.ToggleDropDownMenu(1, nil, B.AssignBagDropdown, 'cursor')
else
if holder.id == 0 then
_G.MainMenuBarBackpackButton_OnClick(holder)
else
_G.BagSlotButton_OnClick(holder)
end
end
end)
end
B:SizeAndPositionBagBar()
E:CreateMover(B.BagBar, 'BagsMover', L["Bags"], nil, nil, nil, nil, nil, 'bags,general')
B:RegisterEvent('BAG_SLOT_FLAGS_UPDATED', 'SizeAndPositionBagBar')
end

2461
Modules/Bags/Bags.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Script file='Bags.lua'/>
<Script file='BagBar.lua'/>
<Script file='Sort.lua'/>
</Ui>

949
Modules/Bags/Sort.lua Normal file
View File

@@ -0,0 +1,949 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Bags')
local Search = E.Libs.ItemSearch
local ipairs, pairs, select, unpack, pcall = ipairs, pairs, select, unpack, pcall
local strmatch, gmatch, strfind = strmatch, gmatch, strfind
local tinsert, tremove, sort, wipe = tinsert, tremove, sort, wipe
local tonumber, floor, band = tonumber, floor, bit.band
local ContainerIDToInventoryID = ContainerIDToInventoryID
local GetContainerItemID = GetContainerItemID
local GetContainerItemInfo = GetContainerItemInfo
local GetContainerItemLink = GetContainerItemLink
local GetContainerNumFreeSlots = GetContainerNumFreeSlots
local GetContainerNumSlots = GetContainerNumSlots
local GetCurrentGuildBankTab = GetCurrentGuildBankTab
local GetCursorInfo = GetCursorInfo
local GetGuildBankItemInfo = GetGuildBankItemInfo
local GetGuildBankItemLink = GetGuildBankItemLink
local GetGuildBankTabInfo = GetGuildBankTabInfo
local GetInventoryItemLink = GetInventoryItemLink
local GetItemFamily = GetItemFamily
local GetItemInfo = GetItemInfo
local GetTime = GetTime
local InCombatLockdown = InCombatLockdown
local PickupContainerItem = PickupContainerItem
local PickupGuildBankItem = PickupGuildBankItem
local QueryGuildBankTab = QueryGuildBankTab
local SplitContainerItem = SplitContainerItem
local SplitGuildBankItem = SplitGuildBankItem
local C_PetJournalGetPetInfoBySpeciesID = C_PetJournal.GetPetInfoBySpeciesID
local LE_ITEM_CLASS_ARMOR = LE_ITEM_CLASS_ARMOR
local LE_ITEM_CLASS_WEAPON = LE_ITEM_CLASS_WEAPON
local guildBags = {51,52,53,54,55,56,57,58}
local bankBags = {BANK_CONTAINER}
local MAX_MOVE_TIME = 1.25
for i = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do
tinsert(bankBags, i)
end
local playerBags = {}
for i = 0, NUM_BAG_SLOTS do
tinsert(playerBags, i)
end
local allBags = {}
for _,i in ipairs(playerBags) do
tinsert(allBags, i)
end
for _,i in ipairs(bankBags) do
tinsert(allBags, i)
end
for _,i in ipairs(guildBags) do
tinsert(allBags, i)
end
local coreGroups = {
guild = guildBags,
bank = bankBags,
bags = playerBags,
all = allBags,
}
local bagCache = {}
local bagIDs = {}
local bagQualities = {}
local bagPetIDs = {}
local bagStacks = {}
local bagMaxStacks = {}
local bagGroups = {}
local initialOrder = {}
local bagSorted, bagLocked = {}, {}
local bagRole
local moves = {}
local targetItems = {}
local sourceUsed = {}
local targetSlots = {}
local specialtyBags = {}
local emptySlots = {}
local moveRetries = 0
local lastItemID, lockStop, lastDestination, lastMove
local moveTracker = {}
local inventorySlots = {
INVTYPE_AMMO = 0,
INVTYPE_HEAD = 1,
INVTYPE_NECK = 2,
INVTYPE_SHOULDER = 3,
INVTYPE_BODY = 4,
INVTYPE_CHEST = 5,
INVTYPE_ROBE = 5,
INVTYPE_WAIST = 6,
INVTYPE_LEGS = 7,
INVTYPE_FEET = 8,
INVTYPE_WRIST = 9,
INVTYPE_HAND = 10,
INVTYPE_FINGER = 11,
INVTYPE_TRINKET = 12,
INVTYPE_CLOAK = 13,
INVTYPE_WEAPON = 14,
INVTYPE_SHIELD = 15,
INVTYPE_2HWEAPON = 16,
INVTYPE_WEAPONMAINHAND = 18,
INVTYPE_WEAPONOFFHAND = 19,
INVTYPE_HOLDABLE = 20,
INVTYPE_RANGED = 21,
INVTYPE_THROWN = 22,
INVTYPE_RANGEDRIGHT = 23,
INVTYPE_RELIC = 24,
INVTYPE_TABARD = 25,
}
local conjured_items = {
[5512] = true, -- Healthstone
[162518] = true, -- Mystical Flask
[113509] = true, -- Conjured Mana Bun
}
local safe = {
[BANK_CONTAINER] = true,
[0] = true
}
local WAIT_TIME = 0.05
do
local t = 0
local frame = CreateFrame('Frame')
frame:SetScript('OnUpdate', function(_, elapsed)
t = t + (elapsed or 0.01)
if t > WAIT_TIME then
t = 0
B:DoMoves()
end
end)
frame:Hide()
B.SortUpdateTimer = frame
end
local function IsGuildBankBag(bagid)
return bagid > 50 and bagid <= 58
end
local function UpdateLocation(from, to)
if bagIDs[from] == bagIDs[to] and (bagStacks[to] < bagMaxStacks[to]) then
local stackSize = bagMaxStacks[to]
if (bagStacks[to] + bagStacks[from]) > stackSize then
bagStacks[from] = bagStacks[from] - (stackSize - bagStacks[to])
bagStacks[to] = stackSize
else
bagStacks[to] = bagStacks[to] + bagStacks[from]
bagStacks[from] = nil
bagIDs[from] = nil
bagQualities[from] = nil
bagMaxStacks[from] = nil
end
else
bagIDs[from], bagIDs[to] = bagIDs[to], bagIDs[from]
bagQualities[from], bagQualities[to] = bagQualities[to], bagQualities[from]
bagStacks[from], bagStacks[to] = bagStacks[to], bagStacks[from]
bagMaxStacks[from], bagMaxStacks[to] = bagMaxStacks[to], bagMaxStacks[from]
end
end
local function PrimarySort(a, b)
local aName, _, _, aLvl, _, _, _, _, _, _, aPrice = GetItemInfo(bagIDs[a])
local bName, _, _, bLvl, _, _, _, _, _, _, bPrice = GetItemInfo(bagIDs[b])
if aLvl ~= bLvl and aLvl and bLvl then
return aLvl > bLvl
end
if aPrice ~= bPrice and aPrice and bPrice then
return aPrice > bPrice
end
if aName and bName then
return aName < bName
end
end
local function DefaultSort(a, b)
local aID = bagIDs[a]
local bID = bagIDs[b]
if not aID or not bID then return aID end
if bagPetIDs[a] and bagPetIDs[b] then
local aName, _, aType = C_PetJournalGetPetInfoBySpeciesID(aID)
local bName, _, bType = C_PetJournalGetPetInfoBySpeciesID(bID)
if aType and bType and aType ~= bType then
return aType > bType
end
if aName and bName and aName ~= bName then
return aName < bName
end
end
local aOrder, bOrder = initialOrder[a], initialOrder[b]
if aID == bID then
local aCount = bagStacks[a]
local bCount = bagStacks[b]
if aCount and bCount and aCount == bCount then
return aOrder < bOrder
elseif aCount and bCount then
return aCount < bCount
end
end
local _, _, _, _, _, _, _, _, aEquipLoc, _, _, aItemClassId, aItemSubClassId = GetItemInfo(aID)
local _, _, _, _, _, _, _, _, bEquipLoc, _, _, bItemClassId, bItemSubClassId = GetItemInfo(bID)
local aRarity, bRarity = bagQualities[a], bagQualities[b]
if bagPetIDs[a] then
aRarity = 1
end
if bagPetIDs[b] then
bRarity = 1
end
if conjured_items[aID] then
aRarity = -99
end
if conjured_items[bID] then
bRarity = -99
end
if aRarity ~= bRarity and aRarity and bRarity then
return aRarity > bRarity
end
if aItemClassId ~= bItemClassId then
return (aItemClassId or 99) < (bItemClassId or 99)
end
if aItemClassId == LE_ITEM_CLASS_ARMOR or aItemClassId == LE_ITEM_CLASS_WEAPON then
aEquipLoc = inventorySlots[aEquipLoc] or -1
bEquipLoc = inventorySlots[bEquipLoc] or -1
if aEquipLoc == bEquipLoc then
return PrimarySort(a, b)
end
if aEquipLoc and bEquipLoc then
return aEquipLoc < bEquipLoc
end
end
if aItemClassId == bItemClassId and (aItemSubClassId == bItemSubClassId) then
return PrimarySort(a, b)
end
return (aItemSubClassId or 99) < (bItemSubClassId or 99)
end
local function ReverseSort(a, b)
return DefaultSort(b, a)
end
local function UpdateSorted(source, destination)
for i, bs in pairs(bagSorted) do
if bs == source then
bagSorted[i] = destination
elseif bs == destination then
bagSorted[i] = source
end
end
end
local function ShouldMove(source, destination)
if destination == source then return end
if not bagIDs[source] then return end
if bagIDs[source] == bagIDs[destination] and bagStacks[source] == bagStacks[destination] then return end
return true
end
local function IterateForwards(bagList, i)
i = i + 1
local step = 1
for _,bag in ipairs(bagList) do
local slots = B:GetNumSlots(bag, bagRole)
if i > slots + step then
step = step + slots
else
for slot = 1, slots do
if step == i then
return i, bag, slot
end
step = step + 1
end
end
end
bagRole = nil
end
local function IterateBackwards(bagList, i)
i = i + 1
local step = 1
for ii = #bagList, 1, -1 do
local bag = bagList[ii]
local slots = B:GetNumSlots(bag, bagRole)
if i > slots + step then
step = step + slots
else
for slot=slots, 1, -1 do
if step == i then
return i, bag, slot
end
step = step + 1
end
end
end
bagRole = nil
end
function B:IterateBags(bagList, reverse, role)
bagRole = role
return (reverse and IterateBackwards or IterateForwards), bagList, 0
end
function B:GetItemLink(bag, slot)
if IsGuildBankBag(bag) then
return GetGuildBankItemLink(bag - 50, slot)
else
return GetContainerItemLink(bag, slot)
end
end
function B:GetItemID(bag, slot)
if IsGuildBankBag(bag) then
local link = B:GetItemLink(bag, slot)
return link and tonumber(strmatch(link, 'item:(%d+)'))
else
return GetContainerItemID(bag, slot)
end
end
function B:GetItemInfo(bag, slot)
if IsGuildBankBag(bag) then
return GetGuildBankItemInfo(bag - 50, slot)
else
return GetContainerItemInfo(bag, slot)
end
end
function B:PickupItem(bag, slot)
if IsGuildBankBag(bag) then
return PickupGuildBankItem(bag - 50, slot)
else
return PickupContainerItem(bag, slot)
end
end
function B:SplitItem(bag, slot, amount)
if IsGuildBankBag(bag) then
return SplitGuildBankItem(bag - 50, slot, amount)
else
return SplitContainerItem(bag, slot, amount)
end
end
function B:GetNumSlots(bag)
if IsGuildBankBag(bag) then
local name, _, canView = GetGuildBankTabInfo(bag - 50)
if name and canView then
return 98
end
else
return GetContainerNumSlots(bag)
end
return 0
end
function B:ConvertLinkToID(link)
if not link then return end
local item = strmatch(link, 'item:(%d+)')
if item then return tonumber(item) end
local ks = strmatch(link, 'keystone:(%d+)')
if ks then return tonumber(ks), nil, true end
local bp = strmatch(link, 'battlepet:(%d+)')
if bp then return tonumber(bp), true end
end
local function DefaultCanMove()
return true
end
function B:Encode_BagSlot(bag, slot)
return (bag*100) + slot
end
function B:Decode_BagSlot(int)
return floor(int/100), int % 100
end
function B:IsPartial(bag, slot)
local bagSlot = B:Encode_BagSlot(bag, slot)
return ((bagMaxStacks[bagSlot] or 0) - (bagStacks[bagSlot] or 0)) > 0
end
function B:EncodeMove(source, target)
return (source * 10000) + target
end
function B:DecodeMove(move)
local s = floor(move/10000)
local t = move%10000
s = (t>9000) and (s+1) or s
t = (t>9000) and (t-10000) or t
return s, t
end
function B:AddMove(source, destination)
UpdateLocation(source, destination)
tinsert(moves, 1, B:EncodeMove(source, destination))
end
function B:ScanBags()
for _, bag, slot in B:IterateBags(allBags) do
local bagSlot = B:Encode_BagSlot(bag, slot)
local itemLink = B:GetItemLink(bag, slot)
local itemID, isBattlePet, isKeystone = B:ConvertLinkToID(itemLink)
if itemID then
if isBattlePet then
bagPetIDs[bagSlot] = itemID
bagMaxStacks[bagSlot] = 1
elseif isKeystone then
bagMaxStacks[bagSlot] = 1
bagQualities[bagSlot] = 4
bagStacks[bagSlot] = 1
else
bagMaxStacks[bagSlot] = select(8, GetItemInfo(itemID))
end
bagIDs[bagSlot] = itemID
if not isKeystone then
bagQualities[bagSlot] = select(3, GetItemInfo(itemLink))
bagStacks[bagSlot] = select(2, B:GetItemInfo(bag, slot))
end
end
end
end
function B:IsSpecialtyBag(bagID)
if safe[bagID] or IsGuildBankBag(bagID) then return false end
local inventorySlot = ContainerIDToInventoryID(bagID)
if not inventorySlot then return false end
local bag = GetInventoryItemLink('player', inventorySlot)
if not bag then return false end
local family = GetItemFamily(bag)
if family == 0 or family == nil then return false end
return family
end
function B:CanItemGoInBag(bag, slot, targetBag)
if IsGuildBankBag(targetBag) then return true end
local item = bagIDs[B:Encode_BagSlot(bag, slot)]
local itemFamily = GetItemFamily(item)
if itemFamily and itemFamily > 0 then
local equipSlot = select(9, GetItemInfo(item))
if equipSlot == 'INVTYPE_BAG' then
itemFamily = 1
end
end
local bagFamily = select(2, GetContainerNumFreeSlots(targetBag))
if itemFamily then
return (bagFamily == 0) or band(itemFamily, bagFamily) > 0
else
return false
end
end
function B.Compress(...)
for i=1, select('#', ...) do
local bags = select(i, ...)
B.Stack(bags, bags, B.IsPartial)
end
end
function B.Stack(sourceBags, targetBags, canMove)
if not canMove then canMove = DefaultCanMove end
for _, bag, slot in B:IterateBags(targetBags, nil, 'deposit') do
local bagSlot = B:Encode_BagSlot(bag, slot)
local itemID = bagIDs[bagSlot]
if itemID and (bagStacks[bagSlot] ~= bagMaxStacks[bagSlot]) then
targetItems[itemID] = (targetItems[itemID] or 0) + 1
tinsert(targetSlots, bagSlot)
end
end
for _, bag, slot in B:IterateBags(sourceBags, true, 'withdraw') do
local sourceSlot = B:Encode_BagSlot(bag, slot)
local itemID = bagIDs[sourceSlot]
if itemID and targetItems[itemID] and canMove(itemID, bag, slot) then
for i = #targetSlots, 1, -1 do
local targetedSlot = targetSlots[i]
if bagIDs[sourceSlot] and bagIDs[targetedSlot] == itemID and targetedSlot ~= sourceSlot and not (bagStacks[targetedSlot] == bagMaxStacks[targetedSlot]) and not sourceUsed[targetedSlot] then
B:AddMove(sourceSlot, targetedSlot)
sourceUsed[sourceSlot] = true
if bagStacks[targetedSlot] == bagMaxStacks[targetedSlot] then
targetItems[itemID] = (targetItems[itemID] > 1) and (targetItems[itemID] - 1) or nil
end
if bagStacks[sourceSlot] == 0 then
targetItems[itemID] = (targetItems[itemID] > 1) and (targetItems[itemID] - 1) or nil
break
end
if not targetItems[itemID] then break end
end
end
end
end
wipe(targetItems)
wipe(targetSlots)
wipe(sourceUsed)
end
local blackListedSlots = {}
local blackList = {}
local blackListQueries = {}
function B:BuildBlacklist(...)
for entry in pairs(...) do
local itemName = GetItemInfo(entry)
if itemName then
blackList[itemName] = true
elseif entry ~= '' then
if strfind(entry, '%[') and strfind(entry, '%]') then
--For some reason the entry was not treated as a valid item. Extract the item name.
entry = strmatch(entry, '%[(.*)%]')
end
blackListQueries[#blackListQueries+1] = entry
end
end
end
function B.Sort(bags, sorter, invertDirection)
if not sorter then sorter = invertDirection and ReverseSort or DefaultSort end
--Wipe tables before we begin
wipe(blackList)
wipe(blackListQueries)
wipe(blackListedSlots)
--Build blacklist of items based on the profile and global list
B:BuildBlacklist(B.db.ignoredItems)
B:BuildBlacklist(E.global.bags.ignoredItems)
for i, bag, slot in B:IterateBags(bags, nil, 'both') do
local bagSlot = B:Encode_BagSlot(bag, slot)
local link = B:GetItemLink(bag, slot)
if link then
if blackList[GetItemInfo(link)] then
blackListedSlots[bagSlot] = true
end
if not blackListedSlots[bagSlot] then
local method
for _,itemsearchquery in pairs(blackListQueries) do
method = Search.Matches
if Search.Filters.tipPhrases.keywords[itemsearchquery] then
method = Search.TooltipPhrase
itemsearchquery = Search.Filters.tipPhrases.keywords[itemsearchquery]
end
local success, result = pcall(method, Search, link, itemsearchquery)
if success and result then
blackListedSlots[bagSlot] = result
break
end
end
end
end
if not blackListedSlots[bagSlot] then
initialOrder[bagSlot] = i
tinsert(bagSorted, bagSlot)
end
end
sort(bagSorted, sorter)
local passNeeded = true
while passNeeded do
passNeeded = false
local i = 1
for _, bag, slot in B:IterateBags(bags, nil, 'both') do
local destination = B:Encode_BagSlot(bag, slot)
local source = bagSorted[i]
if not blackListedSlots[destination] then
if ShouldMove(source, destination) then
if not (bagLocked[source] or bagLocked[destination]) then
B:AddMove(source, destination)
UpdateSorted(source, destination)
bagLocked[source] = true
bagLocked[destination] = true
else
passNeeded = true
end
end
i = i + 1
end
end
wipe(bagLocked)
end
wipe(bagSorted)
wipe(initialOrder)
end
function B.FillBags(from, to)
B.Stack(from, to)
for _, bag in ipairs(to) do
if B:IsSpecialtyBag(bag) then
tinsert(specialtyBags, bag)
end
end
if #specialtyBags > 0 then
B:Fill(from, specialtyBags)
end
B.Fill(from, to)
wipe(specialtyBags)
end
function B.Fill(sourceBags, targetBags, reverse, canMove)
if not canMove then canMove = DefaultCanMove end
--Wipe tables before we begin
wipe(blackList)
wipe(blackListedSlots)
--Build blacklist of items based on the profile and global list
B:BuildBlacklist(B.db.ignoredItems)
B:BuildBlacklist(E.global.bags.ignoredItems)
for _, bag, slot in B:IterateBags(targetBags, reverse, 'deposit') do
local bagSlot = B:Encode_BagSlot(bag, slot)
if not bagIDs[bagSlot] then
tinsert(emptySlots, bagSlot)
end
end
for _, bag, slot in B:IterateBags(sourceBags, not reverse, 'withdraw') do
if #emptySlots == 0 then break end
local bagSlot = B:Encode_BagSlot(bag, slot)
local targetBag = B:Decode_BagSlot(emptySlots[1])
local link = B:GetItemLink(bag, slot)
if link and blackList[GetItemInfo(link)] then
blackListedSlots[bagSlot] = true
end
if bagIDs[bagSlot] and B:CanItemGoInBag(bag, slot, targetBag) and canMove(bagIDs[bagSlot], bag, slot) and not blackListedSlots[bagSlot] then
B:AddMove(bagSlot, tremove(emptySlots, 1))
end
end
wipe(emptySlots)
end
function B.SortBags(...)
for i=1, select('#', ...) do
local bags = select(i, ...)
for _, slotNum in ipairs(bags) do
local bagType = B:IsSpecialtyBag(slotNum)
if bagType == false then bagType = 'Normal' end
if not bagCache[bagType] then bagCache[bagType] = {} end
tinsert(bagCache[bagType], slotNum)
end
for bagType, sortedBags in pairs(bagCache) do
if bagType ~= 'Normal' then
B.Stack(sortedBags, sortedBags, B.IsPartial)
B.Stack(bagCache.Normal, sortedBags)
B.Fill(bagCache.Normal, sortedBags, B.db.sortInverted)
B.Sort(sortedBags, nil, B.db.sortInverted)
wipe(sortedBags)
end
end
if bagCache.Normal then
B.Stack(bagCache.Normal, bagCache.Normal, B.IsPartial)
B.Sort(bagCache.Normal, nil, B.db.sortInverted)
wipe(bagCache.Normal)
end
wipe(bagCache)
wipe(bagGroups)
end
end
function B:StartStacking()
wipe(bagMaxStacks)
wipe(bagStacks)
wipe(bagIDs)
wipe(bagQualities)
wipe(bagPetIDs)
wipe(moveTracker)
if #moves > 0 then
B.SortUpdateTimer:Show()
else
B:StopStacking()
end
end
function B:RegisterUpdateDelayed()
local shouldUpdateFade
for _, bagFrame in pairs(B.BagFrames) do
if bagFrame.registerUpdate then
B:UpdateAllSlots(bagFrame)
bagFrame:RegisterEvent('BAG_UPDATE')
bagFrame:RegisterEvent('BAG_UPDATE_COOLDOWN')
for _, event in pairs(bagFrame.events) do
bagFrame:RegisterEvent(event)
end
bagFrame.registerUpdate = nil
shouldUpdateFade = true -- we should refresh the bag search after sorting
end
end
if shouldUpdateFade then
B:RefreshSearch() -- this will clear the bag lock look during a sort
end
end
function B:StopStacking(message, noUpdate)
wipe(moves)
wipe(moveTracker)
moveRetries, lastItemID, lockStop, lastDestination, lastMove = 0, nil, nil, nil, nil
B.SortUpdateTimer:Hide()
if not noUpdate then
--Add a delayed update call, as BAG_UPDATE fires slightly delayed
-- and we don't want the last few unneeded updates to be catched
E:Delay(0.6, B.RegisterUpdateDelayed)
end
if message then
E:Print(message)
end
end
function B:DoMove(move)
if GetCursorInfo() == 'item' then
return false, 'cursorhasitem'
end
local source, target = B:DecodeMove(move)
local sourceBag, sourceSlot = B:Decode_BagSlot(source)
local targetBag, targetSlot = B:Decode_BagSlot(target)
local _, sourceCount, sourceLocked = B:GetItemInfo(sourceBag, sourceSlot)
local _, targetCount, targetLocked = B:GetItemInfo(targetBag, targetSlot)
if sourceLocked or targetLocked then
return false, 'source/target_locked'
end
local sourceItemID = B:GetItemID(sourceBag, sourceSlot)
local targetItemID = B:GetItemID(targetBag, targetSlot)
if not sourceItemID then
if moveTracker[source] then
return false, 'move incomplete'
else
return B:StopStacking(L["Confused.. Try Again!"])
end
end
local stackSize = select(8, GetItemInfo(sourceItemID))
if sourceItemID == targetItemID and (targetCount ~= stackSize) and ((targetCount + sourceCount) > stackSize) then
B:SplitItem(sourceBag, sourceSlot, stackSize - targetCount)
else
B:PickupItem(sourceBag, sourceSlot)
end
if GetCursorInfo() == 'item' then
B:PickupItem(targetBag, targetSlot)
end
local sourceGuild = IsGuildBankBag(sourceBag)
local targetGuild = IsGuildBankBag(targetBag)
if sourceGuild then
QueryGuildBankTab(sourceBag - 50)
end
if targetGuild then
QueryGuildBankTab(targetBag - 50)
end
return true, sourceItemID, source, targetItemID, target, sourceGuild or targetGuild
end
function B:DoMoves()
if InCombatLockdown() then
return B:StopStacking(L["Confused.. Try Again!"])
end
local cursorType, cursorItemID = GetCursorInfo()
if cursorType == 'item' and cursorItemID then
if lastItemID ~= cursorItemID then
return B:StopStacking(L["Confused.. Try Again!"])
end
if moveRetries < 100 then
local targetBag, targetSlot = B:Decode_BagSlot(lastDestination)
local _, _, targetLocked = B:GetItemInfo(targetBag, targetSlot)
if not targetLocked then
B:PickupItem(targetBag, targetSlot)
WAIT_TIME = 0.1
lockStop = GetTime()
moveRetries = moveRetries + 1
return
end
end
end
if lockStop then
for slot, itemID in pairs(moveTracker) do
local actualItemID = B:GetItemID(B:Decode_BagSlot(slot))
if actualItemID ~= itemID then
WAIT_TIME = 0.1
if (GetTime() - lockStop) > MAX_MOVE_TIME then
if lastMove and moveRetries < 100 then
local success, moveID, moveSource, targetID, moveTarget, wasGuild = B:DoMove(lastMove)
WAIT_TIME = wasGuild and 0.5 or 0.1
if not success then
lockStop = GetTime()
moveRetries = moveRetries + 1
return
end
moveTracker[moveSource] = targetID
moveTracker[moveTarget] = moveID
lastDestination = moveTarget
-- lastMove = moves[i] --Where does 'i' come from???
lastItemID = moveID
-- tremove(moves, i) --Where does 'i' come from???
return
end
B:StopStacking()
return
end
return --give processing time to happen
end
moveTracker[slot] = nil
end
end
lastItemID, lockStop, lastDestination, lastMove = nil, nil, nil, nil
wipe(moveTracker)
local success, moveID, targetID, moveSource, moveTarget, wasGuild
if #moves > 0 then
for i = #moves, 1, -1 do
success, moveID, moveSource, targetID, moveTarget, wasGuild = B:DoMove(moves[i])
if not success then
WAIT_TIME = wasGuild and 0.3 or 0.1
lockStop = GetTime()
return
end
moveTracker[moveSource] = targetID
moveTracker[moveTarget] = moveID
lastDestination = moveTarget
lastMove = moves[i]
lastItemID = moveID
tremove(moves, i)
if moves[i-1] then
WAIT_TIME = wasGuild and 0.3 or 0
return
end
end
end
B:StopStacking()
end
function B:GetGroup(id)
if strmatch(id, '^[-%d,]+$') then
local bags = {}
for b in gmatch(id, '-?%d+') do
tinsert(bags, tonumber(b))
end
return bags
end
return coreGroups[id]
end
function B:CommandDecorator(func, groupsDefaults)
return function(groups)
if B.SortUpdateTimer:IsShown() then
B:StopStacking(L["Already Running.. Bailing Out!"], true)
return
end
wipe(bagGroups)
if not groups or #groups == 0 then
groups = groupsDefaults
end
for bags in (groups or ''):gmatch('%S+') do
if bags == 'guild' then
bags = B:GetGroup(bags)
if bags then
tinsert(bagGroups, {bags[GetCurrentGuildBankTab()]})
end
else
bags = B:GetGroup(bags)
if bags then
tinsert(bagGroups, bags)
end
end
end
B:ScanBags()
if func(unpack(bagGroups)) == false then
return
end
wipe(bagGroups)
B:StartStacking()
end
end

View File

@@ -0,0 +1,195 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local Misc = E:GetModule('Misc')
local _G = _G
local pairs = pairs
local ipairs = ipairs
local CreateFrame = CreateFrame
local hooksecurefunc = hooksecurefunc
local POSITION, ANCHOR_POINT, YOFFSET = 'TOP', 'BOTTOM', -10
function E:PostAlertMove()
local AlertFrameMover = _G.AlertFrameMover
local AlertFrameHolder = _G.AlertFrameHolder
local _, y = AlertFrameMover:GetCenter()
local screenHeight = E.UIParent:GetTop()
if y > (screenHeight / 2) then
POSITION = 'TOP'
ANCHOR_POINT = 'BOTTOM'
YOFFSET = -10
AlertFrameMover:SetText(AlertFrameMover.textString..' (Grow Down)')
else
POSITION = 'BOTTOM'
ANCHOR_POINT = 'TOP'
YOFFSET = 10
AlertFrameMover:SetText(AlertFrameMover.textString..' (Grow Up)')
end
local AlertFrame = _G.AlertFrame
local GroupLootContainer = _G.GroupLootContainer
local rollBars = Misc.RollBars
if E.private.general.lootRoll then
local lastframe, lastShownFrame
for i, frame in pairs(rollBars) do
frame:ClearAllPoints()
if i ~= 1 then
if POSITION == 'TOP' then
frame:Point('TOP', lastframe, 'BOTTOM', 0, -4)
else
frame:Point('BOTTOM', lastframe, 'TOP', 0, 4)
end
else
if POSITION == 'TOP' then
frame:Point('TOP', AlertFrameHolder, 'BOTTOM', 0, -4)
else
frame:Point('BOTTOM', AlertFrameHolder, 'TOP', 0, 4)
end
end
lastframe = frame
if frame:IsShown() then
lastShownFrame = frame
end
end
AlertFrame:ClearAllPoints()
GroupLootContainer:ClearAllPoints()
if lastShownFrame then
AlertFrame:SetAllPoints(lastShownFrame)
GroupLootContainer:Point(POSITION, lastShownFrame, ANCHOR_POINT, 0, YOFFSET)
else
AlertFrame:SetAllPoints(AlertFrameHolder)
GroupLootContainer:Point(POSITION, AlertFrameHolder, ANCHOR_POINT, 0, YOFFSET)
end
if GroupLootContainer:IsShown() then
B.GroupLootContainer_Update(GroupLootContainer)
end
else
AlertFrame:ClearAllPoints()
AlertFrame:SetAllPoints(AlertFrameHolder)
GroupLootContainer:ClearAllPoints()
GroupLootContainer:Point(POSITION, AlertFrameHolder, ANCHOR_POINT, 0, YOFFSET)
if GroupLootContainer:IsShown() then
B.GroupLootContainer_Update(GroupLootContainer)
end
end
end
function B:AdjustAnchors(relativeAlert)
if self.alertFrame:IsShown() then
self.alertFrame:ClearAllPoints()
self.alertFrame:Point(POSITION, relativeAlert, ANCHOR_POINT, 0, YOFFSET)
return self.alertFrame
end
return relativeAlert
end
function B:AdjustAnchorsNonAlert(relativeAlert)
if self.anchorFrame:IsShown() then
self.anchorFrame:ClearAllPoints()
self.anchorFrame:Point(POSITION, relativeAlert, ANCHOR_POINT, 0, YOFFSET)
return self.anchorFrame
end
return relativeAlert
end
function B:AdjustQueuedAnchors(relativeAlert)
for alertFrame in self.alertFramePool:EnumerateActive() do
alertFrame:ClearAllPoints()
alertFrame:Point(POSITION, relativeAlert, ANCHOR_POINT, 0, YOFFSET)
relativeAlert = alertFrame
end
return relativeAlert
end
function B:GroupLootContainer_Update()
local lastIdx
for i=1, self.maxIndex do
local frame = self.rollFrames[i]
if frame then
frame:ClearAllPoints()
local prevFrame = self.rollFrames[i-1]
if prevFrame and prevFrame ~= frame then
frame:Point(POSITION, prevFrame, ANCHOR_POINT, 0, YOFFSET)
else
frame:Point(POSITION, self, POSITION, 0, YOFFSET)
end
lastIdx = i
end
end
if lastIdx then
self:Height(self.reservedSize * lastIdx)
self:Show()
else
self:Hide()
end
end
local function AlertSubSystem_AdjustPosition(alertFrameSubSystem)
if alertFrameSubSystem.alertFramePool then --queued alert system
alertFrameSubSystem.AdjustAnchors = B.AdjustQueuedAnchors
elseif not alertFrameSubSystem.anchorFrame then --simple alert system
alertFrameSubSystem.AdjustAnchors = B.AdjustAnchors
elseif alertFrameSubSystem.anchorFrame then --anchor frame system
alertFrameSubSystem.AdjustAnchors = B.AdjustAnchorsNonAlert
end
end
function B:AlertMovers()
local AlertFrameHolder = CreateFrame('Frame', 'AlertFrameHolder', E.UIParent)
AlertFrameHolder:Size(180, 20)
AlertFrameHolder:Point('TOP', E.UIParent, 'TOP', -1, -18)
_G.GroupLootContainer:EnableMouse(false) -- Prevent this weird non-clickable area stuff since 8.1; Monitor this, as it may cause addon compatibility.
_G.UIPARENT_MANAGED_FRAME_POSITIONS.GroupLootContainer = nil
E:CreateMover(AlertFrameHolder, 'AlertFrameMover', L["Loot / Alert Frames"], nil, nil, E.PostAlertMove, nil, nil, 'general,blizzUIImprovements')
--Replace AdjustAnchors functions to allow alerts to grow down if needed.
--We will need to keep an eye on this in case it taints. It shouldn't, but you never know.
for _, alertFrameSubSystem in ipairs(_G.AlertFrame.alertFrameSubSystems) do
AlertSubSystem_AdjustPosition(alertFrameSubSystem)
end
--This should catch any alert systems that are created by other addons
hooksecurefunc(_G.AlertFrame, 'AddAlertFrameSubSystem', function(_, alertFrameSubSystem)
AlertSubSystem_AdjustPosition(alertFrameSubSystem)
end)
self:SecureHook(_G.AlertFrame, 'UpdateAnchors', E.PostAlertMove)
hooksecurefunc('GroupLootContainer_Update', B.GroupLootContainer_Update)
--[=[ Code you can use for alert testing
--Queued Alerts:
/run AchievementAlertSystem:AddAlert(5192)
/run CriteriaAlertSystem:AddAlert(9023, 'Doing great!')
/run LootAlertSystem:AddAlert('\124cffa335ee\124Hitem:18832::::::::::\124h[Brutality Blade]\124h\124r', 1, 1, 1, 1, false, false, 0, false, false)
/run LootUpgradeAlertSystem:AddAlert('\124cffa335ee\124Hitem:18832::::::::::\124h[Brutality Blade]\124h\124r', 1, 1, 1, nil, nil, false)
/run MoneyWonAlertSystem:AddAlert(81500)
/run NewRecipeLearnedAlertSystem:AddAlert(204)
--Simple Alerts
/run GuildChallengeAlertSystem:AddAlert(3, 2, 5)
/run InvasionAlertSystem:AddAlert(678, DUNGEON_FLOOR_THENEXUS1, true, 1, 1)
/run WorldQuestCompleteAlertSystem:AddAlert(AlertFrameMixin:BuildQuestData(42114))
/run GarrisonBuildingAlertSystem:AddAlert(GARRISON_CACHE)
/run GarrisonFollowerAlertSystem:AddAlert(204, 'Ben Stone', 90, 3, false)
/run GarrisonMissionAlertSystem:AddAlert(681) (Requires a mission ID that is in your mission list.)
/run GarrisonShipFollowerAlertSystem:AddAlert(592, 'Test', 'Transport', 'GarrBuilding_Barracks_1_H', 3, 2, 1)
/run LegendaryItemAlertSystem:AddAlert('\124cffa335ee\124Hitem:18832::::::::::\124h[Brutality Blade]\124h\124r')
/run EntitlementDeliveredAlertSystem:AddAlert('', [[Interface\Icons\Ability_pvp_gladiatormedallion]], TRINKET0SLOT, 214)
/run RafRewardDeliveredAlertSystem:AddAlert('', [[Interface\Icons\Ability_pvp_gladiatormedallion]], TRINKET0SLOT, 214)
/run DigsiteCompleteAlertSystem:AddAlert('Human')
--Bonus Rolls
/run BonusRollFrame_CloseBonusRoll()
/run BonusRollFrame_StartBonusRoll(242969,'test',10,515,1273,14) --515 is darkmoon token, change to another currency id you have
]=]
end

View File

@@ -0,0 +1,178 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local LSM = E.Libs.LSM
local _G = _G
local floor = floor
local format = format
local CreateFrame = CreateFrame
local UnitPowerMax = UnitPowerMax
local UnitPower = UnitPower
local GetUnitPowerBarInfo = GetUnitPowerBarInfo
local GetUnitPowerBarStrings = GetUnitPowerBarStrings
local function updateTooltip(self)
if _G.GameTooltip:IsForbidden() then return end
if self.powerName and self.powerTooltip then
_G.GameTooltip:SetText(self.powerName, 1, 1, 1)
_G.GameTooltip:AddLine(self.powerTooltip, nil, nil, nil, 1)
_G.GameTooltip:Show()
end
end
local function onEnter(self)
if (not self:IsVisible()) or _G.GameTooltip:IsForbidden() then return end
_G.GameTooltip:ClearAllPoints()
_G.GameTooltip_SetDefaultAnchor(_G.GameTooltip, self)
updateTooltip(self)
end
local function onLeave()
_G.GameTooltip:Hide()
end
function B:SetAltPowerBarText(text, name, value, max, percent)
local textFormat = E.db.general.altPowerBar.textFormat
if textFormat == 'NONE' or not textFormat then
text:SetText('')
elseif textFormat == 'NAME' then
text:SetText(format('%s', name))
elseif textFormat == 'NAMEPERC' then
text:SetText(format('%s: %s%%', name, percent))
elseif textFormat == 'NAMECURMAX' then
text:SetText(format('%s: %s / %s', name, value, max))
elseif textFormat == 'NAMECURMAXPERC' then
text:SetText(format('%s: %s / %s - %s%%', name, value, max, percent))
elseif textFormat == 'PERCENT' then
text:SetText(format('%s%%', percent))
elseif textFormat == 'CURMAX' then
text:SetText(format('%s / %s', value, max))
elseif textFormat == 'CURMAXPERC' then
text:SetText(format('%s / %s - %s%%', value, max, percent))
end
end
function B:PositionAltPowerBar()
local holder = CreateFrame('Frame', 'AltPowerBarHolder', E.UIParent)
holder:Point('TOP', E.UIParent, 'TOP', -1, -36)
holder:Size(128, 50)
_G.PlayerPowerBarAlt:ClearAllPoints()
_G.PlayerPowerBarAlt:Point('CENTER', holder, 'CENTER')
_G.PlayerPowerBarAlt:SetParent(holder)
_G.PlayerPowerBarAlt:SetMovable(true)
_G.PlayerPowerBarAlt:SetUserPlaced(true)
_G.UIPARENT_MANAGED_FRAME_POSITIONS.PlayerPowerBarAlt = nil
E:CreateMover(holder, 'AltPowerBarMover', L["Alternative Power"], nil, nil, nil, nil, nil, 'general,alternativePowerGroup')
end
function B:UpdateAltPowerBarColors()
local bar = _G.ElvUI_AltPowerBar
if E.db.general.altPowerBar.statusBarColorGradient then
if bar.colorGradientR and bar.colorGradientG and bar.colorGradientB then
bar:SetStatusBarColor(bar.colorGradientR, bar.colorGradientG, bar.colorGradientB)
elseif bar.powerValue then
local power, maxPower = bar.powerValue or 0, bar.powerMaxValue or 0
local value = (maxPower > 0 and power / maxPower) or 0
bar.colorGradientValue = value
local r, g, b = E:ColorGradient(value, 0.8,0,0, 0.8,0.8,0, 0,0.8,0)
bar.colorGradientR, bar.colorGradientG, bar.colorGradientB = r, g, b
bar:SetStatusBarColor(r, g, b)
else
bar:SetStatusBarColor(0.6, 0.6, 0.6) -- uh, fallback!
end
else
local color = E.db.general.altPowerBar.statusBarColor
bar:SetStatusBarColor(color.r, color.g, color.b)
end
end
function B:UpdateAltPowerBarSettings()
local bar = _G.ElvUI_AltPowerBar
local db = E.db.general.altPowerBar
bar:Size(db.width or 250, db.height or 20)
bar:SetStatusBarTexture(LSM:Fetch('statusbar', db.statusBar))
bar.text:FontTemplate(LSM:Fetch('font', db.font), db.fontSize or 12, db.fontOutline or 'OUTLINE')
_G.AltPowerBarHolder:Size(bar.backdrop:GetSize())
E:SetSmoothing(bar, db.smoothbars)
B:SetAltPowerBarText(bar.text, bar.powerName or '', bar.powerValue or 0, bar.powerMaxValue or 0, bar.powerPercent or 0)
end
function B:UpdateAltPowerBar()
_G.PlayerPowerBarAlt:UnregisterAllEvents()
_G.PlayerPowerBarAlt:Hide()
local barInfo = GetUnitPowerBarInfo('player');
local powerName, powerTooltip = GetUnitPowerBarStrings('player');
if barInfo then
local power = UnitPower('player', _G.ALTERNATE_POWER_INDEX)
local maxPower = UnitPowerMax('player', _G.ALTERNATE_POWER_INDEX) or 0
local perc = (maxPower > 0 and floor(power / maxPower * 100)) or 0
self.powerMaxValue = maxPower
self.powerName = powerName
self.powerPercent = perc
self.powerTooltip = powerTooltip
self.powerValue = power
self:Show()
self:SetMinMaxValues(barInfo.minPower, maxPower)
self:SetValue(power)
if E.db.general.altPowerBar.statusBarColorGradient then
local value = (maxPower > 0 and power / maxPower) or 0
self.colorGradientValue = value
local r, g, b = E:ColorGradient(value, 0.8,0,0, 0.8,0.8,0, 0,0.8,0)
self.colorGradientR, self.colorGradientG, self.colorGradientB = r, g, b
self:SetStatusBarColor(r, g, b)
end
B:SetAltPowerBarText(self.text, powerName or '', power or 0, maxPower, perc)
else
self.powerMaxValue = nil
self.powerName = nil
self.powerPercent = nil
self.powerTooltip = nil
self.powerValue = nil
self:Hide()
end
end
function B:SkinAltPowerBar()
if not E.db.general.altPowerBar.enable then return end
local powerbar = CreateFrame('StatusBar', 'ElvUI_AltPowerBar', E.UIParent)
powerbar:CreateBackdrop(nil, true)
powerbar:SetMinMaxValues(0, 200)
powerbar:Point('CENTER', _G.AltPowerBarHolder)
powerbar:Hide()
powerbar:SetScript('OnEnter', onEnter)
powerbar:SetScript('OnLeave', onLeave)
powerbar.text = powerbar:CreateFontString(nil, 'OVERLAY')
powerbar.text:Point('CENTER', powerbar, 'CENTER')
powerbar.text:SetJustifyH('CENTER')
B:UpdateAltPowerBarSettings()
B:UpdateAltPowerBarColors()
--Event handling
powerbar:RegisterEvent('UNIT_POWER_UPDATE')
powerbar:RegisterEvent('UNIT_POWER_BAR_SHOW')
powerbar:RegisterEvent('UNIT_POWER_BAR_HIDE')
powerbar:RegisterEvent('PLAYER_ENTERING_WORLD')
powerbar:SetScript('OnEvent', B.UpdateAltPowerBar)
end

View File

@@ -0,0 +1,120 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local Skins = E:GetModule('Skins')
local TT = E:GetModule('Tooltip')
local _G = _G
local CreateFrame = CreateFrame
local GetQuestLogRewardXP = GetQuestLogRewardXP
local GetRewardXP = GetRewardXP
local IsAddOnLoaded = IsAddOnLoaded
local UnitXP = UnitXP
local UnitXPMax = UnitXPMax
local hooksecurefunc = hooksecurefunc
local C_QuestLog_ShouldShowQuestRewards = C_QuestLog.ShouldShowQuestRewards
local C_QuestLog_GetSelectedQuest = C_QuestLog.GetSelectedQuest
--This changes the growth direction of the toast frame depending on position of the mover
local function PostBNToastMove(mover)
local x, y = mover:GetCenter();
local screenHeight = E.UIParent:GetTop();
local screenWidth = E.UIParent:GetRight()
local anchorPoint
if y > (screenHeight / 2) then
anchorPoint = (x > (screenWidth/2)) and 'TOPRIGHT' or 'TOPLEFT'
else
anchorPoint = (x > (screenWidth/2)) and 'BOTTOMRIGHT' or 'BOTTOMLEFT'
end
mover.anchorPoint = anchorPoint
_G.BNToastFrame:ClearAllPoints()
_G.BNToastFrame:Point(anchorPoint, mover)
end
function B:Initialize()
B.Initialized = true
B:EnhanceColorPicker()
B:KillBlizzard()
B:DisableHelpTip()
B:DisableNPE()
B:AlertMovers()
B:PositionCaptureBar()
B:PositionDurabilityFrame()
B:PositionGMFrames()
B:SkinBlizzTimers()
B:PositionVehicleFrame()
B:PositionTalkingHead()
B:Handle_LevelUpDisplay_BossBanner()
B:Handle_UIWidgets()
B:GarrisonDropDown()
if not IsAddOnLoaded('DugisGuideViewerZ') then
B:MoveObjectiveFrame()
end
if not IsAddOnLoaded('SimplePowerBar') then
B:PositionAltPowerBar()
B:SkinAltPowerBar()
end
E:CreateMover(_G.LossOfControlFrame, 'LossControlMover', L["Loss Control Icon"])
-- Battle.Net Frame
_G.BNToastFrame:Point('TOPRIGHT', _G.MMHolder or _G.Minimap, 'BOTTOMRIGHT', 0, -10)
E:CreateMover(_G.BNToastFrame, 'BNETMover', L["BNet Frame"], nil, nil, PostBNToastMove)
_G.BNToastFrame.mover:Size(_G.BNToastFrame:GetSize())
TT:SecureHook(_G.BNToastFrame, 'SetPoint', 'RepositionBNET')
-- Quick Join Bug
CreateFrame('Frame'):SetScript('OnUpdate', function()
if _G.LFRBrowseFrame.timeToClear then
_G.LFRBrowseFrame.timeToClear = nil
end
end)
--Add (+X%) to quest rewards experience text
hooksecurefunc('QuestInfo_Display', function()
local unitXP, unitXPMax = UnitXP('player'), UnitXPMax('player')
if _G.QuestInfoFrame.questLog then
local selectedQuest = C_QuestLog_GetSelectedQuest()
if C_QuestLog_ShouldShowQuestRewards(selectedQuest) then
local xp = GetQuestLogRewardXP()
if xp and xp > 0 then
local text = _G.MapQuestInfoRewardsFrame.XPFrame.Name:GetText()
if text then _G.MapQuestInfoRewardsFrame.XPFrame.Name:SetFormattedText('%s (|cff4beb2c+%.2f%%|r)', text, (((unitXP + xp) / unitXPMax) - (unitXP / unitXPMax))*100) end
end
end
else
local xp = GetRewardXP()
if xp and xp > 0 then
local text = _G.QuestInfoXPFrame.ValueText:GetText()
if text then _G.QuestInfoXPFrame.ValueText:SetFormattedText('%s (|cff4beb2c+%.2f%%|r)', text, (((unitXP + xp) / unitXPMax) - (unitXP / unitXPMax))*100) end
end
end
end)
-- MicroButton Talent Alert
local TalentMicroButtonAlert = _G.TalentMicroButtonAlert
if TalentMicroButtonAlert then -- why do we need to check this?
if E.global.general.showMissingTalentAlert then
TalentMicroButtonAlert:ClearAllPoints()
TalentMicroButtonAlert:Point('CENTER', E.UIParent, 'TOP', 0, -75)
TalentMicroButtonAlert:StripTextures()
TalentMicroButtonAlert.Arrow:Hide()
TalentMicroButtonAlert.Text:FontTemplate()
TalentMicroButtonAlert:CreateBackdrop('Transparent')
Skins:HandleCloseButton(TalentMicroButtonAlert.CloseButton)
TalentMicroButtonAlert.tex = TalentMicroButtonAlert:CreateTexture(nil, 'OVERLAY')
TalentMicroButtonAlert.tex:Point('RIGHT', -10, 0)
TalentMicroButtonAlert.tex:SetTexture([[Interface\DialogFrame\UI-Dialog-Icon-AlertNew]])
TalentMicroButtonAlert.tex:Size(32, 32)
else
TalentMicroButtonAlert:Kill() -- Kill it, because then the blizz default will show
end
end
end
E:RegisterModule(B:GetName())

View File

@@ -0,0 +1,28 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local hooksecurefunc = hooksecurefunc
local function CaptureUpdate()
if _G.NUM_EXTENDED_UI_FRAMES then
local captureBar
for i=1, _G.NUM_EXTENDED_UI_FRAMES do
captureBar = _G['WorldStateCaptureBar' .. i]
if captureBar and captureBar:IsVisible() then
captureBar:ClearAllPoints()
if i == 1 then
captureBar:Point('TOP', E.UIParent, 'TOP', 0, -170)
else
captureBar:Point('TOPLEFT', _G['WorldStateCaptureBar' .. i - 1], 'TOPLEFT', 0, -45)
end
end
end
end
end
function B:PositionCaptureBar()
hooksecurefunc('UIParent_ManageFramePositions', CaptureUpdate)
end

View File

@@ -0,0 +1,404 @@
------------------------------------------------------------------------------
-- Credit to Jaslm, most of this code is his from the addon ColorPickerPlus.
-- Modified and optimized by Simpy.
------------------------------------------------------------------------------
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local S = E:GetModule('Skins')
local _G = _G
local strlen, strjoin, gsub = strlen, strjoin, gsub
local tonumber, floor, strsub, wipe = tonumber, floor, strsub, wipe
local CreateFrame = CreateFrame
local IsAddOnLoaded = IsAddOnLoaded
local IsControlKeyDown = IsControlKeyDown
local IsModifierKeyDown = IsModifierKeyDown
local CALENDAR_COPY_EVENT, CALENDAR_PASTE_EVENT = CALENDAR_COPY_EVENT, CALENDAR_PASTE_EVENT
local CLASS, DEFAULT = CLASS, DEFAULT
local colorBuffer = {}
local function alphaValue(num)
return num and floor(((1 - num) * 100) + .05) or 0
end
local function UpdateAlphaText(alpha)
if not alpha then alpha = alphaValue(_G.OpacitySliderFrame:GetValue()) end
_G.ColorPPBoxA:SetText(alpha)
end
local function UpdateAlpha(tbox)
local num = tbox:GetNumber()
if num > 100 then
tbox:SetText(100)
num = 100
end
_G.OpacitySliderFrame:SetValue(1 - (num / 100))
end
local function expandFromThree(r, g, b)
return strjoin('',r,r,g,g,b,b)
end
local function extendToSix(str)
for _=1, 6-strlen(str) do str=str..0 end
return str
end
local function GetHexColor(box)
local rgb, rgbSize = box:GetText(), box:GetNumLetters()
if rgbSize == 3 then
rgb = gsub(rgb, '(%x)(%x)(%x)$', expandFromThree)
elseif rgbSize < 6 then
rgb = gsub(rgb, '(.+)$', extendToSix)
end
local r, g, b = tonumber(strsub(rgb,0,2),16) or 0, tonumber(strsub(rgb,3,4),16) or 0, tonumber(strsub(rgb,5,6),16) or 0
return r/255, g/255, b/255
end
local function UpdateColorTexts(r, g, b, box)
if not (r and g and b) then
r, g, b = _G.ColorPickerFrame:GetColorRGB()
if box then
if box == _G.ColorPPBoxH then
r, g, b = GetHexColor(box)
else
local num = box:GetNumber()
if num > 255 then num = 255 end
local c = num/255
if box == _G.ColorPPBoxR then
r = c
elseif box == _G.ColorPPBoxG then
g = c
elseif box == _G.ColorPPBoxB then
b = c
end
end
end
end
-- we want those /255 values
r, g, b = r*255, g*255, b*255
_G.ColorPPBoxH:SetText(('%.2x%.2x%.2x'):format(r, g, b))
_G.ColorPPBoxR:SetText(r)
_G.ColorPPBoxG:SetText(g)
_G.ColorPPBoxB:SetText(b)
end
local function UpdateColor()
local r, g, b = GetHexColor(_G.ColorPPBoxH)
_G.ColorPickerFrame:SetColorRGB(r, g, b)
_G.ColorSwatch:SetColorTexture(r, g, b)
end
local function ColorPPBoxA_SetFocus()
_G.ColorPPBoxA:SetFocus()
end
local function ColorPPBoxR_SetFocus()
_G.ColorPPBoxR:SetFocus()
end
local delayWait, delayFunc = 0.15
local function delayCall()
if delayFunc then
delayFunc()
delayFunc = nil
end
end
local function onColorSelect(frame, r, g, b)
if frame.noColorCallback then return end
_G.ColorSwatch:SetColorTexture(r, g, b)
UpdateColorTexts(r, g, b)
if r == 0 and g == 0 and b == 0 then
return
end
if not frame:IsVisible() then
delayCall()
elseif not delayFunc then
delayFunc = _G.ColorPickerFrame.func
E:Delay(delayWait, delayCall)
end
end
local function onValueChanged(frame, value)
local alpha = alphaValue(value)
if frame.lastAlpha ~= alpha then
frame.lastAlpha = alpha
UpdateAlphaText(alpha)
if not _G.ColorPickerFrame:IsVisible() then
delayCall()
else
local opacityFunc = _G.ColorPickerFrame.opacityFunc
if delayFunc and (delayFunc ~= opacityFunc) then
delayFunc = opacityFunc
elseif not delayFunc then
delayFunc = opacityFunc
E:Delay(delayWait, delayCall)
end
end
end
end
function B:EnhanceColorPicker()
if IsAddOnLoaded('ColorPickerPlus') then return end
--Skin the default frame, move default buttons into place
_G.ColorPickerFrame:SetClampedToScreen(true)
_G.ColorPickerFrame:CreateBackdrop('Transparent')
_G.ColorPickerFrame.Border:Hide()
_G.ColorPickerFrame.Header:StripTextures()
_G.ColorPickerFrame.Header:ClearAllPoints()
_G.ColorPickerFrame.Header:Point('TOP', _G.ColorPickerFrame, 0, 0)
_G.ColorPickerCancelButton:ClearAllPoints()
_G.ColorPickerOkayButton:ClearAllPoints()
_G.ColorPickerCancelButton:Point('BOTTOMRIGHT', _G.ColorPickerFrame, 'BOTTOMRIGHT', -6, 6)
_G.ColorPickerCancelButton:Point('BOTTOMLEFT', _G.ColorPickerFrame, 'BOTTOM', 0, 6)
_G.ColorPickerOkayButton:Point('BOTTOMLEFT', _G.ColorPickerFrame,'BOTTOMLEFT', 6,6)
_G.ColorPickerOkayButton:Point('RIGHT', _G.ColorPickerCancelButton,'LEFT', -4,0)
S:HandleSliderFrame(_G.OpacitySliderFrame)
S:HandleButton(_G.ColorPickerOkayButton)
S:HandleButton(_G.ColorPickerCancelButton)
_G.ColorPickerFrame:HookScript('OnShow', function(frame)
-- get color that will be replaced
local r, g, b = frame:GetColorRGB()
_G.ColorPPOldColorSwatch:SetColorTexture(r,g,b)
-- show/hide the alpha box
if frame.hasOpacity then
_G.ColorPPBoxA:Show()
_G.ColorPPBoxLabelA:Show()
_G.ColorPPBoxH:SetScript('OnTabPressed', ColorPPBoxA_SetFocus)
UpdateAlphaText()
UpdateColorTexts()
frame:Width(405)
else
_G.ColorPPBoxA:Hide()
_G.ColorPPBoxLabelA:Hide()
_G.ColorPPBoxH:SetScript('OnTabPressed', ColorPPBoxR_SetFocus)
UpdateColorTexts()
frame:Width(345)
end
-- Memory Fix, Colorpicker will call the self.func() 100x per second, causing fps/memory issues,
-- We overwrite these two scripts and set a limit on how often we allow a call their update functions
_G.OpacitySliderFrame:SetScript('OnValueChanged', onValueChanged)
frame:SetScript('OnColorSelect', onColorSelect)
end)
-- make the Color Picker dialog a bit taller, to make room for edit boxes
_G.ColorPickerFrame:Height(_G.ColorPickerFrame:GetHeight() + 40)
-- move the Color Swatch
_G.ColorSwatch:ClearAllPoints()
_G.ColorSwatch:Point('TOPLEFT', _G.ColorPickerFrame, 'TOPLEFT', 215, -45)
-- add Color Swatch for original color
local t = _G.ColorPickerFrame:CreateTexture('ColorPPOldColorSwatch')
local w, h = _G.ColorSwatch:GetSize()
t:Size(w*0.75,h*0.75)
t:SetColorTexture(0,0,0)
-- OldColorSwatch to appear beneath ColorSwatch
t:SetDrawLayer('BORDER')
t:Point('BOTTOMLEFT', 'ColorSwatch', 'TOPRIGHT', -(w/2), -(h/3))
-- add Color Swatch for the copied color
t = _G.ColorPickerFrame:CreateTexture('ColorPPCopyColorSwatch')
t:SetColorTexture(0,0,0)
t:Size(w,h)
t:Hide()
-- add copy button to the _G.ColorPickerFrame
local b = CreateFrame('Button', 'ColorPPCopy', _G.ColorPickerFrame, 'UIPanelButtonTemplate, BackdropTemplate')
S:HandleButton(b)
b:SetText(CALENDAR_COPY_EVENT)
b:Size(60, 22)
b:Point('TOPLEFT', 'ColorSwatch', 'BOTTOMLEFT', 0, -5)
-- copy color into buffer on button click
b:SetScript('OnClick', function()
-- copy current dialog colors into buffer
colorBuffer.r, colorBuffer.g, colorBuffer.b = _G.ColorPickerFrame:GetColorRGB()
-- enable Paste button and display copied color into swatch
_G.ColorPPPaste:Enable()
_G.ColorPPCopyColorSwatch:SetColorTexture(colorBuffer.r, colorBuffer.g, colorBuffer.b)
_G.ColorPPCopyColorSwatch:Show()
colorBuffer.a = (_G.ColorPickerFrame.hasOpacity and _G.OpacitySliderFrame:GetValue()) or nil
end)
--class color button
b = CreateFrame('Button', 'ColorPPClass', _G.ColorPickerFrame, 'UIPanelButtonTemplate, BackdropTemplate')
b:SetText(CLASS)
S:HandleButton(b)
b:Size(80, 22)
b:Point('TOP', 'ColorPPCopy', 'BOTTOMRIGHT', 0, -7)
b:SetScript('OnClick', function()
local color = E:ClassColor(E.myclass, true)
_G.ColorPickerFrame:SetColorRGB(color.r, color.g, color.b)
_G.ColorSwatch:SetColorTexture(color.r, color.g, color.b)
if _G.ColorPickerFrame.hasOpacity then
_G.OpacitySliderFrame:SetValue(0)
end
end)
-- add paste button to the _G.ColorPickerFrame
b = CreateFrame('Button', 'ColorPPPaste', _G.ColorPickerFrame, 'UIPanelButtonTemplate, BackdropTemplate')
b:SetText(CALENDAR_PASTE_EVENT)
S:HandleButton(b)
b:Size(60, 22)
b:Point('TOPLEFT', 'ColorPPCopy', 'TOPRIGHT', 2, 0)
b:Disable() -- enable when something has been copied
-- paste color on button click, updating frame components
b:SetScript('OnClick', function()
_G.ColorPickerFrame:SetColorRGB(colorBuffer.r, colorBuffer.g, colorBuffer.b)
_G.ColorSwatch:SetColorTexture(colorBuffer.r, colorBuffer.g, colorBuffer.b)
if _G.ColorPickerFrame.hasOpacity then
if colorBuffer.a then --color copied had an alpha value
_G.OpacitySliderFrame:SetValue(colorBuffer.a)
end
end
end)
-- add defaults button to the _G.ColorPickerFrame
b = CreateFrame('Button', 'ColorPPDefault', _G.ColorPickerFrame, 'UIPanelButtonTemplate, BackdropTemplate')
b:SetText(DEFAULT)
S:HandleButton(b)
b:Size(80, 22)
b:Point('TOPLEFT', 'ColorPPClass', 'BOTTOMLEFT', 0, -7)
b:Disable() -- enable when something has been copied
b:SetScript('OnHide', function(btn)
if btn.colors then
wipe(btn.colors)
end
end)
b:SetScript('OnShow', function(btn)
if btn.colors then
btn:Enable()
else
btn:Disable()
end
end)
-- paste color on button click, updating frame components
b:SetScript('OnClick', function(btn)
local colors = btn.colors
_G.ColorPickerFrame:SetColorRGB(colors.r, colors.g, colors.b)
_G.ColorSwatch:SetColorTexture(colors.r, colors.g, colors.b)
if _G.ColorPickerFrame.hasOpacity then
if colors.a then
_G.OpacitySliderFrame:SetValue(colors.a)
end
end
end)
-- position Color Swatch for copy color
_G.ColorPPCopyColorSwatch:Point('BOTTOM', 'ColorPPPaste', 'TOP', 0, 10)
-- move the Opacity Slider Frame to align with bottom of Copy ColorSwatch
_G.OpacitySliderFrame:ClearAllPoints()
_G.OpacitySliderFrame:Point('BOTTOM', 'ColorPPDefault', 'BOTTOM', 0, 0)
_G.OpacitySliderFrame:Point('RIGHT', 'ColorPickerFrame', 'RIGHT', -35, 18)
-- set up edit box frames and interior label and text areas
local boxes = { 'R', 'G', 'B', 'H', 'A' }
for i = 1, #boxes do
local rgb = boxes[i]
local box = CreateFrame('EditBox', 'ColorPPBox'..rgb, _G.ColorPickerFrame, 'InputBoxTemplate, BackdropTemplate')
box:Point('TOP', 'ColorPickerWheel', 'BOTTOM', 0, -15)
box:SetFrameStrata('DIALOG')
box:SetAutoFocus(false)
box:SetTextInsets(0,7,0,0)
box:SetJustifyH('RIGHT')
box:Height(24)
box:SetID(i)
S:HandleEditBox(box)
-- hex entry box
if i == 4 then
box:SetMaxLetters(6)
box:Width(56)
box:SetNumeric(false)
else
box:SetMaxLetters(3)
box:Width(40)
box:SetNumeric(true)
end
-- label
local label = box:CreateFontString('ColorPPBoxLabel'..rgb, 'ARTWORK', 'GameFontNormalSmall')
label:Point('RIGHT', 'ColorPPBox'..rgb, 'LEFT', -5, 0)
label:SetText(i == 4 and '#' or rgb)
label:SetTextColor(1, 1, 1)
-- set up scripts to handle event appropriately
if i == 5 then
box:SetScript('OnKeyUp', function(eb, key)
local copyPaste = IsControlKeyDown() and key == 'V'
if key == 'BACKSPACE' or copyPaste or (strlen(key) == 1 and not IsModifierKeyDown()) then
UpdateAlpha(eb)
elseif key == 'ENTER' or key == 'ESCAPE' then
eb:ClearFocus()
UpdateAlpha(eb)
end
end)
else
box:SetScript('OnKeyUp', function(eb, key)
local copyPaste = IsControlKeyDown() and key == 'V'
if key == 'BACKSPACE' or copyPaste or (strlen(key) == 1 and not IsModifierKeyDown()) then
if i ~= 4 then UpdateColorTexts(nil, nil, nil, eb) end
if i == 4 and eb:GetNumLetters() ~= 6 then return end
UpdateColor()
elseif key == 'ENTER' or key == 'ESCAPE' then
eb:ClearFocus()
UpdateColorTexts(nil, nil, nil, eb)
UpdateColor()
end
end)
end
box:SetScript('OnEditFocusGained', function(eb) eb:SetCursorPosition(0) eb:HighlightText() end)
box:SetScript('OnEditFocusLost', function(eb) eb:HighlightText(0,0) end)
box:Show()
end
-- finish up with placement
_G.ColorPPBoxA:Point('RIGHT', 'OpacitySliderFrame', 'RIGHT', 10, 0)
_G.ColorPPBoxH:Point('RIGHT', 'ColorPPDefault', 'RIGHT', -10, 0)
_G.ColorPPBoxB:Point('RIGHT', 'ColorPPDefault', 'LEFT', -40, 0)
_G.ColorPPBoxG:Point('RIGHT', 'ColorPPBoxB', 'LEFT', -25, 0)
_G.ColorPPBoxR:Point('RIGHT', 'ColorPPBoxG', 'LEFT', -25, 0)
-- define the order of tab cursor movement
_G.ColorPPBoxR:SetScript('OnTabPressed', function() _G.ColorPPBoxG:SetFocus() end)
_G.ColorPPBoxG:SetScript('OnTabPressed', function() _G.ColorPPBoxB:SetFocus() end)
_G.ColorPPBoxB:SetScript('OnTabPressed', function() _G.ColorPPBoxH:SetFocus() end)
_G.ColorPPBoxA:SetScript('OnTabPressed', function() _G.ColorPPBoxR:SetFocus() end)
-- make the color picker movable.
local mover = CreateFrame('Frame', nil, _G.ColorPickerFrame)
mover:Point('TOPLEFT', _G.ColorPickerFrame, 'TOP', -60, 0)
mover:Point('BOTTOMRIGHT', _G.ColorPickerFrame, 'TOP', 60, -15)
mover:SetScript('OnMouseDown', function() _G.ColorPickerFrame:StartMoving() end)
mover:SetScript('OnMouseUp', function() _G.ColorPickerFrame:StopMovingOrSizing() end)
mover:EnableMouse(true)
_G.ColorPickerFrame:SetUserPlaced(true)
_G.ColorPickerFrame:EnableKeyboard(false)
end

View File

@@ -0,0 +1,32 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
--Lua functions
local _G = _G
local hooksecurefunc = hooksecurefunc
local CreateFrame = CreateFrame
local DurabilityFrame = _G.DurabilityFrame
local function SetPosition(frame, _, parent)
if parent ~= _G.DurabilityFrameHolder then
frame:ClearAllPoints()
frame:SetPoint('CENTER', _G.DurabilityFrameHolder, 'CENTER')
end
end
function B:UpdateDurabilityScale()
DurabilityFrame:SetScale(E.db.general.durabilityScale or 1)
end
function B:PositionDurabilityFrame()
local DurabilityFrameHolder = CreateFrame('Frame', 'DurabilityFrameHolder', E.UIParent)
DurabilityFrameHolder:Size(DurabilityFrame:GetSize())
DurabilityFrameHolder:Point('TOPRIGHT', E.UIParent, 'TOPRIGHT', -135, -300)
E:CreateMover(DurabilityFrameHolder, 'DurabilityFrameMover', L["Durability Frame"], nil, nil, nil, nil, nil, 'all,general')
DurabilityFrame:SetFrameStrata('HIGH')
B:UpdateDurabilityScale()
hooksecurefunc(DurabilityFrame, 'SetPoint', SetPosition)
end

23
Modules/Blizzard/GM.lua Normal file
View File

@@ -0,0 +1,23 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local hooksecurefunc = hooksecurefunc
local function SetPosition(frame, _, anchor)
if anchor and (anchor == _G.UIParent) then
frame:ClearAllPoints()
frame:Point('TOPLEFT', _G.GMMover, 0, 0)
end
end
function B:PositionGMFrames()
local TicketStatusFrame = _G.TicketStatusFrame
TicketStatusFrame:ClearAllPoints()
TicketStatusFrame:Point('TOPLEFT', E.UIParent, 'TOPLEFT', 250, -5)
E:CreateMover(TicketStatusFrame, 'GMMover', L["GM Ticket Frame"])
--Blizzard repositions this frame now in UIParent_UpdateTopFramePositions
hooksecurefunc(TicketStatusFrame, 'SetPoint', SetPosition)
end

View File

@@ -0,0 +1,82 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local C_Garrison_GetLandingPageGarrisonType = C_Garrison.GetLandingPageGarrisonType
local ShowGarrisonLandingPage = ShowGarrisonLandingPage
local IsAddOnLoaded = IsAddOnLoaded
local HideUIPanel = HideUIPanel
local PlaySound = PlaySound
local StopSound = StopSound
local SOUNDKIT_UI_GARRISON_GARRISON_REPORT_OPEN = SOUNDKIT.UI_GARRISON_GARRISON_REPORT_OPEN
local SOUNDKIT_UI_GARRISON_GARRISON_REPORT_CLOSE = SOUNDKIT.UI_GARRISON_GARRISON_REPORT_CLOSE
local WAR_CAMPAIGN = WAR_CAMPAIGN
local GARRISON_LANDING_PAGE_TITLE = GARRISON_LANDING_PAGE_TITLE
local ORDER_HALL_LANDING_PAGE_TITLE = ORDER_HALL_LANDING_PAGE_TITLE
function B:GarrisonDropDown()
-- Right click Menu for Garrision Button all Credits to Foxlit (WarPlan)
if IsAddOnLoaded('WarPlan') then return; end
local function ShowLanding(page)
HideUIPanel(_G.GarrisonLandingPage)
ShowGarrisonLandingPage(page)
end
local function MaybeStopSound(sound)
return sound and StopSound(sound)
end
local landingChoices
_G.GarrisonLandingPageMinimapButton:RegisterForClicks('LeftButtonUp', 'RightButtonUp')
_G.GarrisonLandingPageMinimapButton:HookScript('PreClick', function(btn, b)
btn.landingVisiblePriorToClick = _G.GarrisonLandingPage and _G.GarrisonLandingPage:IsVisible() and _G.GarrisonLandingPage.garrTypeID
if b == 'RightButton' then
local openOK, openID = PlaySound(SOUNDKIT_UI_GARRISON_GARRISON_REPORT_OPEN)
local closeOK, closeID = PlaySound(SOUNDKIT_UI_GARRISON_GARRISON_REPORT_CLOSE)
btn.openSoundID = openOK and openID
btn.closeSoundID = closeOK and closeID
end
end)
_G.GarrisonLandingPageMinimapButton:HookScript('OnClick', function(btn, b)
if b == 'LeftButton' then
if _G.GarrisonLandingPage.garrTypeID ~= C_Garrison_GetLandingPageGarrisonType() then
ShowLanding(C_Garrison_GetLandingPageGarrisonType())
end
return
elseif b == 'RightButton' then
if (C_Garrison_GetLandingPageGarrisonType() or 0) > 3 then
if btn.landingVisiblePriorToClick then
ShowLanding(btn.landingVisiblePriorToClick)
else
HideUIPanel(_G.GarrisonLandingPage)
end
MaybeStopSound(btn.openSoundID)
MaybeStopSound(btn.closeSoundID)
if not landingChoices then
local function ShowLanding_(_, ...)
return ShowLanding(...)
end
landingChoices = {
{text = GARRISON_LANDING_PAGE_TITLE, func = ShowLanding_, arg1 = 2, notCheckable = true},
{text = ORDER_HALL_LANDING_PAGE_TITLE, func = ShowLanding_, arg1 = 3, notCheckable = true},
{text = WAR_CAMPAIGN, func = ShowLanding_, arg1 = C_Garrison_GetLandingPageGarrisonType(), notCheckable = true},
}
end
E.DataTexts:SetEasyMenuAnchor(E.DataTexts.EasyMenu, btn)
_G.EasyMenu(landingChoices, E.DataTexts.EasyMenu, nil, nil, nil, 'MENU')
elseif _G.GarrisonLandingPage.garrTypeID == 3 then
ShowLanding(2)
MaybeStopSound(btn.closeSoundID)
end
end
end)
_G.GarrisonLandingPageMinimapButton:HookScript('PostClick', function(btn)
btn.closeSoundID, btn.openSoundID = nil, nil
end)
end

45
Modules/Blizzard/Kill.lua Normal file
View File

@@ -0,0 +1,45 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local hooksecurefunc = hooksecurefunc
function B:KillBlizzard()
_G.Display_UIScaleSlider:Kill()
_G.Display_UseUIScale:Kill()
end
local function AcknowledgeTips()
for frame in _G.HelpTip.framePool:EnumerateActive() do
frame:Acknowledge()
end
end
function B:DisableHelpTip() -- auto complete helptips
if not E.global.general.disableTutorialButtons then return end
hooksecurefunc(_G.HelpTip, 'Show', AcknowledgeTips)
E:Delay(1, AcknowledgeTips)
end
-- NOTE: ActionBars heavily conflicts with NPE
local function ShutdownNPE(event)
local NPE = _G.NewPlayerExperience
if NPE then
if NPE:GetIsActive() then
NPE:Shutdown()
end
if event then
B:UnregisterEvent(event)
end
end
end
function B:DisableNPE() -- disable new player experience
if _G.NewPlayerExperience then
ShutdownNPE()
else
B:RegisterEvent('ADDON_LOADED', ShutdownNPE)
end
end

View File

@@ -0,0 +1,32 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local hooksecurefunc = hooksecurefunc
local CreateFrame = CreateFrame
local Holder
local function Reanchor(frame, _, anchor)
if anchor and (anchor ~= Holder) then
frame:ClearAllPoints()
frame:Point('TOP', Holder)
end
end
function B:Handle_LevelUpDisplay_BossBanner()
if not Holder then
Holder = CreateFrame('Frame', 'LevelUpBossBannerHolder', E.UIParent)
Holder:Size(200, 20)
Holder:Point('TOP', E.UIParent, 'TOP', -1, -120)
end
E:CreateMover(Holder, 'LevelUpBossBannerMover', L["Level Up Display / Boss Banner"])
_G.LevelUpDisplay:ClearAllPoints()
_G.LevelUpDisplay:Point('TOP', Holder)
hooksecurefunc(_G.LevelUpDisplay, 'SetPoint', Reanchor)
_G.BossBanner:ClearAllPoints()
_G.BossBanner:Point('TOP', Holder)
hooksecurefunc(_G.BossBanner, 'SetPoint', Reanchor)
end

View File

@@ -0,0 +1,17 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Script file='Blizzard.lua'/>
<Script file='ColorPicker.lua'/>
<Script file='Kill.lua'/>
<Script file='ObjectiveFrame.lua'/>
<Script file='Vehicle.lua'/>
<Script file='TimerTracker.lua'/>
<Script file='GM.lua'/>
<Script file='Durability.lua'/>
<Script file='CaptureBar.lua'/>
<Script file='AlertFrame.lua'/>
<Script file='AltPower.lua'/>
<Script file='TalkingHeadFrame.lua'/>
<Script file='LevelUpBossBanner.lua'/>
<Script file='WidgetsUI.lua'/>
<Script file='Garrison.lua'/>
</Ui>

View File

@@ -0,0 +1,96 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local min = min
local CreateFrame = CreateFrame
local GetScreenHeight = GetScreenHeight
local GetInstanceInfo = GetInstanceInfo
local GetScreenWidth = GetScreenWidth
local hooksecurefunc = hooksecurefunc
local RegisterStateDriver = RegisterStateDriver
local UnregisterStateDriver = UnregisterStateDriver
function B:SetObjectiveFrameHeight()
local top = _G.ObjectiveTrackerFrame:GetTop() or 0
local screenHeight = GetScreenHeight()
local gapFromTop = screenHeight - top
local maxHeight = screenHeight - gapFromTop
local objectiveFrameHeight = min(maxHeight, E.db.general.objectiveFrameHeight)
_G.ObjectiveTrackerFrame:Height(objectiveFrameHeight)
end
local function IsFramePositionedLeft(frame)
local x = frame:GetCenter()
local screenWidth = GetScreenWidth()
local positionedLeft = false
if x and x < (screenWidth / 2) then
positionedLeft = true
end
return positionedLeft
end
function B:SetObjectiveFrameAutoHide()
if not _G.ObjectiveTrackerFrame.AutoHider then return end --Kaliel's Tracker prevents B:MoveObjectiveFrame() from executing
if E.db.general.objectiveFrameAutoHide then
RegisterStateDriver(_G.ObjectiveTrackerFrame.AutoHider, 'objectiveHider', '[@arena1,exists][@arena2,exists][@arena3,exists][@arena4,exists][@arena5,exists][@boss1,exists][@boss2,exists][@boss3,exists][@boss4,exists] 1;0')
else
UnregisterStateDriver(_G.ObjectiveTrackerFrame.AutoHider, 'objectiveHider')
end
end
function B:MoveObjectiveFrame()
local ObjectiveFrameHolder = CreateFrame('Frame', 'ObjectiveFrameHolder', E.UIParent)
ObjectiveFrameHolder:Point('TOPRIGHT', E.UIParent, 'TOPRIGHT', -135, -300)
ObjectiveFrameHolder:Size(130, 22)
E:CreateMover(ObjectiveFrameHolder, 'ObjectiveFrameMover', L["Objective Frame"], nil, nil, nil, nil, nil, 'general,blizzUIImprovements')
ObjectiveFrameHolder:SetAllPoints(_G.ObjectiveFrameMover)
local ObjectiveTrackerFrame = _G.ObjectiveTrackerFrame
ObjectiveTrackerFrame:SetClampedToScreen(false)
ObjectiveTrackerFrame:ClearAllPoints()
ObjectiveTrackerFrame:Point('TOP', ObjectiveFrameHolder, 'TOP')
ObjectiveTrackerFrame:SetMovable(true)
ObjectiveTrackerFrame:SetUserPlaced(true) -- UIParent.lua line 3090 stops it from being moved <3
B:SetObjectiveFrameHeight()
local function RewardsFrame_SetPosition(block)
local rewardsFrame = _G.ObjectiveTrackerBonusRewardsFrame
rewardsFrame:ClearAllPoints()
if E.db.general.bonusObjectivePosition == 'RIGHT' or (E.db.general.bonusObjectivePosition == 'AUTO' and IsFramePositionedLeft(ObjectiveTrackerFrame)) then
rewardsFrame:Point('TOPLEFT', block, 'TOPRIGHT', -10, -4)
else
rewardsFrame:Point('TOPRIGHT', block, 'TOPLEFT', 10, -4)
end
end
hooksecurefunc('BonusObjectiveTracker_AnimateReward', RewardsFrame_SetPosition)
-- objectiveFrameAutoHide
ObjectiveTrackerFrame.AutoHider = CreateFrame('Frame', nil, ObjectiveTrackerFrame, 'SecureHandlerStateTemplate')
ObjectiveTrackerFrame.AutoHider:SetAttribute('_onstate-objectiveHider', 'if newstate == 1 then self:Hide() else self:Show() end')
ObjectiveTrackerFrame.AutoHider:SetScript('OnHide', function()
if not ObjectiveTrackerFrame.collapsed then
if E.db.general.objectiveFrameAutoHideInKeystone then
_G.ObjectiveTracker_Collapse()
else
local _, _, difficultyID = GetInstanceInfo()
if difficultyID and difficultyID ~= 8 then -- ignore hide in keystone runs
_G.ObjectiveTracker_Collapse()
end
end
end
end)
ObjectiveTrackerFrame.AutoHider:SetScript('OnShow', function()
if ObjectiveTrackerFrame.collapsed then
_G.ObjectiveTracker_Expand()
end
end)
self:SetObjectiveFrameAutoHide()
end

View File

@@ -0,0 +1,62 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local ipairs, tremove = ipairs, tremove
function B:ScaleTalkingHeadFrame()
local scale = E.db.general.talkingHeadFrameScale or 1
local TalkingHeadFrame = _G.TalkingHeadFrame
local width, height = TalkingHeadFrame:GetSize()
TalkingHeadFrame.mover:Size(width * scale, height * scale)
TalkingHeadFrame:SetScale(scale)
--Reset Model Camera
local model = TalkingHeadFrame.MainFrame.Model
if model.uiCameraID then
model:RefreshCamera()
_G.Model_ApplyUICamera(model, model.uiCameraID)
end
--Use this to prevent the frame from auto closing, so you have time to test things.
-- TalkingHeadFrame:UnregisterEvent('SOUNDKIT_FINISHED')
-- TalkingHeadFrame:UnregisterEvent('TALKINGHEAD_CLOSE')
-- TalkingHeadFrame:UnregisterEvent('LOADING_SCREEN_ENABLED')
end
local function InitializeTalkingHead()
local TalkingHeadFrame = _G.TalkingHeadFrame
--Prevent WoW from moving the frame around
_G.UIPARENT_MANAGED_FRAME_POSITIONS.TalkingHeadFrame = nil
--Set default position
TalkingHeadFrame:ClearAllPoints()
TalkingHeadFrame:Point('BOTTOM', E.UIParent, 'BOTTOM', -1, 373)
E:CreateMover(TalkingHeadFrame, 'TalkingHeadFrameMover', L["Talking Head Frame"], nil, nil, nil, nil, nil, 'skins')
--Iterate through all alert subsystems in order to find the one created for TalkingHeadFrame, and then remove it.
--We do this to prevent alerts from anchoring to this frame when it is shown.
for index, alertFrameSubSystem in ipairs(_G.AlertFrame.alertFrameSubSystems) do
if alertFrameSubSystem.anchorFrame and alertFrameSubSystem.anchorFrame == TalkingHeadFrame then
tremove(_G.AlertFrame.alertFrameSubSystems, index)
end
end
end
local function LoadTalkingHead()
if not _G.TalkingHeadFrame then
_G.TalkingHead_LoadUI()
end
InitializeTalkingHead()
B:ScaleTalkingHeadFrame()
end
function B:PositionTalkingHead()
if not E:IsAddOnEnabled('Blizzard_TalkingHeadUI') then return end
-- wait until first frame, then load talking head (if it isnt yet) and spawn the mover
E:Delay(1, LoadTalkingHead)
end

View File

@@ -0,0 +1,46 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local select, unpack, pairs = select, unpack, pairs
local CreateFrame = CreateFrame
local function SkinIt(bar)
for i=1, bar:GetNumRegions() do
local region = select(i, bar:GetRegions())
if region:IsObjectType('Texture') then
region:SetTexture()
elseif region:IsObjectType('FontString') then
region:FontTemplate(nil, 12, 'OUTLINE')
end
end
bar:SetStatusBarTexture(E.media.normTex)
if E.PixelMode then
bar:SetStatusBarColor(.31, .31, .31)
else
bar:SetStatusBarColor(unpack(E.media.bordercolor))
end
if not bar.backdrop then
bar.backdrop = CreateFrame('Frame', nil, bar, 'BackdropTemplate')
bar.backdrop:SetFrameLevel(0)
bar.backdrop:SetTemplate('Transparent')
bar.backdrop:SetOutside()
E:RegisterStatusBar(bar)
end
end
function B:START_TIMER()
for _, b in pairs(_G.TimerTracker.timerList) do
if b.bar and not b.bar.skinned then
SkinIt(b.bar)
b.bar.skinned = true
end
end
end
function B:SkinBlizzTimers()
B:RegisterEvent('START_TIMER')
B:START_TIMER()
end

View File

@@ -0,0 +1,56 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local hooksecurefunc = hooksecurefunc
local GetVehicleUIIndicator = GetVehicleUIIndicator
local GetVehicleUIIndicatorSeat = GetVehicleUIIndicatorSeat
local VehicleSeatIndicator_SetUpVehicle = VehicleSeatIndicator_SetUpVehicle
local function SetPosition(_,_,anchor)
if anchor == 'MinimapCluster' or anchor == _G.MinimapCluster then
_G.VehicleSeatIndicator:ClearAllPoints()
_G.VehicleSeatIndicator:Point('TOPLEFT', _G.VehicleSeatMover, 'TOPLEFT', 0, 0)
end
end
local function VehicleSetUp(vehicleID)
local size = E.db.general.vehicleSeatIndicatorSize
_G.VehicleSeatIndicator:Size(size)
local _, numSeatIndicators = GetVehicleUIIndicator(vehicleID)
if numSeatIndicators then
local fourth = size / 4
for i = 1, numSeatIndicators do
local button = _G['VehicleSeatIndicatorButton'..i]
button:Size(fourth)
local _, xOffset, yOffset = GetVehicleUIIndicatorSeat(vehicleID, i)
button:ClearAllPoints()
button:Point('CENTER', button:GetParent(), 'TOPLEFT', xOffset * size, -yOffset * size)
end
end
end
function B:UpdateVehicleFrame()
if _G.VehicleSeatIndicator.currSkin then
VehicleSeatIndicator_SetUpVehicle(_G.VehicleSeatIndicator.currSkin)
end
end
function B:PositionVehicleFrame()
local VehicleSeatIndicator = _G.VehicleSeatIndicator
if not VehicleSeatIndicator.PositionVehicleFrameHooked then
hooksecurefunc(VehicleSeatIndicator, 'SetPoint', SetPosition)
hooksecurefunc('VehicleSeatIndicator_SetUpVehicle', VehicleSetUp)
E:CreateMover(VehicleSeatIndicator, 'VehicleSeatMover', L["Vehicle Seat Frame"], nil, nil, nil, nil, nil, 'general,blizzUIImprovements')
VehicleSeatIndicator.PositionVehicleFrameHooked = true
end
VehicleSeatIndicator:Size(E.db.general.vehicleSeatIndicatorSize)
if VehicleSeatIndicator.currSkin then
VehicleSetUp(VehicleSeatIndicator.currSkin)
end
end

View File

@@ -0,0 +1,53 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local B = E:GetModule('Blizzard')
local _G = _G
local CreateFrame = CreateFrame
local hooksecurefunc = hooksecurefunc
local function topCenterPosition(self, _, b)
local holder = _G.TopCenterContainerHolder
if b and (b ~= holder) then
self:ClearAllPoints()
self:Point('CENTER', holder)
self:SetParent(holder)
end
end
local function belowMinimapPosition(self, _, b)
local holder = _G.BelowMinimapContainerHolder
if b and (b ~= holder) then
self:ClearAllPoints()
self:Point('CENTER', holder, 'CENTER')
self:SetParent(holder)
end
end
local function UIWidgets()
local topCenterContainer = _G.UIWidgetTopCenterContainerFrame
local belowMiniMapcontainer = _G.UIWidgetBelowMinimapContainerFrame
local topCenterHolder = CreateFrame('Frame', 'TopCenterContainerHolder', E.UIParent)
topCenterHolder:Point('TOP', E.UIParent, 'TOP', 0, -30)
topCenterHolder:Size(10, 58)
local belowMiniMapHolder = CreateFrame('Frame', 'BelowMinimapContainerHolder', E.UIParent)
belowMiniMapHolder:Point('TOPRIGHT', _G.Minimap, 'BOTTOMRIGHT', 0, -16)
belowMiniMapHolder:Size(128, 40)
E:CreateMover(topCenterHolder, 'TopCenterContainerMover', L["UIWidgetTopContainer"], nil, nil, nil,'ALL,SOLO')
E:CreateMover(belowMiniMapHolder, 'BelowMinimapContainerMover', L["UIWidgetBelowMinimapContainer"], nil, nil, nil,'ALL,SOLO')
topCenterContainer:ClearAllPoints()
topCenterContainer:Point('CENTER', topCenterHolder)
belowMiniMapcontainer:ClearAllPoints()
belowMiniMapcontainer:Point('CENTER', belowMiniMapHolder, 'CENTER')
hooksecurefunc(topCenterContainer, 'SetPoint', topCenterPosition)
hooksecurefunc(belowMiniMapcontainer, 'SetPoint', belowMinimapPosition)
end
function B:Handle_UIWidgets()
UIWidgets()
end

3315
Modules/Chat/Chat.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Script file='Chat.lua'/>
</Ui>

View File

@@ -0,0 +1,138 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DB = E:GetModule('DataBars')
local _G = _G
local floor = floor
local format = format
local InCombatLockdown = InCombatLockdown
local HasArtifactEquipped = HasArtifactEquipped
local SocketInventoryItem = SocketInventoryItem
local UIParentLoadAddOn = UIParentLoadAddOn
local ToggleFrame = ToggleFrame
local Item = Item
local C_ArtifactUI_IsEquippedArtifactDisabled = C_ArtifactUI.IsEquippedArtifactDisabled
local C_AzeriteItem_FindActiveAzeriteItem = C_AzeriteItem.FindActiveAzeriteItem
local C_AzeriteItem_GetAzeriteItemXPInfo = C_AzeriteItem.GetAzeriteItemXPInfo
local C_AzeriteItem_GetPowerLevel = C_AzeriteItem.GetPowerLevel
local C_AzeriteItem_IsAzeriteItemAtMaxLevel = C_AzeriteItem.IsAzeriteItemAtMaxLevel
local ARTIFACT_POWER = ARTIFACT_POWER
function DB:AzeriteBar_Update(event, unit)
if event == 'UNIT_INVENTORY_CHANGED' and unit ~= 'player' then return end
local bar = DB.StatusBars.Azerite
DB:SetVisibility(bar)
if not bar.db.enable or bar:ShouldHide() then return end
local item = C_AzeriteItem_FindActiveAzeriteItem()
local cur, max = C_AzeriteItem_GetAzeriteItemXPInfo(item)
local currentLevel = C_AzeriteItem_GetPowerLevel(item)
local color = DB.db.colors.azerite
bar:SetStatusBarColor(color.r, color.g, color.b, color.a)
bar:SetMinMaxValues(0, max)
bar:SetValue(cur)
local textFormat = DB.db.azerite.textFormat
if textFormat == 'NONE' then
bar.text:SetText('')
elseif textFormat == 'PERCENT' then
bar.text:SetFormattedText('%s%% [%s]', floor(cur / max * 100), currentLevel)
elseif textFormat == 'CURMAX' then
bar.text:SetFormattedText('%s - %s [%s]', E:ShortValue(cur), E:ShortValue(max), currentLevel)
elseif textFormat == 'CURPERC' then
bar.text:SetFormattedText('%s - %s%% [%s]', E:ShortValue(cur), floor(cur / max * 100), currentLevel)
elseif textFormat == 'CUR' then
bar.text:SetFormattedText('%s [%s]', E:ShortValue(cur), currentLevel)
elseif textFormat == 'REM' then
bar.text:SetFormattedText('%s [%s]', E:ShortValue(max - cur), currentLevel)
elseif textFormat == 'CURREM' then
bar.text:SetFormattedText('%s - %s [%s]', E:ShortValue(cur), E:ShortValue(max - cur), currentLevel)
elseif textFormat == 'CURPERCREM' then
bar.text:SetFormattedText('%s - %s%% (%s) [%s]', E:ShortValue(cur), floor(cur / max * 100), E:ShortValue(max - cur), currentLevel)
else
bar.text:SetFormattedText('[%s]', currentLevel)
end
end
do
local azeriteItem, currentLevel, curXP, maxXP
local function dataLoadedCancelFunc()
if _G.GameTooltip:IsForbidden() then return end
_G.GameTooltip:AddDoubleLine(ARTIFACT_POWER, azeriteItem:GetItemName()..' ('..currentLevel..')', nil, nil, nil, 0.90, 0.80, 0.50) -- Temp Locale
_G.GameTooltip:AddLine(' ')
_G.GameTooltip:AddDoubleLine(L["AP:"], format(' %d / %d (%d%%)', curXP, maxXP, curXP / maxXP * 100), 1, 1, 1)
_G.GameTooltip:AddDoubleLine(L["Remaining:"], format(' %d (%d%% - %d '..L["Bars"]..')', maxXP - curXP, (maxXP - curXP) / maxXP * 100, 10 * (maxXP - curXP) / maxXP), 1, 1, 1)
_G.GameTooltip:Show()
end
function DB:AzeriteBar_OnEnter()
local item = C_AzeriteItem_FindActiveAzeriteItem()
if item then
if DB.db.azerite.mouseover then
E:UIFrameFadeIn(self, 0.4, self:GetAlpha(), 1)
end
if not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:ClearLines()
_G.GameTooltip:SetOwner(self, 'ANCHOR_CURSOR')
end
curXP, maxXP = C_AzeriteItem_GetAzeriteItemXPInfo(item)
currentLevel = C_AzeriteItem_GetPowerLevel(item)
azeriteItem = Item:CreateFromItemLocation(item)
azeriteItem:ContinueWithCancelOnItemLoad(dataLoadedCancelFunc)
end
end
end
function DB:AzeriteBar_OnClick()
if InCombatLockdown() then return end
if HasArtifactEquipped() and not C_ArtifactUI_IsEquippedArtifactDisabled() then
SocketInventoryItem(_G.INVSLOT_MAINHAND)
elseif C_AzeriteItem_FindActiveAzeriteItem() then
UIParentLoadAddOn('Blizzard_AzeriteEssenceUI')
ToggleFrame(_G.AzeriteEssenceUI)
end
end
function DB:AzeriteBar_Toggle()
local bar = DB.StatusBars.Azerite
bar.db = DB.db.azerite
if bar.db.enable then
E:EnableMover(bar.holder.mover:GetName())
DB:RegisterEvent('AZERITE_ITEM_EXPERIENCE_CHANGED', 'AzeriteBar_Update')
DB:RegisterEvent('PLAYER_EQUIPMENT_CHANGED', 'AzeriteBar_Update')
DB:AzeriteBar_Update()
else
E:DisableMover(bar.holder.mover:GetName())
DB:UnregisterEvent('AZERITE_ITEM_EXPERIENCE_CHANGED')
DB:UnregisterEvent('PLAYER_EQUIPMENT_CHANGED')
end
end
function DB:AzeriteBar()
local Azerite = DB:CreateBar('ElvUI_AzeriteBar', 'Azerite', DB.AzeriteBar_Update, DB.AzeriteBar_OnEnter, DB.AzeriteBar_OnClick, {'TOPRIGHT', E.UIParent, 'TOPRIGHT', -3, -245})
DB:CreateBarBubbles(Azerite)
Azerite.ShouldHide = function()
local item = C_AzeriteItem_FindActiveAzeriteItem()
local equipped = item and item:IsEquipmentSlot()
return not equipped or (DB.db.azerite.hideAtMaxLevel and C_AzeriteItem_IsAzeriteItemAtMaxLevel())
end
E:CreateMover(Azerite.holder, 'AzeriteBarMover', L["Azerite Bar"], nil, nil, nil, nil, nil, 'databars,azerite')
DB:AzeriteBar_Toggle()
end

View File

@@ -0,0 +1,181 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DB = E:GetModule('DataBars')
local LSM = E.Libs.LSM
local _G = _G
local unpack, select = unpack, select
local pairs, ipairs = pairs, ipairs
local CreateFrame = CreateFrame
local GetInstanceInfo = GetInstanceInfo
local UnitAffectingCombat = UnitAffectingCombat
local C_PvP_IsWarModeActive = C_PvP.IsWarModeActive
function DB:OnLeave()
if self.db.mouseover then
E:UIFrameFadeOut(self, 1, self:GetAlpha(), 0)
end
if not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:Hide()
end
end
function DB:CreateBar(name, key, updateFunc, onEnter, onClick, points)
local holder = CreateFrame('Frame', name..'Holder', E.UIParent, 'BackdropTemplate')
holder:SetTemplate(DB.db.transparent and 'Transparent')
holder:SetScript('OnEnter', onEnter)
holder:SetScript('OnLeave', DB.OnLeave)
holder:SetScript('OnMouseDown', onClick)
if points then
holder:ClearAllPoints()
holder:Point(unpack(points))
end
local bar = CreateFrame('StatusBar', name, holder)
bar:SetStatusBarTexture(E.media.normTex)
bar:EnableMouse(false)
bar:SetInside()
bar:Hide()
bar.barTexture = bar:GetStatusBarTexture()
bar.text = bar:CreateFontString(nil, 'OVERLAY', nil, 7)
bar.text:FontTemplate()
bar.text:Point('CENTER')
bar.holder = holder
bar.Update = updateFunc
E.FrameLocks[holder] = true
DB.StatusBars[key] = bar
return bar
end
function DB:CreateBarBubbles(bar)
if bar.bubbles then return end
bar.bubbles = {}
for i = 1, 19 do
bar.bubbles[i] = bar:CreateTexture(nil, 'OVERLAY', nil, 0)
bar.bubbles[i]:SetColorTexture(0, 0, 0)
end
end
function DB:UpdateBarBubbles(bar)
if not bar.bubbles then return end
local width, height = bar.db.width, bar.db.height
local vertical = bar:GetOrientation() ~= 'HORIZONTAL'
local bubbleWidth, bubbleHeight = vertical and (width - 2) or 1, vertical and 1 or (height - 2)
local offset = (vertical and height or width) / 20
for i, bubble in ipairs(bar.bubbles) do
bubble:ClearAllPoints()
bubble:SetSize(bubbleWidth, bubbleHeight)
bubble:SetShown(bar.db.showBubbles)
if vertical then
bubble:Point('TOP', bar, 'BOTTOM', 0, offset * i)
else
bubble:Point('RIGHT', bar, 'LEFT', offset * i, 0)
end
end
end
function DB:UpdateAll()
local texture = DB.db.customTexture and LSM:Fetch('statusbar', DB.db.statusbar) or E.media.normTex
for _, bar in pairs(DB.StatusBars) do
bar.holder.db = bar.db
bar.holder:Size(bar.db.width, bar.db.height)
bar.holder:SetTemplate(DB.db.transparent and 'Transparent')
bar.holder:EnableMouse(not bar.db.clickThrough)
bar.text:FontTemplate(LSM:Fetch('font', bar.db.font), bar.db.fontSize, bar.db.fontOutline)
bar:SetStatusBarTexture(texture)
bar:SetReverseFill(bar.db.reverseFill)
if bar.db.enable then
bar.holder:SetAlpha(bar.db.mouseover and 0 or 1)
end
if bar.db.hideInVehicle then
E:RegisterObjectForVehicleLock(bar.holder, E.UIParent)
else
E:UnregisterObjectForVehicleLock(bar.holder)
end
if bar.db.orientation == 'AUTOMATIC' then
bar:SetOrientation(bar.db.height > bar.db.width and 'VERTICAL' or 'HORIZONTAL')
bar:SetRotatesTexture(bar.db.height > bar.db.width)
else
bar:SetOrientation(bar.db.orientation)
bar:SetRotatesTexture(bar.db.orientation ~= 'HORIZONTAL')
end
local orientation = bar:GetOrientation()
local rotatesTexture = bar:GetRotatesTexture()
local reverseFill = bar:GetReverseFill()
for i = 1, bar.holder:GetNumChildren() do
local child = select(i, bar.holder:GetChildren())
if child:IsObjectType('StatusBar') then
child:SetStatusBarTexture(texture)
child:SetOrientation(orientation)
child:SetRotatesTexture(rotatesTexture)
child:SetReverseFill(reverseFill)
end
end
DB:UpdateBarBubbles(bar)
end
DB:HandleVisibility()
end
function DB:SetVisibility(bar)
if bar.showBar ~= nil then
bar:SetShown(bar.showBar)
bar.holder:SetShown(bar.showBar)
elseif bar.db.enable then
local hideBar = (bar == DB.StatusBars.Threat or bar.db.hideInCombat) and UnitAffectingCombat('player')
or (bar.db.hideOutsidePvP and not (C_PvP_IsWarModeActive() or select(2, GetInstanceInfo()) == 'pvp'))
or (bar.ShouldHide and bar:ShouldHide())
bar:SetShown(not hideBar)
bar.holder:SetShown(not hideBar)
else
bar:SetShown(false)
bar.holder:SetShown(false)
end
end
function DB:HandleVisibility()
for _, bar in pairs(DB.StatusBars) do
DB:SetVisibility(bar)
end
end
function DB:Initialize()
DB.Initialized = true
DB.StatusBars = {}
DB.db = E.db.databars
DB:ExperienceBar()
DB:ReputationBar()
DB:HonorBar()
DB:AzeriteBar()
DB:ThreatBar()
DB:UpdateAll()
DB:RegisterEvent('PLAYER_LEVEL_UP', 'HandleVisibility')
DB:RegisterEvent('PLAYER_ENTERING_WORLD', 'HandleVisibility')
DB:RegisterEvent('PLAYER_REGEN_DISABLED', 'HandleVisibility')
DB:RegisterEvent('PLAYER_REGEN_ENABLED', 'HandleVisibility')
DB:RegisterEvent('PVP_TIMER_UPDATE', 'HandleVisibility')
end
E:RegisterModule(DB:GetName())

View File

@@ -0,0 +1,220 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DB = E:GetModule('DataBars')
local LSM = E.Libs.LSM
local _G = _G
local min, format = min, format
local CreateFrame = CreateFrame
local GetXPExhaustion = GetXPExhaustion
local IsXPUserDisabled = IsXPUserDisabled
local GetQuestLogRewardXP = GetQuestLogRewardXP
local IsPlayerAtEffectiveMaxLevel = IsPlayerAtEffectiveMaxLevel
local C_QuestLog_GetNumQuestLogEntries = C_QuestLog.GetNumQuestLogEntries
local C_QuestLog_GetQuestIDForLogIndex = C_QuestLog.GetQuestIDForLogIndex
local C_QuestLog_ReadyForTurnIn = C_QuestLog.ReadyForTurnIn
local C_QuestLog_GetInfo = C_QuestLog.GetInfo
local UnitXP, UnitXPMax = UnitXP, UnitXPMax
local CurrentXP, XPToLevel, RestedXP, PercentRested
local PercentXP, RemainXP, RemainTotal, RemainBars
local QuestLogXP = 0
function DB:ExperienceBar_CheckQuests(questID, completedOnly)
if not questID then return end
local isCompleted = C_QuestLog_ReadyForTurnIn(questID)
if not completedOnly or isCompleted then
QuestLogXP = QuestLogXP + GetQuestLogRewardXP(questID)
end
end
function DB:ExperienceBar_ShouldBeVisible()
return not IsPlayerAtEffectiveMaxLevel() and not IsXPUserDisabled()
end
function DB:ExperienceBar_Update()
local bar = DB.StatusBars.Experience
DB:SetVisibility(bar)
if not bar.db.enable or bar:ShouldHide() then return end
CurrentXP, XPToLevel, RestedXP = UnitXP('player'), UnitXPMax('player'), GetXPExhaustion()
if XPToLevel <= 0 then XPToLevel = 1 end
local remainXP = XPToLevel - CurrentXP
local remainPercent = remainXP / XPToLevel
RemainTotal, RemainBars = remainPercent * 100, remainPercent * 20
PercentXP, RemainXP = (CurrentXP / XPToLevel) * 100, E:ShortValue(remainXP)
local expColor, restedColor = DB.db.colors.experience, DB.db.colors.rested
bar:SetStatusBarColor(expColor.r, expColor.g, expColor.b, expColor.a)
bar.Rested:SetStatusBarColor(restedColor.r, restedColor.g, restedColor.b, restedColor.a)
local displayString, textFormat = '', DB.db.experience.textFormat
if not DB:ExperienceBar_ShouldBeVisible() then
bar:SetMinMaxValues(0, 1)
bar:SetValue(1)
if textFormat ~= 'NONE' then
displayString = IsXPUserDisabled() and L["Disabled"] or L["Max Level"]
end
else
bar:SetMinMaxValues(0, XPToLevel)
bar:SetValue(CurrentXP)
if textFormat == 'PERCENT' then
displayString = format('%.2f%%', PercentXP)
elseif textFormat == 'CURMAX' then
displayString = format('%s - %s', E:ShortValue(CurrentXP), E:ShortValue(XPToLevel))
elseif textFormat == 'CURPERC' then
displayString = format('%s - %.2f%%', E:ShortValue(CurrentXP), PercentXP)
elseif textFormat == 'CUR' then
displayString = format('%s', E:ShortValue(CurrentXP))
elseif textFormat == 'REM' then
displayString = format('%s', RemainXP)
elseif textFormat == 'CURREM' then
displayString = format('%s - %s', E:ShortValue(CurrentXP), RemainXP)
elseif textFormat == 'CURPERCREM' then
displayString = format('%s - %.2f%% (%s)', E:ShortValue(CurrentXP), PercentXP, RemainXP)
end
local isRested = RestedXP and RestedXP > 0
if isRested then
bar.Rested:SetMinMaxValues(0, XPToLevel)
bar.Rested:SetValue(min(CurrentXP + RestedXP, XPToLevel))
PercentRested = (RestedXP / XPToLevel) * 100
if textFormat == 'PERCENT' then
displayString = format('%s R:%.2f%%', displayString, PercentRested)
elseif textFormat == 'CURPERC' then
displayString = format('%s R:%s [%.2f%%]', displayString, E:ShortValue(RestedXP), PercentRested)
elseif textFormat ~= 'NONE' then
displayString = format('%s R:%s', displayString, E:ShortValue(RestedXP))
end
end
if bar.db.showLevel then
displayString = format('%s %s : %s', L['Level'], E.mylevel, displayString)
end
bar.Rested:SetShown(isRested)
end
bar.text:SetText(displayString)
end
function DB:ExperienceBar_QuestXP()
if not DB:ExperienceBar_ShouldBeVisible() then return end
local bar = DB.StatusBars.Experience
QuestLogXP = 0
for i = 1, C_QuestLog_GetNumQuestLogEntries() do
local info = C_QuestLog_GetInfo(i)
if info and (not info.isHidden) and (bar.db.questCurrentZoneOnly and info.isOnMap or not bar.db.questCurrentZoneOnly) then
DB:ExperienceBar_CheckQuests(C_QuestLog_GetQuestIDForLogIndex(i), bar.db.questCompletedOnly)
end
end
if QuestLogXP > 0 then
bar.Quest:SetMinMaxValues(0, XPToLevel)
bar.Quest:SetValue(min(CurrentXP + QuestLogXP, XPToLevel))
bar.Quest:SetStatusBarColor(DB.db.colors.quest.r, DB.db.colors.quest.g, DB.db.colors.quest.b, DB.db.colors.quest.a)
bar.Quest:Show()
else
bar.Quest:Hide()
end
end
function DB:ExperienceBar_OnEnter()
if self.db.mouseover then
E:UIFrameFadeIn(self, 0.4, self:GetAlpha(), 1)
end
if _G.GameTooltip:IsForbidden() or not DB:ExperienceBar_ShouldBeVisible() then return end
_G.GameTooltip:ClearLines()
_G.GameTooltip:SetOwner(self, 'ANCHOR_CURSOR')
_G.GameTooltip:AddLine(L["Experience"])
_G.GameTooltip:AddLine(' ')
_G.GameTooltip:AddDoubleLine(L["XP:"], format(' %d / %d (%.2f%%)', CurrentXP, XPToLevel, PercentXP), 1, 1, 1)
_G.GameTooltip:AddDoubleLine(L["Remaining:"], format(' %s (%.2f%% - %d '..L["Bars"]..')', RemainXP, RemainTotal, RemainBars), 1, 1, 1)
_G.GameTooltip:AddDoubleLine(L["Quest Log XP:"], QuestLogXP, 1, 1, 1)
if RestedXP and RestedXP > 0 then
_G.GameTooltip:AddDoubleLine(L["Rested:"], format('+%d (%.2f%%)', RestedXP, PercentRested), 1, 1, 1)
end
_G.GameTooltip:Show()
end
function DB:ExperienceBar_OnClick() end
function DB:ExperienceBar_Toggle()
local bar = DB.StatusBars.Experience
bar.db = DB.db.experience
if bar.db.enable then
E:EnableMover(bar.holder.mover:GetName())
else
E:DisableMover(bar.holder.mover:GetName())
end
if bar.db.enable and not bar:ShouldHide() then
DB:RegisterEvent('PLAYER_XP_UPDATE', 'ExperienceBar_Update')
DB:RegisterEvent('DISABLE_XP_GAIN', 'ExperienceBar_Update')
DB:RegisterEvent('ENABLE_XP_GAIN', 'ExperienceBar_Update')
DB:RegisterEvent('UPDATE_EXHAUSTION', 'ExperienceBar_Update')
DB:RegisterEvent('QUEST_LOG_UPDATE', 'ExperienceBar_QuestXP')
DB:RegisterEvent('ZONE_CHANGED', 'ExperienceBar_QuestXP')
DB:RegisterEvent('ZONE_CHANGED_NEW_AREA', 'ExperienceBar_QuestXP')
DB:UnregisterEvent('UPDATE_EXPANSION_LEVEL')
DB:ExperienceBar_Update()
else
DB:UnregisterEvent('PLAYER_XP_UPDATE')
DB:UnregisterEvent('DISABLE_XP_GAIN')
DB:UnregisterEvent('ENABLE_XP_GAIN')
DB:UnregisterEvent('UPDATE_EXHAUSTION')
DB:UnregisterEvent('QUEST_LOG_UPDATE')
DB:UnregisterEvent('ZONE_CHANGED')
DB:UnregisterEvent('ZONE_CHANGED_NEW_AREA')
DB:RegisterEvent('UPDATE_EXPANSION_LEVEL', 'ExperienceBar_Toggle')
end
end
function DB:ExperienceBar()
local Experience = DB:CreateBar('ElvUI_ExperienceBar', 'Experience', DB.ExperienceBar_Update, DB.ExperienceBar_OnEnter, DB.ExperienceBar_OnClick, {'BOTTOM', E.UIParent, 'BOTTOM', 0, 43})
Experience.barTexture:SetDrawLayer('ARTWORK', 4)
DB:CreateBarBubbles(Experience)
Experience.ShouldHide = function()
return DB.db.experience.hideAtMaxLevel and not DB:ExperienceBar_ShouldBeVisible()
end
local Rested = CreateFrame('StatusBar', 'ElvUI_ExperienceBar_Rested', Experience.holder)
Rested:SetStatusBarTexture(DB.db.customTexture and LSM:Fetch('statusbar', DB.db.statusbar) or E.media.normTex)
Rested:EnableMouse(false)
Rested:SetInside()
Rested:Hide()
Rested.barTexture = Rested:GetStatusBarTexture()
Rested.barTexture:SetDrawLayer('ARTWORK', 2)
Experience.Rested = Rested
local Quest = CreateFrame('StatusBar', 'ElvUI_ExperienceBar_Quest', Experience.holder)
Quest:SetStatusBarTexture(DB.db.customTexture and LSM:Fetch('statusbar', DB.db.statusbar) or E.media.normTex)
Quest:EnableMouse(false)
Quest:SetInside()
Quest:Hide()
Quest.barTexture = Quest:GetStatusBarTexture()
Quest.barTexture:SetDrawLayer('ARTWORK', 3)
Experience.Quest = Quest
E:CreateMover(Experience.holder, 'ExperienceBarMover', L["Experience Bar"], nil, nil, nil, nil, nil, 'databars,experience')
DB:ExperienceBar_Toggle()
end

111
Modules/DataBars/Honor.lua Normal file
View File

@@ -0,0 +1,111 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DB = E:GetModule('DataBars')
local _G = _G
local format = format
local UnitHonor = UnitHonor
local UnitHonorLevel = UnitHonorLevel
local IsPlayerAtEffectiveMaxLevel = IsPlayerAtEffectiveMaxLevel
local UnitHonorMax = UnitHonorMax
local TogglePVPUI = TogglePVPUI
local HONOR = HONOR
local CurrentHonor, MaxHonor, CurrentLevel, PercentHonor, RemainingHonor
function DB:HonorBar_Update(event, unit)
if event == 'PLAYER_FLAGS_CHANGED' and unit ~= 'player' then return end
local bar = DB.StatusBars.Honor
DB:SetVisibility(bar)
if not DB.db.honor.enable then return end
CurrentHonor, MaxHonor, CurrentLevel = UnitHonor('player'), UnitHonorMax('player'), UnitHonorLevel('player')
--Guard against division by zero, which appears to be an issue when zoning in/out of dungeons
if MaxHonor == 0 then MaxHonor = 1 end
PercentHonor, RemainingHonor = (CurrentHonor / MaxHonor) * 100, MaxHonor - CurrentHonor
local displayString, textFormat = '', DB.db.honor.textFormat
local color = DB.db.colors.honor
bar:SetMinMaxValues(0, MaxHonor)
bar:SetValue(CurrentHonor)
bar:SetStatusBarColor(color.r, color.g, color.b, color.a)
if textFormat == 'PERCENT' then
displayString = format('%d%% - [%s]', PercentHonor, CurrentLevel)
elseif textFormat == 'CURMAX' then
displayString = format('%s - %s - [%s]', E:ShortValue(CurrentHonor), E:ShortValue(MaxHonor), CurrentLevel)
elseif textFormat == 'CURPERC' then
displayString = format('%s - %d%% - [%s]', E:ShortValue(CurrentHonor), PercentHonor, CurrentLevel)
elseif textFormat == 'CUR' then
displayString = format('%s - [%s]', E:ShortValue(CurrentHonor), CurrentLevel)
elseif textFormat == 'REM' then
displayString = format('%s - [%s]', E:ShortValue(RemainingHonor), CurrentLevel)
elseif textFormat == 'CURREM' then
displayString = format('%s - %s - [%s]', E:ShortValue(CurrentHonor), E:ShortValue(RemainingHonor), CurrentLevel)
elseif textFormat == 'CURPERCREM' then
displayString = format('%s - %d%% (%s) - [%s]', E:ShortValue(CurrentHonor), CurrentHonor, E:ShortValue(RemainingHonor), CurrentLevel)
end
bar.text:SetText(displayString)
end
function DB:HonorBar_OnEnter()
if self.db.mouseover then
E:UIFrameFadeIn(self, .4, self:GetAlpha(), 1)
end
if _G.GameTooltip:IsForbidden() then return end
_G.GameTooltip:ClearLines()
_G.GameTooltip:SetOwner(self, 'ANCHOR_CURSOR')
_G.GameTooltip:AddLine(HONOR)
_G.GameTooltip:AddDoubleLine(L["Current Level:"], CurrentLevel, 1, 1, 1)
_G.GameTooltip:AddLine(' ')
_G.GameTooltip:AddDoubleLine(L["Honor XP:"], format(' %d / %d (%d%%)', CurrentHonor, MaxHonor, PercentHonor), 1, 1, 1)
_G.GameTooltip:AddDoubleLine(L["Honor Remaining:"], format(' %d (%d%% - %d '..L["Bars"]..')', RemainingHonor, (RemainingHonor) / MaxHonor * 100, 20 * (RemainingHonor) / MaxHonor), 1, 1, 1)
_G.GameTooltip:Show()
end
function DB:HonorBar_OnClick()
TogglePVPUI()
end
function DB:HonorBar_Toggle()
local bar = DB.StatusBars.Honor
bar.db = DB.db.honor
if bar.db.enable then
E:EnableMover(bar.holder.mover:GetName())
DB:RegisterEvent('HONOR_XP_UPDATE', 'HonorBar_Update')
DB:RegisterEvent('PLAYER_FLAGS_CHANGED', 'HonorBar_Update')
DB:HonorBar_Update()
else
E:DisableMover(bar.holder.mover:GetName())
DB:UnregisterEvent('HONOR_XP_UPDATE')
DB:UnregisterEvent('PLAYER_FLAGS_CHANGED')
end
end
function DB:HonorBar()
local Honor = DB:CreateBar('ElvUI_HonorBar', 'Honor', DB.HonorBar_Update, DB.HonorBar_OnEnter, DB.HonorBar_OnClick, {'TOPRIGHT', E.UIParent, 'TOPRIGHT', -3, -255})
DB:CreateBarBubbles(Honor)
Honor.ShouldHide = function()
return DB.db.honor.hideBelowMaxLevel and not IsPlayerAtEffectiveMaxLevel()
end
E:CreateMover(Honor.holder, 'HonorBarMover', L["Honor Bar"], nil, nil, nil, nil, nil, 'databars,honor')
DB:HonorBar_Toggle()
end

View File

@@ -0,0 +1,8 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Script file='DataBars.lua'/>
<Script file='Experience.lua'/>
<Script file='Reputation.lua'/>
<Script file='Honor.lua'/>
<Script file='Threat.lua'/>
<Script file='Azerite.lua'/>
</Ui>

View File

@@ -0,0 +1,154 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DB = E:GetModule('DataBars')
local _G = _G
local format = format
local IsPlayerAtEffectiveMaxLevel = IsPlayerAtEffectiveMaxLevel
local C_Reputation_GetFactionParagonInfo = C_Reputation.GetFactionParagonInfo
local C_Reputation_IsFactionParagon = C_Reputation.IsFactionParagon
local GetFriendshipReputation = GetFriendshipReputation
local GetWatchedFactionInfo = GetWatchedFactionInfo
local ToggleCharacter = ToggleCharacter
local REPUTATION = REPUTATION
local STANDING = STANDING
function DB:ReputationBar_Update()
local bar = DB.StatusBars.Reputation
DB:SetVisibility(bar)
if not bar.db.enable or bar:ShouldHide() then return end
local name, reaction, Min, Max, value, factionID = GetWatchedFactionInfo()
local displayString, textFormat = '', DB.db.reputation.textFormat
local isCapped, isFriend, friendText, standingLabel
local friendshipID = GetFriendshipReputation(factionID)
local color = DB.db.colors.useCustomFactionColors and DB.db.colors.factionColors[reaction] or _G.FACTION_BAR_COLORS[reaction]
if friendshipID then
local _, friendRep, _, _, _, _, friendTextLevel, friendThreshold, nextFriendThreshold = GetFriendshipReputation(factionID)
isFriend, reaction, friendText = true, 5, friendTextLevel
if nextFriendThreshold then
Min, Max, value = friendThreshold, nextFriendThreshold, friendRep;
else
Min, Max, value = 0, 1, 1
isCapped = true
end
elseif C_Reputation_IsFactionParagon(factionID) then
local currentValue, threshold, _, hasRewardPending = C_Reputation_GetFactionParagonInfo(factionID)
if currentValue and threshold then
Min, Max = 0, threshold
value = currentValue % threshold
if hasRewardPending then
value = value + threshold
end
end
elseif reaction == _G.MAX_REPUTATION_REACTION then
Min, Max, value = 0, 1, 1
isCapped = true
end
bar:SetMinMaxValues(Min, Max)
bar:SetValue(value)
bar:SetStatusBarColor(color.r, color.g, color.b)
standingLabel = _G['FACTION_STANDING_LABEL'..reaction]
--Prevent a division by zero
local maxMinDiff = Max - Min
if maxMinDiff == 0 then
maxMinDiff = 1
end
if isCapped and textFormat ~= 'NONE' then
-- show only name and standing on exalted
displayString = format('%s: [%s]', name, isFriend and friendText or standingLabel)
else
if textFormat == 'PERCENT' then
displayString = format('%s: %d%% [%s]', name, ((value - Min) / (maxMinDiff) * 100), isFriend and friendText or standingLabel)
elseif textFormat == 'CURMAX' then
displayString = format('%s: %s - %s [%s]', name, E:ShortValue(value - Min), E:ShortValue(Max - Min), isFriend and friendText or standingLabel)
elseif textFormat == 'CURPERC' then
displayString = format('%s: %s - %d%% [%s]', name, E:ShortValue(value - Min), ((value - Min) / (maxMinDiff) * 100), isFriend and friendText or standingLabel)
elseif textFormat == 'CUR' then
displayString = format('%s: %s [%s]', name, E:ShortValue(value - Min), isFriend and friendText or standingLabel)
elseif textFormat == 'REM' then
displayString = format('%s: %s [%s]', name, E:ShortValue((Max - Min) - (value-Min)), isFriend and friendText or standingLabel)
elseif textFormat == 'CURREM' then
displayString = format('%s: %s - %s [%s]', name, E:ShortValue(value - Min), E:ShortValue((Max - Min) - (value-Min)), isFriend and friendText or standingLabel)
elseif textFormat == 'CURPERCREM' then
displayString = format('%s: %s - %d%% (%s) [%s]', name, E:ShortValue(value - Min), ((value - Min) / (maxMinDiff) * 100), E:ShortValue((Max - Min) - (value-Min)), isFriend and friendText or standingLabel)
end
end
bar.text:SetText(displayString)
end
function DB:ReputationBar_OnEnter()
if self.db.mouseover then
E:UIFrameFadeIn(self, 0.4, self:GetAlpha(), 1)
end
local name, reaction, min, max, value, factionID = GetWatchedFactionInfo()
if factionID and C_Reputation_IsFactionParagon(factionID) then
local currentValue, threshold, _, hasRewardPending = C_Reputation_GetFactionParagonInfo(factionID)
if currentValue and threshold then
min, max = 0, threshold
value = currentValue % threshold
if hasRewardPending then
value = value + threshold
end
end
end
if name and not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:ClearLines()
_G.GameTooltip:SetOwner(self, 'ANCHOR_CURSOR')
_G.GameTooltip:AddLine(name)
_G.GameTooltip:AddLine(' ')
local friendID, friendTextLevel, _
if factionID then friendID, _, _, _, _, _, friendTextLevel = GetFriendshipReputation(factionID) end
_G.GameTooltip:AddDoubleLine(STANDING..':', (friendID and friendTextLevel) or _G['FACTION_STANDING_LABEL'..reaction], 1, 1, 1)
if reaction ~= _G.MAX_REPUTATION_REACTION or C_Reputation_IsFactionParagon(factionID) then
_G.GameTooltip:AddDoubleLine(REPUTATION..':', format('%d / %d (%d%%)', value - min, max - min, (value - min) / ((max - min == 0) and max or (max - min)) * 100), 1, 1, 1)
end
_G.GameTooltip:Show()
end
end
function DB:ReputationBar_OnClick()
ToggleCharacter('ReputationFrame')
end
function DB:ReputationBar_Toggle()
local bar = DB.StatusBars.Reputation
bar.db = DB.db.reputation
if bar.db.enable then
E:EnableMover(bar.holder.mover:GetName())
DB:RegisterEvent('UPDATE_FACTION', 'ReputationBar_Update')
DB:RegisterEvent('COMBAT_TEXT_UPDATE', 'ReputationBar_Update')
DB:ReputationBar_Update()
else
E:DisableMover(bar.holder.mover:GetName())
DB:UnregisterEvent('UPDATE_FACTION')
DB:UnregisterEvent('COMBAT_TEXT_UPDATE')
end
end
function DB:ReputationBar()
local Reputation = DB:CreateBar('ElvUI_ReputationBar', 'Reputation', DB.ReputationBar_Update, DB.ReputationBar_OnEnter, DB.ReputationBar_OnClick, {'TOPRIGHT', E.UIParent, 'TOPRIGHT', -3, -264})
DB:CreateBarBubbles(Reputation)
Reputation.ShouldHide = function()
return (DB.db.reputation.hideBelowMaxLevel and not IsPlayerAtEffectiveMaxLevel()) or not GetWatchedFactionInfo()
end
E:CreateMover(Reputation.holder, 'ReputationBarMover', L["Reputation Bar"], nil, nil, nil, nil, nil, 'databars,reputation')
DB:ReputationBar_Toggle()
end

140
Modules/DataBars/Threat.lua Normal file
View File

@@ -0,0 +1,140 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DB = E:GetModule('DataBars')
local pairs, select, wipe = pairs, select, wipe
local GetThreatStatusColor = GetThreatStatusColor
local IsInGroup, IsInRaid = IsInGroup, IsInRaid
local UnitClass = UnitClass
local UnitAffectingCombat = UnitAffectingCombat
local UnitDetailedThreatSituation = UnitDetailedThreatSituation
local UnitExists = UnitExists
local UnitIsPlayer = UnitIsPlayer
local UnitIsUnit = UnitIsUnit
local UnitName = UnitName
local UnitReaction = UnitReaction
local UNKNOWN = UNKNOWN
-- GLOBALS: ElvUF
function DB:ThreatBar_GetLargestThreatOnList(percent)
local largestValue, largestUnit = 0, nil
for unit, threatPercent in pairs(DB.StatusBars.Threat.list) do
if threatPercent > largestValue then
largestValue = threatPercent
largestUnit = unit
end
end
return (percent - largestValue), largestUnit
end
function DB:ThreatBar_GetColor(unit)
local unitReaction = UnitReaction(unit, 'player')
local _, unitClass = UnitClass(unit)
if (UnitIsPlayer(unit)) then
local class = E:ClassColor(unitClass)
if not class then return 194, 194, 194 end
return class.r*255, class.g*255, class.b*255
elseif (unitReaction) then
local reaction = ElvUF.colors.reaction[unitReaction]
return reaction[1]*255, reaction[2]*255, reaction[3]*255
else
return 194, 194, 194
end
end
function DB:ThreatBar_Update()
local bar = DB.StatusBars.Threat
local isInGroup, isInRaid, petExists = IsInGroup(), IsInRaid(), UnitExists('pet')
if UnitAffectingCombat('player') and (isInGroup or petExists) then
local _, status, percent = UnitDetailedThreatSituation('player', 'target')
local name = UnitName('target') or UNKNOWN
bar.showBar = true
if percent == 100 then
if petExists then
bar.list.pet = select(3, UnitDetailedThreatSituation('pet', 'target'))
end
if isInRaid then
for i = 1, 40 do
if UnitExists('raid'..i) and not UnitIsUnit('raid'..i, 'player') then
bar.list['raid'..i] = select(3, UnitDetailedThreatSituation('raid'..i, 'target'))
end
end
elseif isInGroup then
for i = 1, 4 do
if UnitExists('party'..i) then
bar.list['party'..i] = select(3, UnitDetailedThreatSituation('party'..i, 'target'))
end
end
end
local leadPercent, largestUnit = DB:ThreatBar_GetLargestThreatOnList(percent)
if leadPercent > 0 and largestUnit ~= nil then
local r, g, b = DB:ThreatBar_GetColor(largestUnit)
bar.text:SetFormattedText(L["ABOVE_THREAT_FORMAT"], name, percent, leadPercent, r, g, b, UnitName(largestUnit) or UNKNOWN)
if E.myrole == 'TANK' then
bar:SetStatusBarColor(0, 0.839, 0)
bar:SetValue(leadPercent)
else
bar:SetStatusBarColor(GetThreatStatusColor(status))
bar:SetValue(percent)
end
else
bar:SetStatusBarColor(GetThreatStatusColor(status))
bar.text:SetFormattedText('%s: %.0f%%', name, percent)
bar:SetValue(percent)
end
elseif percent then
bar:SetStatusBarColor(GetThreatStatusColor(status))
bar.text:SetFormattedText('%s: %.0f%%', name, percent)
bar:SetValue(percent)
else
bar.showBar = false
end
else
bar.showBar = false
end
DB:SetVisibility(bar) -- lower visibility because of using showBar variable
wipe(bar.list)
end
function DB:ThreatBar_Toggle()
local bar = DB.StatusBars.Threat
bar.db = DB.db.threat
if bar.db.enable then
E:EnableMover(bar.holder.mover:GetName())
DB:RegisterEvent('PLAYER_TARGET_CHANGED', 'ThreatBar_Update')
DB:RegisterEvent('UNIT_THREAT_LIST_UPDATE', 'ThreatBar_Update')
DB:RegisterEvent('GROUP_ROSTER_UPDATE', 'ThreatBar_Update')
DB:RegisterEvent('UNIT_FLAGS', 'ThreatBar_Update')
DB:RegisterEvent('UNIT_PET', 'ThreatBar_Update')
DB:ThreatBar_Update()
else
E:DisableMover(bar.holder.mover:GetName())
DB:UnregisterEvent('PLAYER_TARGET_CHANGED')
DB:UnregisterEvent('UNIT_THREAT_LIST_UPDATE')
DB:UnregisterEvent('GROUP_ROSTER_UPDATE')
DB:UnregisterEvent('UNIT_FLAGS')
DB:UnregisterEvent('UNIT_PET')
end
end
function DB:ThreatBar()
local Threat = DB:CreateBar('ElvUI_ThreatBar', 'Threat', DB.ThreatBar_Update, nil, nil, {'TOPRIGHT', E.UIParent, 'TOPRIGHT', -3, -245})
Threat:SetMinMaxValues(0, 100)
Threat.list = {}
E:CreateMover(Threat.holder, 'ThreatBarMover', L["Threat Bar"], nil, nil, nil, nil, nil, 'databars,threat')
DB:ThreatBar_Toggle()
end

View File

@@ -0,0 +1,30 @@
local E, L, V, P, G = unpack(select(2, ...))
local DT = E:GetModule('DataTexts')
local strjoin = strjoin
local UnitStat = UnitStat
local ITEM_MOD_AGILITY_SHORT = ITEM_MOD_AGILITY_SHORT
local LE_UNIT_STAT_AGILITY = LE_UNIT_STAT_AGILITY
local STAT_CATEGORY_ATTRIBUTES = STAT_CATEGORY_ATTRIBUTES
local displayString, lastPanel = ''
local function OnEvent(self)
if E.global.datatexts.settings.Agility.NoLabel then
self.text:SetFormattedText(displayString, UnitStat('player', LE_UNIT_STAT_AGILITY))
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Agility.Label ~= '' and E.global.datatexts.settings.Agility.Label or ITEM_MOD_AGILITY_SHORT..': ', UnitStat('player', LE_UNIT_STAT_AGILITY))
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Agility.NoLabel and '' or '%s', hex, '%d|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Agility', STAT_CATEGORY_ATTRIBUTES, {'UNIT_STATS', 'UNIT_AURA', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE'}, OnEvent, nil, nil, nil, nil, ITEM_MOD_AGILITY_SHORT, nil, ValueColorUpdate)

View File

@@ -0,0 +1,55 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local select = select
local format = format
local strjoin = strjoin
local UnitLevel = UnitLevel
local UnitArmor = UnitArmor
local PaperDollFrame_GetArmorReduction = PaperDollFrame_GetArmorReduction
local STAT_CATEGORY_ATTRIBUTES = STAT_CATEGORY_ATTRIBUTES
local ARMOR = ARMOR
local chanceString = '%.2f%%'
local displayString, lastPanel, effectiveArmor = ''
local function OnEvent(self)
effectiveArmor = select(2, UnitArmor('player'))
if E.global.datatexts.settings.Armor.NoLabel then
self.text:SetFormattedText(displayString, effectiveArmor)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Armor.Label ~= '' and E.global.datatexts.settings.Armor.Label or ARMOR..': ', effectiveArmor)
end
lastPanel = self
end
local function OnEnter()
DT.tooltip:ClearLines()
DT.tooltip:AddLine(L["Mitigation By Level: "])
DT.tooltip:AddLine(' ')
local playerlvl = E.mylevel + 3
for _ = 1, 4 do
local armorReduction = PaperDollFrame_GetArmorReduction(effectiveArmor, playerlvl)
DT.tooltip:AddDoubleLine(playerlvl,format(chanceString, armorReduction),1,1,1)
playerlvl = playerlvl - 1
end
local lv = UnitLevel('target')
if lv and lv > 0 and (lv > playerlvl + 3 or lv < playerlvl) then
local armorReduction = PaperDollFrame_GetArmorReduction(effectiveArmor, lv)
DT.tooltip:AddDoubleLine(lv, format(chanceString, armorReduction),1,1,1)
end
DT.tooltip:Show()
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Armor.NoLabel and '' or '%s', hex, '%d|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Armor', STAT_CATEGORY_ATTRIBUTES, {'UNIT_STATS', 'UNIT_RESISTANCES', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE'}, OnEvent, nil, nil, OnEnter, nil, ARMOR, nil, ValueColorUpdate)

View File

@@ -0,0 +1,117 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local format, strjoin, abs = format, strjoin, abs
local GetBlockChance = GetBlockChance
local GetBonusBarOffset = GetBonusBarOffset
local GetDodgeChance = GetDodgeChance
local GetInventoryItemID = GetInventoryItemID
local GetInventorySlotInfo = GetInventorySlotInfo
local GetItemInfo = GetItemInfo
local GetParryChance = GetParryChance
local UnitLevel = UnitLevel
local BOSS = BOSS
local BLOCK_CHANCE = BLOCK_CHANCE
local DODGE_CHANCE = DODGE_CHANCE
local MISS_CHANCE = MISS_CHANCE
local PARRY_CHANCE = PARRY_CHANCE
local STAT_CATEGORY_ENHANCEMENTS = STAT_CATEGORY_ENHANCEMENTS
local displayString, lastPanel, targetlv, playerlv
local basemisschance, leveldifference, dodge, parry, block, unhittable
local AVD_DECAY_RATE, chanceString = 1.5, '%.2f%%'
local function IsWearingShield()
local slotID = GetInventorySlotInfo('SecondaryHandSlot')
local itemID = GetInventoryItemID('player', slotID)
if itemID then
local _, _, _, _, _, _, _, _, itemEquipLoc = GetItemInfo(itemID)
return itemEquipLoc == 'INVTYPE_SHIELD'
end
end
local function OnEvent(self)
targetlv, playerlv = UnitLevel('target'), E.mylevel
basemisschance = E.myrace == 'NightElf' and 7 or 5
if targetlv == -1 then
leveldifference = 3
elseif targetlv > playerlv then
leveldifference = (targetlv - playerlv)
elseif targetlv < playerlv and targetlv > 0 then
leveldifference = (targetlv - playerlv)
else
leveldifference = 0
end
if leveldifference >= 0 then
dodge = (GetDodgeChance() - leveldifference * AVD_DECAY_RATE)
parry = (GetParryChance() - leveldifference * AVD_DECAY_RATE)
block = (GetBlockChance() - leveldifference * AVD_DECAY_RATE)
basemisschance = (basemisschance - leveldifference * AVD_DECAY_RATE)
else
dodge = (GetDodgeChance() + abs(leveldifference * AVD_DECAY_RATE))
parry = (GetParryChance() + abs(leveldifference * AVD_DECAY_RATE))
block = (GetBlockChance() + abs(leveldifference * AVD_DECAY_RATE))
basemisschance = (basemisschance+ abs(leveldifference * AVD_DECAY_RATE))
end
local unhittableMax = 100
local numAvoidances = 4
if dodge <= 0 then dodge = 0 end
if parry <= 0 then parry = 0 end
if block <= 0 then block = 0 end
if E.myclass == 'DRUID' and GetBonusBarOffset() == 3 then
parry = 0
numAvoidances = numAvoidances - 1
end
if not IsWearingShield() then
block = 0
numAvoidances = numAvoidances - 1
end
unhittableMax = unhittableMax + ((AVD_DECAY_RATE * leveldifference) * numAvoidances)
local avoided = (dodge+parry+basemisschance) --First roll on hit table determining if the hit missed
local blocked = (100 - avoided)*block/100 --If the hit landed then the second roll determines if the his was blocked
local avoidance = (avoided+blocked)
unhittable = avoidance - unhittableMax
if E.global.datatexts.settings.Avoidance.NoLabel then
self.text:SetFormattedText(displayString, avoidance)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Avoidance.Label ~= '' and E.global.datatexts.settings.Avoidance.Label or L["AVD: "], avoidance)
end
--print(unhittableMax) -- should report 102.4 for a level differance of +3 for shield classes, 101.2 for druids, 101.8 for monks and dks
lastPanel = self
end
local function OnEnter()
DT.tooltip:ClearLines()
local rightString = targetlv > 1 and strjoin('', ' (', L["lvl"], ' ', targetlv, ')') or targetlv == -1 and strjoin('', ' (', BOSS, ')') or strjoin('', ' (', L["lvl"], ' ', playerlv, ')')
DT.tooltip:AddDoubleLine(L["Avoidance Breakdown"], rightString)
DT.tooltip:AddLine(' ')
DT.tooltip:AddDoubleLine(DODGE_CHANCE, format(chanceString, dodge), 1, 1, 1)
DT.tooltip:AddDoubleLine(PARRY_CHANCE, format(chanceString, parry), 1, 1, 1)
DT.tooltip:AddDoubleLine(BLOCK_CHANCE, format(chanceString, block), 1, 1, 1)
DT.tooltip:AddDoubleLine(MISS_CHANCE, format(chanceString, basemisschance), 1, 1, 1)
DT.tooltip:AddLine(' ')
DT.tooltip:AddDoubleLine(L["Unhittable:"], (unhittable > 0 and '+' or '')..format(chanceString, unhittable), 1, 1, 1, (unhittable < 0 and 1 or 0), (unhittable > 0 and 1 or 0), 0)
DT.tooltip:Show()
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Avoidance.NoLabel and '' or '%s', hex, '%.'..E.global.datatexts.settings.Avoidance.decimalLength..'f%%|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Avoidance', STAT_CATEGORY_ENHANCEMENTS, {'UNIT_TARGET', 'UNIT_STATS', 'UNIT_AURA', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE', 'PLAYER_EQUIPMENT_CHANGED'}, OnEvent, nil, nil, OnEnter, nil, L["Avoidance Breakdown"], nil, ValueColorUpdate)

View File

@@ -0,0 +1,98 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local strjoin = strjoin
local format = format
local GetContainerNumFreeSlots = GetContainerNumFreeSlots
local GetContainerNumSlots = GetContainerNumSlots
local ToggleAllBags = ToggleAllBags
local CURRENCY = CURRENCY
local NUM_BAG_SLOTS = NUM_BAG_SLOTS
local MAX_WATCHED_TOKENS = MAX_WATCHED_TOKENS
local GetBagName = GetBagName
local GetInventoryItemQuality = GetInventoryItemQuality
local GetItemQualityColor = GetItemQualityColor
local GetInventoryItemTexture = GetInventoryItemTexture
local C_CurrencyInfo_GetBackpackCurrencyInfo = C_CurrencyInfo.GetBackpackCurrencyInfo
local displayString, lastPanel = ''
local iconString = '|T%s:14:14:0:0:64:64:4:60:4:60|t %s'
local bagIcon = 'Interface/Buttons/Button-Backpack-Up'
local function OnEvent(self)
lastPanel = self
local free, total, used = 0, 0
for i = 0, NUM_BAG_SLOTS do
free, total = free + GetContainerNumFreeSlots(i), total + GetContainerNumSlots(i)
end
used = total - free
local textFormat = E.global.datatexts.settings.Bags.textFormat
if textFormat == "FREE" then
self.text:SetFormattedText(displayString, L["Bags"]..": ", free)
elseif textFormat == "USED" then
self.text:SetFormattedText(displayString, L["Bags"]..": ", used)
elseif textFormat == "FREE_TOTAL" then
self.text:SetFormattedText(displayString, L["Bags"]..": ", free, total)
else
self.text:SetFormattedText(displayString, L["Bags"]..": ", used, total)
end
end
local function OnClick()
ToggleAllBags()
end
local function OnEnter()
DT.tooltip:ClearLines()
for i = 0, NUM_BAG_SLOTS do
local bagName = GetBagName(i)
if bagName then
local numSlots = GetContainerNumSlots(i)
local freeSlots = GetContainerNumFreeSlots(i)
local usedSlots, sumNum = numSlots - freeSlots, 19 + i
local r2, g2, b2 = E:ColorGradient(usedSlots / numSlots, .1,1,.1, 1,1,.1, 1,.1,.1)
local r, g, b, icon
if i > 0 then
r, g, b = GetItemQualityColor(GetInventoryItemQuality('player', sumNum) or 1)
icon = GetInventoryItemTexture('player', sumNum)
end
DT.tooltip:AddDoubleLine(format(iconString, icon or bagIcon, bagName), format('%d / %d', usedSlots, numSlots), r or 1, g or 1, b or 1, r2, g2, b2)
end
end
for i = 1, MAX_WATCHED_TOKENS do
local info = C_CurrencyInfo_GetBackpackCurrencyInfo(i)
if info then
if i == 1 then
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(CURRENCY)
DT.tooltip:AddLine(' ')
end
if info.quantity then
DT.tooltip:AddDoubleLine(format(iconString, info.iconFileID, info.name), info.quantity, 1, 1, 1, 1, 1, 1)
end
end
end
DT.tooltip:Show()
end
local function ValueColorUpdate(hex)
local textFormat = E.global.datatexts.settings.Bags.textFormat
if textFormat == "FREE" or textFormat == "USED" then
displayString = strjoin('', '%s', hex, '%d|r')
else
displayString = strjoin('', '%s', hex, '%d/%d|r')
end
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Bags', nil, {'BAG_UPDATE'}, OnEvent, nil, OnClick, OnEnter, nil, L["Bags"], nil, ValueColorUpdate)

View File

@@ -0,0 +1,118 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local sort = sort
local ipairs = ipairs
local strlen = strlen
local strjoin = strjoin
local C_PvP_GetMatchPVPStatColumns = C_PvP.GetMatchPVPStatColumns
local GetNumBattlefieldScores = GetNumBattlefieldScores
local GetBattlefieldStatData = GetBattlefieldStatData
local GetBattlefieldScore = GetBattlefieldScore
local BATTLEGROUND = BATTLEGROUND
local displayString = ''
local holder = {
LEFT = { data = {}, _G.KILLS, _G.KILLING_BLOWS, _G.DEATHS },
RIGHT = { data = {}, _G.DAMAGE, _G.SHOW_COMBAT_HEALING, _G.HONOR }
}
DT.BattleStats = holder
function DT:UpdateBattlePanel(which)
local info = which and holder[which]
local panel = info and info.panel
if not panel then return end
for i, name in ipairs(info) do
local dt = panel[i]
if dt and dt.text then
dt.text:SetFormattedText(displayString, name, info.data[i] or 0)
end
end
end
local myIndex
local LEFT = holder.LEFT.data
local RIGHT = holder.RIGHT.data
function DT:UPDATE_BATTLEFIELD_SCORE()
myIndex = nil
for i = 1, GetNumBattlefieldScores() do
local name, kb, hks, deaths, honor, _, _, _, _, dmg, heals = GetBattlefieldScore(i)
if name == E.myname then
LEFT[1], LEFT[2], LEFT[3] = E:ShortValue(hks), E:ShortValue(kb), E:ShortValue(deaths)
RIGHT[1], RIGHT[2], RIGHT[3] = E:ShortValue(dmg), E:ShortValue(heals), E:ShortValue(honor)
myIndex = i
break
end
end
if myIndex then
DT:UpdateBattlePanel('LEFT')
DT:UpdateBattlePanel('RIGHT')
end
end
local function columnSort(lhs,rhs)
return lhs.orderIndex < rhs.orderIndex
end
function DT:HoverBattleStats() -- OnEnter
DT.tooltip:ClearLines()
if myIndex and DT.ShowingBattleStats == 'pvp' then
local columns = C_PvP_GetMatchPVPStatColumns()
if columns then
sort(columns, columnSort)
local firstLine
local classColor = E:ClassColor(E.myclass)
DT.tooltip:AddDoubleLine(BATTLEGROUND, E.MapInfo.name, 1,1,1, classColor.r, classColor.g, classColor.b)
-- Add extra statistics to watch based on what BG you are in.
for i, stat in ipairs(columns) do
local name = stat.name
if name and strlen(name) > 0 then
if not firstLine then
DT.tooltip:AddLine(' ')
firstLine = true
end
DT.tooltip:AddDoubleLine(name, GetBattlefieldStatData(myIndex, i), 1,1,1)
end
end
DT.tooltip:Show()
end
end
end
function DT:ToggleBattleStats()
if DT.ForceHideBGStats then
DT.ForceHideBGStats = nil
E:Print(L["Battleground datatexts will now show again if you are inside a battleground."])
else
DT.ForceHideBGStats = true
E:Print(L["Battleground datatexts temporarily hidden, to show type /bgstats"])
end
DT:UpdatePanelInfo('LeftChatDataPanel')
DT:UpdatePanelInfo('RightChatDataPanel')
if DT.ShowingBattleStats then
DT:UpdateBattlePanel('LEFT')
DT:UpdateBattlePanel('RIGHT')
end
end
local function ValueColorUpdate(hex)
displayString = strjoin('', '%s: ', hex, '%s|r')
if DT.ShowingBattleStats then
DT:UpdateBattlePanel('LEFT')
DT:UpdateBattlePanel('RIGHT')
end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true

View File

@@ -0,0 +1,172 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local strjoin = strjoin
local GetLFGRandomDungeonInfo = GetLFGRandomDungeonInfo
local GetLFGRoleShortageRewards = GetLFGRoleShortageRewards
local GetNumRandomDungeons = GetNumRandomDungeons
local GetNumRFDungeons = GetNumRFDungeons
local GetRFDungeonInfo = GetRFDungeonInfo
local PVEFrame_ToggleFrame = PVEFrame_ToggleFrame
local LFG_ROLE_NUM_SHORTAGE_TYPES = LFG_ROLE_NUM_SHORTAGE_TYPES
local BATTLEGROUND_HOLIDAY = BATTLEGROUND_HOLIDAY
local DUNGEONS = DUNGEONS
local RAID_FINDER = RAID_FINDER
local TANK_ICON = E:TextureString(E.Media.Textures.Tank, ':14:14')
local HEALER_ICON = E:TextureString(E.Media.Textures.Healer, ':14:14')
local DPS_ICON = E:TextureString(E.Media.Textures.DPS, ':14:14')
local enteredFrame, lastPanel = false
local displayString = ''
local function MakeIconString(tank, healer, damage)
local str = ''
if tank then
str = str..TANK_ICON
end
if healer then
str = str..HEALER_ICON
end
if damage then
str = str..DPS_ICON
end
return str
end
local function OnEvent(self)
local tankReward = false
local healerReward = false
local dpsReward = false
local unavailable = true
--Dungeons
for i = 1, GetNumRandomDungeons() do
local id = GetLFGRandomDungeonInfo(i)
for x = 1, LFG_ROLE_NUM_SHORTAGE_TYPES do
local eligible, forTank, forHealer, forDamage, itemCount = GetLFGRoleShortageRewards(id, x)
if eligible and forTank and itemCount > 0 then tankReward = true; unavailable = false; end
if eligible and forHealer and itemCount > 0 then healerReward = true; unavailable = false; end
if eligible and forDamage and itemCount > 0 then dpsReward = true; unavailable = false; end
end
end
--LFR
for i = 1, GetNumRFDungeons() do
local id = GetRFDungeonInfo(i)
for x = 1, LFG_ROLE_NUM_SHORTAGE_TYPES do
local eligible, forTank, forHealer, forDamage, itemCount = GetLFGRoleShortageRewards(id, x)
if eligible and forTank and itemCount > 0 then tankReward = true; unavailable = false; end
if eligible and forHealer and itemCount > 0 then healerReward = true; unavailable = false; end
if eligible and forDamage and itemCount > 0 then dpsReward = true; unavailable = false; end
end
end
if E.global.datatexts.settings.CallToArms.NoLabel then
self.text:SetFormattedText(displayString, unavailable and 'N/A' or MakeIconString(tankReward, healerReward, dpsReward))
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.CallToArms.Label ~= '' and E.global.datatexts.settings.CallToArms.Label or BATTLEGROUND_HOLIDAY..": ", unavailable and 'N/A' or MakeIconString(tankReward, healerReward, dpsReward))
end
lastPanel = self
end
local function OnClick()
PVEFrame_ToggleFrame('GroupFinderFrame', _G.LFDParentFrame)
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.CallToArms.NoLabel and '' or '%s', hex, '%s|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
local function OnEnter()
DT.tooltip:ClearLines()
enteredFrame = true
local numCTA = 0
local addTooltipHeader, addTooltipSeparator = true
for i = 1, GetNumRandomDungeons() do
local id, name = GetLFGRandomDungeonInfo(i)
local tankReward = false
local healerReward = false
local dpsReward = false
local unavailable = true
for x = 1, LFG_ROLE_NUM_SHORTAGE_TYPES do
local eligible, forTank, forHealer, forDamage, itemCount = GetLFGRoleShortageRewards(id, x)
if eligible then unavailable = false end
if eligible and forTank and itemCount > 0 then tankReward = true end
if eligible and forHealer and itemCount > 0 then healerReward = true end
if eligible and forDamage and itemCount > 0 then dpsReward = true end
end
if not unavailable then
local rolesString = MakeIconString(tankReward, healerReward, dpsReward)
if rolesString ~= '' then
if addTooltipHeader then
DT.tooltip:AddLine(DUNGEONS)
addTooltipHeader = false
addTooltipSeparator = true
end
DT.tooltip:AddDoubleLine(name..':', rolesString, 1, 1, 1)
end
if tankReward or healerReward or dpsReward then numCTA = numCTA + 1 end
end
end
addTooltipHeader = true
for i = 1, GetNumRFDungeons() do
local id, name = GetRFDungeonInfo(i)
local tankReward = false
local healerReward = false
local dpsReward = false
local unavailable = true
for x = 1, LFG_ROLE_NUM_SHORTAGE_TYPES do
local eligible, forTank, forHealer, forDamage, itemCount = GetLFGRoleShortageRewards(id, x)
if eligible then unavailable = false end
if eligible and forTank and itemCount > 0 then tankReward = true end
if eligible and forHealer and itemCount > 0 then healerReward = true end
if eligible and forDamage and itemCount > 0 then dpsReward = true end
end
if not unavailable then
local rolesString = MakeIconString(tankReward, healerReward, dpsReward)
if rolesString ~= '' then
if addTooltipHeader then
if addTooltipSeparator then DT.tooltip:AddLine(' ') end
DT.tooltip:AddLine(RAID_FINDER)
addTooltipHeader = false
end
DT.tooltip:AddDoubleLine(name..':', rolesString, 1, 1, 1)
end
if tankReward or healerReward or dpsReward then numCTA = numCTA + 1 end
end
end
DT.tooltip:Show()
end
local updateInterval = 10
local function Update(self, elapsed)
if self.timeSinceUpdate and self.timeSinceUpdate > updateInterval then
OnEvent(self)
if enteredFrame then
OnEnter(self)
end
self.timeSinceUpdate = 0
else
self.timeSinceUpdate = (self.timeSinceUpdate or 0) + elapsed
end
end
local function OnLeave()
enteredFrame = false
end
DT:RegisterDatatext('CallToArms', nil, {"LFG_UPDATE_RANDOM_INFO"}, OnEvent, Update, OnClick, OnEnter, OnLeave, BATTLEGROUND_HOLIDAY, nil, ValueColorUpdate)

View File

@@ -0,0 +1,55 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local floor, format, strjoin = floor, format, strjoin
local GetInstanceInfo = GetInstanceInfo
local GetTime = GetTime
local displayString, lastPanel = ''
local timerText, timer, startTime = L["Combat"], 0, 0
local function UpdateText()
return format(E.global.datatexts.settings.Combat.TimeFull and '%02d:%02d:%02d' or '%02d:%02d', floor(timer/60), timer % 60, (timer - floor(timer)) * 100)
end
local function OnUpdate(self)
timer = GetTime() - startTime
self.text:SetFormattedText(displayString, timerText, UpdateText())
end
local function DelayOnUpdate(self, elapsed)
startTime = startTime - elapsed
if startTime <= 0 then
timer, startTime = 0, GetTime()
self:SetScript('OnUpdate', OnUpdate)
end
end
local function OnEvent(self, event, _, timeSeconds)
local _, instanceType = GetInstanceInfo()
local isInArena = instanceType == 'arena'
if event == 'START_TIMER' and isInArena then
timerText, timer, startTime = L["Arena"], 0, timeSeconds
self.text:SetFormattedText(displayString, timerText, '00:00:00')
self:SetScript('OnUpdate', DelayOnUpdate)
elseif event == 'PLAYER_REGEN_ENABLED' and not isInArena then
self:SetScript('OnUpdate', nil)
elseif event == 'PLAYER_REGEN_DISABLED' and not isInArena then
timerText, timer, startTime = L["Combat"], 0, GetTime()
self:SetScript('OnUpdate', OnUpdate)
elseif not self.text:GetText() then
self.text:SetFormattedText(displayString, timerText, 'N/A')
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', '%s: ', hex, '%s|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Combat', nil, {'START_TIMER', 'PLAYER_REGEN_DISABLED', 'PLAYER_REGEN_ENABLED'}, OnEvent, nil, nil, nil, nil, L["Combat/Arena Time"], nil, ValueColorUpdate)

View File

@@ -0,0 +1,59 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local pairs, strjoin = pairs, strjoin
local IsShiftKeyDown = IsShiftKeyDown
local InCombatLockdown = InCombatLockdown
local ReloadUI = ReloadUI
local displayString = ''
local configText = 'ElvUI'
local reloadText = RELOADUI
local lastPanel
local function OnEvent(self)
lastPanel = self
self.text:SetFormattedText(displayString, E.global.datatexts.settings.ElvUI.Label ~= '' and E.global.datatexts.settings.ElvUI.Label or configText)
end
local function OnEnter()
DT.tooltip:ClearLines()
DT.tooltip:AddDoubleLine(L["Left Click:"], L["Toggle Configuration"], 1, 1, 1)
DT.tooltip:AddDoubleLine(L["Hold Shift + Right Click:"], reloadText, 1, 1, 1)
if E.Libs.EP.registeredPrefix then
DT.tooltip:AddLine(' ')
DT.tooltip:AddDoubleLine('Plugins:', 'Version:')
for _, plugin in pairs(E.Libs.EP.plugins) do
if not plugin.isLib then
local r, g, b = E:HexToRGB(plugin.old and 'ff3333' or '33ff33')
DT.tooltip:AddDoubleLine(plugin.title, plugin.version, 1, 1, 1, r/255, g/255, b/255)
end
end
end
DT.tooltip:Show()
end
local function OnClick(_, button)
if InCombatLockdown() then _G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT) return end
if button == 'LeftButton' then
E:ToggleOptionsUI()
elseif button == 'RightButton' and IsShiftKeyDown() then
ReloadUI()
end
end
local function ValueColorUpdate(hex)
displayString = strjoin('', hex, '%s|r')
if lastPanel then
OnEvent(lastPanel, 'ELVUI_COLOR_UPDATE')
end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('ElvUI', nil, nil, OnEvent, nil, OnClick, OnEnter, nil, L['ElvUI Config'], nil, ValueColorUpdate)

View File

@@ -0,0 +1,43 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local strjoin = strjoin
local InCombatLockdown = InCombatLockdown
local displayString = ''
local inRestrictedArea = false
local mapInfo = E.MapInfo
local function Update(self, elapsed)
if inRestrictedArea or not mapInfo.coordsWatching then return end
self.timeSinceUpdate = (self.timeSinceUpdate or 0) + elapsed
if self.timeSinceUpdate > 0.1 then
self.text:SetFormattedText(displayString, mapInfo.xText or 0, mapInfo.yText or 0)
self.timeSinceUpdate = 0
end
end
local function OnEvent(self)
if mapInfo.x and mapInfo.y then
inRestrictedArea = false
self.text:SetFormattedText(displayString, mapInfo.xText or 0, mapInfo.yText or 0)
else
inRestrictedArea = true
self.text:SetText('N/A')
end
end
local function Click()
if InCombatLockdown() then _G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT) return end
_G.ToggleFrame(_G.WorldMapFrame)
end
local function ValueColorUpdate(hex)
displayString = strjoin('', hex, '%.2f|r', ' | ', hex, '%.2f|r')
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Coords', nil, {'LOADING_SCREEN_DISABLED', 'ZONE_CHANGED', 'ZONE_CHANGED_INDOORS', 'ZONE_CHANGED_NEW_AREA'}, OnEvent, Update, Click, nil, nil, L["Coords"], mapInfo, ValueColorUpdate)

View File

@@ -0,0 +1,96 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local min = min
local format, strjoin = format, strjoin
local BreakUpLargeNumbers = BreakUpLargeNumbers
local GetCombatRating = GetCombatRating
local GetCombatRatingBonus = GetCombatRatingBonus
local GetCritChance = GetCritChance
local GetRangedCritChance = GetRangedCritChance
local GetSpellCritChance = GetSpellCritChance
local GetCritChanceProvidesParryEffect = GetCritChanceProvidesParryEffect
local GetCombatRatingBonusForCombatRatingValue = GetCombatRatingBonusForCombatRatingValue
local CR_CRIT_MELEE = CR_CRIT_MELEE
local CR_CRIT_RANGED = CR_CRIT_RANGED
local CR_CRIT_SPELL = CR_CRIT_SPELL
local CR_PARRY = CR_PARRY
local MAX_SPELL_SCHOOLS = MAX_SPELL_SCHOOLS
local CRIT_ABBR = CRIT_ABBR
local FONT_COLOR_CODE_CLOSE = FONT_COLOR_CODE_CLOSE
local HIGHLIGHT_FONT_COLOR_CODE = HIGHLIGHT_FONT_COLOR_CODE
local MELEE_CRIT_CHANCE = MELEE_CRIT_CHANCE
local PAPERDOLLFRAME_TOOLTIP_FORMAT = PAPERDOLLFRAME_TOOLTIP_FORMAT
local RANGED_CRIT_CHANCE = RANGED_CRIT_CHANCE
local SPELL_CRIT_CHANCE = SPELL_CRIT_CHANCE
local STAT_CATEGORY_ENHANCEMENTS = STAT_CATEGORY_ENHANCEMENTS
local CR_CRIT_PARRY_RATING_TOOLTIP = CR_CRIT_PARRY_RATING_TOOLTIP
local CR_CRIT_TOOLTIP = CR_CRIT_TOOLTIP
local displayString, lastPanel = ''
local rating, spellCrit, rangedCrit, meleeCrit, critChance
local extraCritChance, extraCritRating
local function OnEnter()
DT.tooltip:ClearLines()
local tooltip, critText
if spellCrit >= rangedCrit and spellCrit >= meleeCrit then
critText = SPELL_CRIT_CHANCE
elseif rangedCrit >= meleeCrit then
critText = RANGED_CRIT_CHANCE
else
critText = MELEE_CRIT_CHANCE;
end
if GetCritChanceProvidesParryEffect() then
tooltip = format(CR_CRIT_PARRY_RATING_TOOLTIP, BreakUpLargeNumbers(extraCritRating), extraCritChance, GetCombatRatingBonusForCombatRatingValue(CR_PARRY, extraCritRating));
else
tooltip = format(CR_CRIT_TOOLTIP, BreakUpLargeNumbers(extraCritRating), extraCritChance);
end
DT.tooltip:AddDoubleLine(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, critText)..' '..format('%.2f%%', critChance)..FONT_COLOR_CODE_CLOSE, nil, 1, 1, 1)
DT.tooltip:AddLine(tooltip, nil, nil, nil, true)
DT.tooltip:Show()
end
local function OnEvent(self)
local minCrit = GetSpellCritChance(2)
for i = 3, MAX_SPELL_SCHOOLS do
spellCrit = GetSpellCritChance(i);
minCrit = min(minCrit, spellCrit);
end
spellCrit = minCrit
rangedCrit = GetRangedCritChance();
meleeCrit = GetCritChance();
if spellCrit >= rangedCrit and spellCrit >= meleeCrit then
critChance = spellCrit;
rating = CR_CRIT_SPELL;
elseif rangedCrit >= meleeCrit then
critChance = rangedCrit;
rating = CR_CRIT_RANGED;
else
critChance = meleeCrit;
rating = CR_CRIT_MELEE;
end
extraCritChance, extraCritRating = GetCombatRatingBonus(rating), GetCombatRating(rating)
if E.global.datatexts.settings.Crit.NoLabel then
self.text:SetFormattedText(displayString, critChance)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Crit.Label ~= '' and E.global.datatexts.settings.Crit.Label or CRIT_ABBR..': ', critChance)
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Crit.NoLabel and '' or '%s', hex, '%.'..E.global.datatexts.settings.Crit.decimalLength..'f%%|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Crit', STAT_CATEGORY_ENHANCEMENTS, {'UNIT_STATS', 'UNIT_AURA', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE', 'PLAYER_DAMAGE_DONE_MODS'}, OnEvent, nil, nil, OnEnter, nil, _G.STAT_CRITICAL_STRIKE, nil, ValueColorUpdate)

View File

@@ -0,0 +1,104 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local format, tonumber = format, tonumber
local type, ipairs, unpack = type, ipairs, unpack
local BreakUpLargeNumbers = BreakUpLargeNumbers
local GetMoney = GetMoney
local C_CurrencyInfo_GetBackpackCurrencyInfo = C_CurrencyInfo.GetBackpackCurrencyInfo
local C_CurrencyInfo_GetCurrencyInfo = C_CurrencyInfo.GetCurrencyInfo
local BONUS_ROLL_REWARD_MONEY = BONUS_ROLL_REWARD_MONEY
local iconString = '|T%s:16:16:0:0:64:64:4:60:4:60|t'
DT.CurrencyList = { GOLD = BONUS_ROLL_REWARD_MONEY, BACKPACK = 'Backpack' }
local function OnClick()
_G.ToggleCharacter('TokenFrame')
end
local function GetInfo(id)
local info = C_CurrencyInfo_GetCurrencyInfo(id)
if info then
return info.name, info.quantity, (info.iconFileID and format(iconString, info.iconFileID)) or '136012'
else
return '', '', '136012'
end
end
local function AddInfo(id)
local name, num, icon = GetInfo(id)
if name then
DT.tooltip:AddDoubleLine(format('%s %s', icon, name), BreakUpLargeNumbers(num), 1, 1, 1, 1, 1, 1)
end
end
local goldText
local function OnEvent(self)
goldText = E:FormatMoney(GetMoney(), E.global.datatexts.settings.Currencies.goldFormat or 'BLIZZARD', not E.global.datatexts.settings.Currencies.goldCoins)
local displayed = E.global.datatexts.settings.Currencies.displayedCurrency
if displayed == 'BACKPACK' then
local displayString = ''
for i = 1, 3 do
local info = C_CurrencyInfo_GetBackpackCurrencyInfo(i)
if info and info.quantity then
displayString = (i > 1 and displayString..' ' or displayString)..format('%s %s', format(iconString, info.iconFileID), E:ShortValue(info.quantity))
end
end
self.text:SetText(displayString == '' and goldText or displayString)
elseif displayed == 'GOLD' then
self.text:SetText(goldText)
else
local id = tonumber(displayed)
if not id then return end
local name, num, icon = GetInfo(id)
if not name then return end
local style = E.global.datatexts.settings.Currencies.displayStyle
if style == 'ICON' then
self.text:SetFormattedText('%s %s', icon, E:ShortValue(num))
elseif style == 'ICON_TEXT' then
self.text:SetFormattedText('%s %s %s', icon, name, E:ShortValue(num))
else --ICON_TEXT_ABBR
self.text:SetFormattedText('%s %s %s', icon, E:AbbreviateString(name), E:ShortValue(num))
end
end
end
local function OnEnter()
DT.tooltip:ClearLines()
local addLine, goldSpace
for _, info in ipairs(E.global.datatexts.settings.Currencies.tooltipData) do
local name, id, _, enabled = unpack(info)
if id and enabled then
if type(id) == 'number' then
AddInfo(id)
end
goldSpace = true
elseif enabled then
if addLine then
DT.tooltip:AddLine(' ')
else
addLine = true
end
DT.tooltip:AddLine(name)
goldSpace = true
end
end
if goldSpace then
DT.tooltip:AddLine(' ')
end
DT.tooltip:AddDoubleLine(L["Gold"]..':', goldText, nil, nil, nil, 1, 1, 1)
DT.tooltip:Show()
end
DT:RegisterDatatext('Currencies', nil, {'PLAYER_MONEY', 'SEND_MAIL_MONEY_CHANGED', 'SEND_MAIL_COD_CHANGED', 'PLAYER_TRADE_MONEY', 'TRADE_MONEY_CHANGED', 'CHAT_MSG_CURRENCY', 'CURRENCY_DISPLAY_UPDATE'}, OnEvent, nil, OnClick, OnEnter, nil, _G.CURRENCY)

View File

@@ -0,0 +1,155 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local ipairs, pairs, format = ipairs, pairs, format
local tinsert, tremove, next = tinsert, tremove, next
local C_CurrencyInfo_GetCurrencyInfo = C_CurrencyInfo.GetCurrencyInfo
local C_CurrencyInfo_GetCurrencyListInfo = C_CurrencyInfo.GetCurrencyListInfo
local C_CurrencyInfo_GetCurrencyListSize = C_CurrencyInfo.GetCurrencyListSize
local CustomCurrencies = {}
local CurrencyListNameToIndex = {}
local function OnEvent(self)
local currency = CustomCurrencies[self.name]
if currency then
local info = C_CurrencyInfo_GetCurrencyInfo(currency.ID)
if not info then return end
if currency.DISPLAY_STYLE == 'ICON' then
if currency.SHOW_MAX then
self.text:SetFormattedText('%s %d / %d', currency.ICON, info.quantity, info.maxQuantity)
else
self.text:SetFormattedText('%s %d', currency.ICON, info.quantity)
end
elseif currency.DISPLAY_STYLE == 'ICON_TEXT' then
if currency.SHOW_MAX then
self.text:SetFormattedText('%s %s %d / %d', currency.ICON, currency.NAME, info.quantity, info.maxQuantity)
else
self.text:SetFormattedText('%s %s %d', currency.ICON, currency.NAME, info.quantity)
end
else --ICON_TEXT_ABBR
if currency.SHOW_MAX then
self.text:SetFormattedText('%s %s %d / %d', currency.ICON, E:AbbreviateString(currency.NAME), info.quantity, info.maxQuantity)
else
self.text:SetFormattedText('%s %s %d', currency.ICON, E:AbbreviateString(currency.NAME), info.quantity)
end
end
end
end
local function OnEnter(self)
DT.tooltip:ClearLines()
local currency = CustomCurrencies[self.name]
if not currency or not currency.USE_TOOLTIP then return end
local index = CurrencyListNameToIndex[self.name]
if not index then return end
DT.tooltip:SetCurrencyToken(index)
DT.tooltip:Show()
end
local function AddCurrencyNameToIndex(name)
for index = 1, C_CurrencyInfo_GetCurrencyListSize() do
local info = C_CurrencyInfo_GetCurrencyListInfo(index)
if info.name == name then
CurrencyListNameToIndex[name] = index
break
end
end
end
local function RegisterNewDT(currencyID)
local info = C_CurrencyInfo_GetCurrencyInfo(currencyID)
if info.discovered then
local name = info.name
--Add to internal storage, stored with name as key
CustomCurrencies[name] = {NAME = name, ID = currencyID, ICON = format('|T%s:16:16:0:0:64:64:4:60:4:60|t', info.iconFileID), DISPLAY_STYLE = 'ICON', USE_TOOLTIP = true, SHOW_MAX = false, DISPLAY_IN_MAIN_TOOLTIP = true}
--Register datatext
DT:RegisterDatatext(name, _G.CURRENCY, {'CHAT_MSG_CURRENCY', 'CURRENCY_DISPLAY_UPDATE'}, OnEvent, nil, nil, OnEnter, nil, name)
--Save info to persistent storage, stored with ID as key
E.global.datatexts.customCurrencies[currencyID] = CustomCurrencies[name]
--Get the currency index for this currency, so we can use it for a tooltip
AddCurrencyNameToIndex(name)
--Set the HyperDT
local menuIndex = DT:GetMenuListCategory(_G.CURRENCY)
local hyperList = DT.HyperList[menuIndex]
if hyperList then
local menuList = hyperList.menuList
tinsert(menuList, {
text = name,
checked = function() return DT.EasyMenu.MenuGetItem(DT.SelectedDatatext, name) end,
func = function() DT.EasyMenu.MenuSetItem(DT.SelectedDatatext, name) end
})
DT:SortMenuList(menuList)
end
end
end
function DT:UpdateCustomCurrencySettings(currencyName, option, value)
if not currencyName or not option then return end
if option == 'DISPLAY_STYLE' then
CustomCurrencies[currencyName].DISPLAY_STYLE = value
elseif option == 'USE_TOOLTIP' then
CustomCurrencies[currencyName].USE_TOOLTIP = value
elseif option == 'SHOW_MAX' then
CustomCurrencies[currencyName].SHOW_MAX = value
elseif option == 'DISPLAY_IN_MAIN_TOOLTIP' then
CustomCurrencies[currencyName].DISPLAY_IN_MAIN_TOOLTIP = value
end
end
function DT:RegisterCustomCurrencyDT(currencyID)
if currencyID then
--We added a new datatext through the config
if not next(CustomCurrencies) then -- add Currency category if one didn't already exist
tinsert(DT.HyperList, { text = _G.CURRENCY, notCheckable = true, hasArrow = true, menuList = {} } )
DT:SortMenuList(DT.HyperList)
end
RegisterNewDT(currencyID)
else
--We called this in DT:Initialize, so load all the stored currency datatexts
for _, info in pairs(E.global.datatexts.customCurrencies) do
CustomCurrencies[info.NAME] = {NAME = info.NAME, ID = info.ID, ICON = info.ICON, DISPLAY_STYLE = info.DISPLAY_STYLE, USE_TOOLTIP = info.USE_TOOLTIP, SHOW_MAX = info.SHOW_MAX}
DT:RegisterDatatext(info.NAME, _G.CURRENCY, {'CHAT_MSG_CURRENCY', 'CURRENCY_DISPLAY_UPDATE'}, OnEvent, nil, nil, OnEnter, nil, info.NAME)
--Get the currency index for this currency, so we can use it for a tooltip
AddCurrencyNameToIndex(info.NAME)
end
end
end
function DT:RemoveCustomCurrency(currencyName)
--Remove from internal storage
CustomCurrencies[currencyName] = nil
if not next(CustomCurrencies) then
for i, menu in ipairs(DT.HyperList) do
if menu.text == _G.CURRENCY then
tremove(DT.HyperList, i)
break
end
end
else
local menuIndex = DT:GetMenuListCategory(_G.CURRENCY)
local hyperList = DT.HyperList[menuIndex]
if hyperList then
local menuList = hyperList.menuList
for i, info in ipairs(menuList) do
if info.text == currencyName then
tremove(menuList, i)
end
end
end
end
DT:SortMenuList(DT.HyperList)
end

82
Modules/DataTexts/DPS.lua Normal file
View File

@@ -0,0 +1,82 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local time, max, strjoin = time, max, strjoin
local CombatLogGetCurrentEventInfo = CombatLogGetCurrentEventInfo
local UnitGUID = UnitGUID
local lastSegment, petGUID = 0
local timeStamp, combatTime, DMGTotal, lastDMGAmount = 0, 0, 0, 0
local displayString, lastPanel = ''
local events = {
SWING_DAMAGE = true,
RANGE_DAMAGE = true,
SPELL_DAMAGE = true,
SPELL_PERIODIC_DAMAGE = true,
DAMAGE_SHIELD = true,
DAMAGE_SPLIT = true,
SPELL_EXTRA_ATTACKS = true
}
local function Reset()
timeStamp, combatTime, DMGTotal, lastDMGAmount = 0, 0, 0, 0
end
local function GetDPS(self)
local DPS
if DMGTotal == 0 or combatTime == 0 then
DPS = 0
else
DPS = DMGTotal / combatTime
end
self.text:SetFormattedText(displayString, L["DPS"], E:ShortValue(DPS))
end
local function OnEvent(self, event)
lastPanel = self
if event == 'UNIT_PET' then
petGUID = UnitGUID('pet')
elseif event == 'PLAYER_REGEN_DISABLED' or event == 'PLAYER_LEAVE_COMBAT' then
local now = time()
if now - lastSegment > 20 then --time since the last segment
Reset()
end
lastSegment = now
elseif event == 'COMBAT_LOG_EVENT_UNFILTERED' then
local timestamp, Event, _, sourceGUID, _, _, _, _, _, _, _, arg12, _, _, arg15, arg16 = CombatLogGetCurrentEventInfo()
if not events[Event] then return end
-- only use events from the player
local overKill
if sourceGUID == E.myguid or sourceGUID == petGUID then
if timeStamp == 0 then timeStamp = timestamp end
lastSegment = timeStamp
combatTime = timestamp - timeStamp
if Event == 'SWING_DAMAGE' then
lastDMGAmount = arg12
else
lastDMGAmount = arg15
end
if arg16 == nil then overKill = 0 else overKill = arg16 end
DMGTotal = DMGTotal + max(0, lastDMGAmount - overKill)
end
end
GetDPS(self)
end
local function OnClick(self)
Reset()
GetDPS(self)
end
local function ValueColorUpdate(hex)
displayString = strjoin('', '%s: ', hex, '%s')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('DPS', nil, {'UNIT_PET', 'COMBAT_LOG_EVENT_UNFILTERED', 'PLAYER_LEAVE_COMBAT', 'PLAYER_REGEN_DISABLED'}, OnEvent, nil, OnClick, nil, nil, _G.STAT_DPS_SHORT, nil, ValueColorUpdate)

View File

@@ -0,0 +1,848 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local TT = E:GetModule('Tooltip')
local LDB = E.Libs.LDB
local LSM = E.Libs.LSM
local _G = _G
local tostring, format, type, pcall = tostring, format, type, pcall
local tinsert, ipairs, pairs, wipe, sort = tinsert, ipairs, pairs, wipe, sort
local next, strfind, strlen, strsplit = next, strfind, strlen, strsplit
local CloseDropDownMenus = CloseDropDownMenus
local CreateFrame = CreateFrame
local EasyMenu = EasyMenu
local InCombatLockdown = InCombatLockdown
local IsInInstance = IsInInstance
local MouseIsOver = MouseIsOver
local RegisterStateDriver = RegisterStateDriver
local UIDropDownMenu_SetAnchor = UIDropDownMenu_SetAnchor
local UnregisterStateDriver = UnregisterStateDriver
local C_CurrencyInfo_GetCurrencyInfo = C_CurrencyInfo.GetCurrencyInfo
local C_CurrencyInfo_GetCurrencyListSize = C_CurrencyInfo.GetCurrencyListSize
local C_CurrencyInfo_GetCurrencyListInfo = C_CurrencyInfo.GetCurrencyListInfo
local C_CurrencyInfo_GetCurrencyListLink = C_CurrencyInfo.GetCurrencyListLink
local C_CurrencyInfo_GetCurrencyIDFromLink = C_CurrencyInfo.GetCurrencyIDFromLink
local C_CurrencyInfo_ExpandCurrencyList = C_CurrencyInfo.ExpandCurrencyList
local GetNumSpecializations = GetNumSpecializations
local GetSpecializationInfo = GetSpecializationInfo
local MISCELLANEOUS = MISCELLANEOUS
local LFG_TYPE_DUNGEON = LFG_TYPE_DUNGEON
local expansion = _G['EXPANSION_NAME'..GetExpansionLevel()]
local ActivateHyperMode
local HyperList = {}
DT.tooltip = CreateFrame('GameTooltip', 'DataTextTooltip', E.UIParent, 'GameTooltipTemplate')
DT.EasyMenu = CreateFrame('Frame', 'DataTextEasyMenu', E.UIParent, 'UIDropDownMenuTemplate')
DT.SelectedDatatext = nil
DT.HyperList = HyperList
DT.RegisteredPanels = {}
DT.RegisteredDataTexts = {}
DT.LoadedInfo = {}
DT.PanelPool = {
InUse = {},
Free = {},
Count = 0
}
DT.FontStrings = {}
DT.AssignedDatatexts = {}
DT.UnitEvents = {
UNIT_AURA = true,
UNIT_RESISTANCES = true,
UNIT_STATS = true,
UNIT_ATTACK_POWER = true,
UNIT_RANGED_ATTACK_POWER = true,
UNIT_TARGET = true,
UNIT_SPELL_HASTE = true
}
DT.SPECIALIZATION_CACHE = {}
function DT:SetEasyMenuAnchor(menu, dt)
local point = E:GetScreenQuadrant(dt)
local bottom = point and strfind(point, 'BOTTOM')
local left = point and strfind(point, 'LEFT')
local anchor1 = (bottom and left and 'BOTTOMLEFT') or (bottom and 'BOTTOMRIGHT') or (left and 'TOPLEFT') or 'TOPRIGHT'
local anchor2 = (bottom and left and 'TOPLEFT') or (bottom and 'TOPRIGHT') or (left and 'BOTTOMLEFT') or 'BOTTOMRIGHT'
UIDropDownMenu_SetAnchor(menu, 0, 0, anchor1, dt, anchor2)
end
--> [HyperDT Credits] <--
--> Original Work: NihilisticPandemonium
--> Modified by Azilroka! :)
function DT:SingleHyperMode(_, key, active)
if DT.SelectedDatatext and (key == 'LALT' or key == 'RALT') then
if active == 1 and MouseIsOver(DT.SelectedDatatext) then
DT:OnLeave()
DT:SetEasyMenuAnchor(DT.EasyMenu, DT.SelectedDatatext)
EasyMenu(HyperList, DT.EasyMenu, nil, nil, nil, 'MENU')
elseif _G.DropDownList1:IsShown() and not _G.DropDownList1:IsMouseOver() then
CloseDropDownMenus()
end
end
end
function DT:HyperClick()
DT.SelectedDatatext = self
DT:SetEasyMenuAnchor(DT.EasyMenu, DT.SelectedDatatext)
EasyMenu(HyperList, DT.EasyMenu, nil, nil, nil, 'MENU')
end
function DT:EnableHyperMode(Panel)
DT:OnLeave()
if Panel then
for _, dt in pairs(Panel.dataPanels) do
dt.overlay:Show()
dt:SetScript('OnEnter', nil)
dt:SetScript('OnLeave', nil)
dt:SetScript('OnClick', DT.HyperClick)
end
else
for _, panel in pairs(DT.RegisteredPanels) do
for _, dt in pairs(panel.dataPanels) do
dt.overlay:Show()
dt:SetScript('OnEnter', nil)
dt:SetScript('OnLeave', nil)
dt:SetScript('OnClick', DT.HyperClick)
end
end
end
end
function DT:OnEnter()
if E.db.datatexts.noCombatHover and InCombatLockdown() then return end
if self.parent then
DT.SelectedDatatext = self
DT:SetupTooltip(self)
end
if self.MouseEnters then
for _, func in ipairs(self.MouseEnters) do
func(self)
end
end
DT.MouseEnter(self)
end
function DT:OnLeave()
if self.MouseLeaves then
for _, func in ipairs(self.MouseLeaves) do
func(self)
end
end
DT.MouseLeave(self)
DT.tooltip:Hide()
end
function DT:MouseEnter()
local frame = self.parent or self
if frame.db and frame.db.mouseover then
E:UIFrameFadeIn(frame, 0.2, frame:GetAlpha(), 1)
end
end
function DT:MouseLeave()
local frame = self.parent or self
if frame.db and frame.db.mouseover then
E:UIFrameFadeOut(frame, 0.2, frame:GetAlpha(), 0)
end
end
function DT:FetchFrame(givenName)
local panelExists = DT.PanelPool.InUse[givenName]
if panelExists then return panelExists end
local count = DT.PanelPool.Count
local name = 'ElvUI_DTPanel' .. count
local frame
local poolName, poolFrame = next(DT.PanelPool.Free)
if poolName then
frame = poolFrame
DT.PanelPool.Free[poolName] = nil
else
frame = CreateFrame('Frame', name, E.UIParent, 'BackdropTemplate')
DT.PanelPool.Count = DT.PanelPool.Count + 1
end
DT.PanelPool.InUse[givenName] = frame
return frame
end
function DT:EmptyPanel(panel)
panel:Hide()
for _, dt in ipairs(panel.dataPanels) do
dt:UnregisterAllEvents()
dt:SetScript('OnUpdate', nil)
dt:SetScript('OnEvent', nil)
dt:SetScript('OnEnter', nil)
dt:SetScript('OnLeave', nil)
dt:SetScript('OnClick', nil)
end
UnregisterStateDriver(panel, 'visibility')
E:DisableMover(panel.moverName)
end
function DT:ReleasePanel(givenName)
local panel = DT.PanelPool.InUse[givenName]
if panel then
DT:EmptyPanel(panel)
DT.PanelPool.Free[givenName] = panel
DT.PanelPool.InUse[givenName] = nil
DT.RegisteredPanels[givenName] = nil
E.db.movers[panel.moverName] = nil
end
end
function DT:BuildPanelFrame(name, db, fromInit)
db = db or E.global.datatexts.customPanels[name] or DT:Panel_DefaultGlobalSettings(name)
local Panel = DT:FetchFrame(name)
Panel:ClearAllPoints()
Panel:SetPoint('CENTER')
Panel:SetSize(db.width, db.height)
local MoverName = 'DTPanel'..name..'Mover'
Panel.moverName = MoverName
Panel.givenName = name
local holder = E:GetMoverHolder(MoverName)
if holder then
E:SetMoverPoints(MoverName, Panel)
else
E:CreateMover(Panel, MoverName, name, nil, nil, nil, nil, nil, 'datatexts,panels')
end
DT:RegisterPanel(Panel, db.numPoints, db.tooltipAnchor, db.tooltipXOffset, db.tooltipYOffset, db.growth == 'VERTICAL')
if not fromInit then
DT:UpdatePanelAttributes(name, db)
end
end
local LDBhex, LDBna = '|cffFFFFFF', {['N/A'] = true, ['n/a'] = true, ['N/a'] = true}
function DT:BuildPanelFunctions(name, obj)
local panel
local function OnEnter(dt)
DT.tooltip:ClearLines()
if obj.OnTooltipShow then obj.OnTooltipShow(DT.tooltip) end
if obj.OnEnter then obj.OnEnter(dt) end
DT.tooltip:Show()
end
local function OnLeave(dt)
if obj.OnLeave then obj.OnLeave(dt) end
end
local function OnClick(dt, button)
if obj.OnClick then
obj.OnClick(dt, button)
end
end
local function UpdateText(_, Name, _, Value)
if not Value or (strlen(Value) >= 3) or (Value == Name or LDBna[Value]) then
panel.text:SetText((not LDBna[Value] and Value) or Name)
else
panel.text:SetFormattedText('%s: %s%s|r', Name, LDBhex, Value)
end
end
local function OnCallback(Hex)
if name and obj then
LDBhex = Hex
LDB.callbacks:Fire('LibDataBroker_AttributeChanged_'..name..'_text', name, nil, obj.text, obj)
end
end
local function OnEvent(dt)
panel = dt
LDB:RegisterCallback('LibDataBroker_AttributeChanged_'..name..'_text', UpdateText)
LDB:RegisterCallback('LibDataBroker_AttributeChanged_'..name..'_value', UpdateText)
OnCallback(LDBhex)
end
return OnEnter, OnLeave, OnClick, OnCallback, OnEvent, UpdateText
end
function DT:SetupObjectLDB(name, obj)
local onEnter, onLeave, onClick, onCallback, onEvent = DT:BuildPanelFunctions(name, obj)
local data = DT:RegisterDatatext(name, 'Data Broker', nil, onEvent, nil, onClick, onEnter, onLeave)
E.valueColorUpdateFuncs[onCallback] = true
data.isLibDataBroker = true
-- Update config if it has been loaded
if DT.PanelLayoutOptions then
DT:PanelLayoutOptions()
end
end
function DT:RegisterLDB()
for name, obj in LDB:DataObjectIterator() do
DT:SetupObjectLDB(name, obj)
end
end
function DT:GetDataPanelPoint(panel, i, numPoints, vertical)
if numPoints == 1 then
return 'CENTER', panel, 'CENTER'
else
local point, relativePoint, xOffset, yOffset = 'LEFT', i == 1 and 'LEFT' or 'RIGHT', 4, 0
if vertical then
point, relativePoint, xOffset, yOffset = 'TOP', i == 1 and 'TOP' or 'BOTTOM', 0, -4
end
local lastPanel = (i == 1 and panel) or panel.dataPanels[i - 1]
return point, lastPanel, relativePoint, xOffset, yOffset
end
end
function DT:SetupTooltip(panel)
local parent = panel:GetParent()
DT.tooltip:SetOwner(panel, parent.anchor, parent.xOff, parent.yOff)
if not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:Hide() -- WHY??? BECAUSE FUCK GAMETOOLTIP, THATS WHY!!
end
end
function DT:RegisterPanel(panel, numPoints, anchor, xOff, yOff, vertical)
local realName = panel:GetName()
local name = panel.givenName or realName
if not name then
E:Print('DataTexts: Requires a panel name.')
return
end
DT.RegisteredPanels[name] = panel
panel:SetScript('OnEnter', DT.OnEnter)
panel:SetScript('OnLeave', DT.OnLeave)
panel:SetScript('OnSizeChanged', DT.PanelSizeChanged)
panel.dataPanels = panel.dataPanels or {}
panel.numPoints = numPoints
panel.xOff = xOff
panel.yOff = yOff
panel.anchor = anchor
panel.vertical = vertical
end
function DT:Panel_DefaultGlobalSettings(name)
local db = E:CopyTable({}, G.datatexts.newPanelInfo)
E.global.datatexts.customPanels[name] = db
return db
end
function DT:AssignPanelToDataText(dt, data, event, ...)
dt.name = data.name or '' -- This is needed for Custom Currencies
if data.events then
for _, ev in pairs(data.events) do
if data.eventFunc then
if data.objectEvent then
if not dt.objectEventFunc then
dt.objectEvent = data.objectEvent
dt.objectEventFunc = function(_, ...)
if data.eventFunc then
data.eventFunc(dt, ...)
end
end
end
if not E:HasFunctionForObject(ev, data.objectEvent, dt.objectEventFunc) then
E:RegisterEventForObject(ev, data.objectEvent, dt.objectEventFunc)
end
elseif DT.UnitEvents[ev] then
pcall(dt.RegisterUnitEvent, dt, ev, 'player')
else
pcall(dt.RegisterEvent, dt, ev)
end
end
end
end
local ev = event or 'ELVUI_FORCE_UPDATE'
if data.eventFunc then
if not data.objectEvent then
dt:SetScript('OnEvent', data.eventFunc)
end
data.eventFunc(dt, ev, ...)
end
if data.onUpdate then
dt:SetScript('OnUpdate', data.onUpdate)
data.onUpdate(dt, 20000)
end
if data.onClick then
dt:SetScript('OnClick', function(p, button)
if E.db.datatexts.noCombatClick and InCombatLockdown() then return end
data.onClick(p, button)
DT.tooltip:Hide()
end)
end
if data.onEnter then
tinsert(dt.MouseEnters, data.onEnter)
end
if data.onLeave then
tinsert(dt.MouseLeaves, data.onLeave)
end
end
function DT:ForceUpdate_DataText(name)
for dtSlot, dtName in pairs(DT.AssignedDatatexts) do
if dtName.name == name then
if dtName.colorUpdate then
dtName.colorUpdate(E.media.hexvaluecolor)
end
if dtName.eventFunc then
dtName.eventFunc(dtSlot, 'ELVUI_FORCE_UPDATE')
end
end
end
end
function DT:GetTextAttributes(panel, db)
local panelWidth, panelHeight = panel:GetSize()
local numPoints = db and db.numPoints or panel.numPoints or 1
local vertical = db and db.vertical or panel.vertical
local width, height = (panelWidth / numPoints) - 4, panelHeight - 4
if vertical then width, height = panelWidth - 4, (panelHeight / numPoints) - 4 end
return width, height, vertical, numPoints
end
function DT:UpdatePanelInfo(panelName, panel, ...)
if not panel then panel = DT.RegisteredPanels[panelName] end
local db = panel.db or P.datatexts.panels[panelName] and DT.db.panels[panelName]
if not db then return end
local info = DT.LoadedInfo
local font, fontSize, fontOutline = info.font, info.fontSize, info.fontOutline
if db and db.fonts and db.fonts.enable then
font, fontSize, fontOutline = LSM:Fetch('font', db.fonts.font), db.fonts.fontSize, db.fonts.fontOutline
end
local chatPanel = panelName == 'LeftChatDataPanel' or panelName == 'RightChatDataPanel'
local battlePanel = info.isInBattle and chatPanel and (not DT.ForceHideBGStats and E.db.datatexts.battleground)
if battlePanel then
DT:RegisterEvent('UPDATE_BATTLEFIELD_SCORE')
DT.ShowingBattleStats = info.instanceType
elseif chatPanel and DT.ShowingBattleStats then
DT:UnregisterEvent('UPDATE_BATTLEFIELD_SCORE')
DT.ShowingBattleStats = nil
end
local width, height, vertical, numPoints = DT:GetTextAttributes(panel, db)
for i = 1, numPoints do
local dt = panel.dataPanels[i]
if not dt then
dt = CreateFrame('Button', panelName..'_DataText'..i, panel)
dt.MouseEnters = {}
dt.MouseLeaves = {}
dt:RegisterForClicks('AnyUp')
local text = dt:CreateFontString(nil, 'ARTWORK')
text:SetAllPoints()
text:SetJustifyV('MIDDLE')
dt.text = text
DT.FontStrings[text] = true
local overlay = dt:CreateTexture(nil, 'OVERLAY')
overlay:SetTexture(E.media.blankTex)
overlay:SetVertexColor(0.3, 0.9, 0.3, .3)
overlay:SetAllPoints()
dt.overlay = overlay
panel.dataPanels[i] = dt
end
end
--Note: some plugins dont have db.border, we need the nil checks
panel.forcedBorderColors = (db.border == false and {0,0,0,0}) or nil
panel:SetTemplate(db.backdrop and (db.panelTransparency and 'Transparent' or 'Default') or 'NoBackdrop', true)
--Show Border option
if db.border ~= nil then
if panel.iborder then panel.iborder:SetShown(db.border) end
if panel.oborder then panel.oborder:SetShown(db.border) end
end
--Restore Panels
for i, dt in ipairs(panel.dataPanels) do
dt:SetShown(i <= numPoints)
dt:SetSize(width, height)
dt:ClearAllPoints()
dt:SetPoint(DT:GetDataPanelPoint(panel, i, numPoints, vertical))
dt:UnregisterAllEvents()
dt:EnableMouseWheel(false)
dt:SetScript('OnUpdate', nil)
dt:SetScript('OnEvent', nil)
dt:SetScript('OnClick', nil)
dt:SetScript('OnEnter', DT.OnEnter)
dt:SetScript('OnLeave', DT.OnLeave)
wipe(dt.MouseEnters)
wipe(dt.MouseLeaves)
dt.overlay:Hide()
dt.pointIndex = i
dt.parent = panel
dt.parentName = panelName
dt.battleStats = battlePanel
dt.db = db
E:StopFlash(dt)
if dt.objectEvent and dt.objectEventFunc then
E:UnregisterAllEventsForObject(dt.objectEvent, dt.objectEventFunc)
dt.objectEvent, dt.objectEventFunc = nil, nil
end
dt.text:FontTemplate(font, fontSize, fontOutline)
dt.text:SetJustifyH(db.textJustify or 'CENTER')
dt.text:SetWordWrap(DT.db.wordWrap)
dt.text:SetText()
if battlePanel then
dt:SetScript('OnClick', DT.ToggleBattleStats)
tinsert(dt.MouseEnters, DT.HoverBattleStats)
else
local assigned = DT.RegisteredDataTexts[ DT.db.panels[panelName][i] ]
DT.AssignedDatatexts[dt] = assigned
if assigned then DT:AssignPanelToDataText(dt, assigned, ...) end
end
end
end
function DT:LoadDataTexts(...)
local data = DT.LoadedInfo
data.font, data.fontSize, data.fontOutline = LSM:Fetch('font', DT.db.font), DT.db.fontSize, DT.db.fontOutline
data.inInstance, data.instanceType = IsInInstance()
data.isInBattle = data.inInstance and data.instanceType == 'pvp'
for panel, db in pairs(E.global.datatexts.customPanels) do
DT:UpdatePanelAttributes(panel, db, true)
end
for panelName, panel in pairs(DT.RegisteredPanels) do
local db = DT.db.panels[panelName]
if db and db.enable then
DT:UpdatePanelInfo(panelName, panel, ...)
end
end
if DT.ShowingBattleStats then
DT:UPDATE_BATTLEFIELD_SCORE()
end
end
function DT:PanelSizeChanged()
if not self.dataPanels then return end
local db = self.db or P.datatexts.panels[self.name] and DT.db.panels[self.name]
local width, height, vertical, numPoints = DT:GetTextAttributes(self, db)
for i, dt in ipairs(self.dataPanels) do
dt:SetSize(width, height)
dt:ClearAllPoints()
dt:SetPoint(DT:GetDataPanelPoint(self, i, numPoints, vertical))
end
end
function DT:UpdatePanelAttributes(name, db, fromLoad)
local Panel = DT.PanelPool.InUse[name]
DT.OnLeave(Panel)
Panel.db = db
Panel.name = name
Panel.numPoints = db.numPoints
Panel.xOff = db.tooltipXOffset
Panel.yOff = db.tooltipYOffset
Panel.anchor = db.tooltipAnchor
Panel.vertical = db.growth == 'VERTICAL'
Panel:SetSize(db.width, db.height)
Panel:SetFrameStrata(db.frameStrata)
Panel:SetFrameLevel(db.frameLevel)
E:UIFrameFadeIn(Panel, 0.2, Panel:GetAlpha(), db.mouseover and 0 or 1)
if not DT.db.panels[name] or type(DT.db.panels[name]) ~= 'table' then
DT.db.panels[name] = { enable = false }
end
for i = 1, (E.global.datatexts.customPanels[name].numPoints or 1) do
if not DT.db.panels[name][i] then
DT.db.panels[name][i] = ''
end
end
if DT.db.panels[name].enable then
E:EnableMover(Panel.moverName)
RegisterStateDriver(Panel, 'visibility', db.visibility)
if not fromLoad then
DT:UpdatePanelInfo(name, Panel)
end
else
DT:EmptyPanel(Panel)
end
end
function DT:GetMenuListCategory(category)
for i, info in ipairs(HyperList) do
if info.text == category then
return i
end
end
end
do
local function menuSort(a, b)
if a.order and b.order then
return a.order < b.order
end
return a.text < b.text
end
function DT:SortMenuList(list)
for _, menu in pairs(list) do
if menu.menuList then
DT:SortMenuList(menu.menuList)
end
end
sort(list, menuSort)
end
end
function DT:HyperDT()
if ActivateHyperMode then
ActivateHyperMode = nil
DT:LoadDataTexts()
else
ActivateHyperMode = true
DT:EnableHyperMode()
end
end
function DT:RegisterHyperDT()
for name, info in pairs(DT.RegisteredDataTexts) do
local category = DT:GetMenuListCategory(info.category or MISCELLANEOUS)
if not category then
category = #HyperList + 1
tinsert(HyperList, { order = 0, text = info.category or MISCELLANEOUS, notCheckable = true, hasArrow = true, menuList = {} } )
end
tinsert(HyperList[category].menuList, {
text = info.localizedName or name,
checked = function() return DT.EasyMenu.MenuGetItem(DT.SelectedDatatext, name) end,
func = function() DT.EasyMenu.MenuSetItem(DT.SelectedDatatext, name) end
})
end
tinsert(HyperList, {
order = 100, text = L["NONE"],
checked = function() return DT.EasyMenu.MenuGetItem(DT.SelectedDatatext, '') end,
func = function() DT.EasyMenu.MenuSetItem(DT.SelectedDatatext, '') end
})
DT:SortMenuList(HyperList)
DT:RegisterEvent('MODIFIER_STATE_CHANGED', 'SingleHyperMode')
end
function DT:PopulateData()
local Collapsed = {}
local listSize, i = C_CurrencyInfo_GetCurrencyListSize(), 1
local headerIndex
while listSize >= i do
local info = C_CurrencyInfo_GetCurrencyListInfo(i)
if info.isHeader and not info.isHeaderExpanded then
C_CurrencyInfo_ExpandCurrencyList(i, true)
listSize = C_CurrencyInfo_GetCurrencyListSize()
Collapsed[info.name] = true
end
if info.isHeader then
G.datatexts.settings.Currencies.tooltipData[i] = { info.name, nil, nil, (info.name == expansion or info.name == MISCELLANEOUS) or strfind(info.name, LFG_TYPE_DUNGEON) }
E.global.datatexts.settings.Currencies.tooltipData[i] = E.global.datatexts.settings.Currencies.tooltipData[i] or { info.name, nil, nil, G.datatexts.settings.Currencies.tooltipData[i][4] }
E.global.datatexts.settings.Currencies.tooltipData[i][1] = info.name
headerIndex = i
end
if not info.isHeader then
local currencyLink = C_CurrencyInfo_GetCurrencyListLink(i)
local currencyID = currencyLink and C_CurrencyInfo_GetCurrencyIDFromLink(currencyLink)
if currencyID then
DT.CurrencyList[tostring(currencyID)] = info.name
G.datatexts.settings.Currencies.tooltipData[i] = { info.name, currencyID, headerIndex, G.datatexts.settings.Currencies.tooltipData[headerIndex][4] }
E.global.datatexts.settings.Currencies.tooltipData[i] = E.global.datatexts.settings.Currencies.tooltipData[i] or { info.name, currencyID, headerIndex, G.datatexts.settings.Currencies.tooltipData[headerIndex][4] }
E.global.datatexts.settings.Currencies.tooltipData[i][1] = info.name
end
end
i = i + 1
end
for k = 1, listSize do
local info = C_CurrencyInfo_GetCurrencyListInfo(k)
if not info then
break
elseif info.isHeader and info.isHeaderExpanded and Collapsed[info.name] then
C_CurrencyInfo_ExpandCurrencyList(k, false)
end
end
wipe(Collapsed)
for index = 1, GetNumSpecializations() do
local id, name, _, icon, _, statID = GetSpecializationInfo(index)
if id then
DT.SPECIALIZATION_CACHE[index] = { id = id, name = name, icon = icon, statID = statID }
DT.SPECIALIZATION_CACHE[id] = { name = name, icon = icon }
end
end
end
function DT:CURRENCY_DISPLAY_UPDATE(_, currencyType)
if currencyType and not DT.CurrencyList[tostring(currencyType)] then
local info = C_CurrencyInfo_GetCurrencyInfo(currencyType)
if info and info.name then
DT.CurrencyList[tostring(currencyType)] = info.name
end
end
end
function DT:PLAYER_ENTERING_WORLD()
DT:LoadDataTexts()
end
function DT:Initialize()
DT.Initialized = true
DT.db = E.db.datatexts
DT.EasyMenu:SetClampedToScreen(true)
DT.EasyMenu:EnableMouse(true)
DT.EasyMenu.MenuSetItem = function(dt, value)
DT.db.panels[dt.parentName][dt.pointIndex] = value
DT:UpdatePanelInfo(dt.parentName, dt.parent)
if ActivateHyperMode then
DT:EnableHyperMode(dt.parent)
end
DT.SelectedDatatext = nil
CloseDropDownMenus()
end
DT.EasyMenu.MenuGetItem = function(dt, value)
return dt and (DT.db.panels[dt.parentName] and DT.db.panels[dt.parentName][dt.pointIndex] == value)
end
if E.private.skins.blizzard.enable and E.private.skins.blizzard.tooltip then
TT:SetStyle(DT.tooltip)
end
-- Ignore header font size on DatatextTooltip
local font = LSM:Fetch('font', E.db.tooltip.font)
local fontOutline = E.db.tooltip.fontOutline
local textSize = E.db.tooltip.textFontSize
_G.DataTextTooltipTextLeft1:FontTemplate(font, textSize, fontOutline)
_G.DataTextTooltipTextRight1:FontTemplate(font, textSize, fontOutline)
LDB.RegisterCallback(E, 'LibDataBroker_DataObjectCreated', DT.SetupObjectLDB)
DT:RegisterLDB() -- LibDataBroker
DT:RegisterCustomCurrencyDT() -- Register all the user created currency datatexts from the 'CustomCurrency' DT.
for name, db in pairs(E.global.datatexts.customPanels) do
DT:BuildPanelFrame(name, db, true)
end
do -- we need to register the panels to access them for the text
DT.BattleStats.LEFT.panel = _G.LeftChatDataPanel.dataPanels
DT.BattleStats.RIGHT.panel = _G.RightChatDataPanel.dataPanels
end
DT:PopulateData()
DT:RegisterHyperDT()
DT:RegisterEvent('PLAYER_ENTERING_WORLD')
DT:RegisterEvent('CURRENCY_DISPLAY_UPDATE')
end
--[[
DT:RegisterDatatext(name, events, eventFunc, updateFunc, clickFunc, onEnterFunc, onLeaveFunc, localizedName)
name - name of the datatext (required)
category - name of the category the datatext belongs to.
events - must be a table with string values of event names to register
eventFunc - function that gets fired when an event gets triggered
updateFunc - onUpdate script target function
click - function to fire when clicking the datatext
onEnterFunc - function to fire OnEnter
onLeaveFunc - function to fire OnLeave, if not provided one will be set for you that hides the tooltip.
localizedName - localized name of the datetext
objectEvent - register events on an object, using E.RegisterEventForObject instead of panel.RegisterEvent
colorUpdate - function that fires when called from the config when you change the dt options.
]]
function DT:RegisterDatatext(name, category, events, eventFunc, updateFunc, clickFunc, onEnterFunc, onLeaveFunc, localizedName, objectEvent, colorUpdate)
if not name then return end
if type(category) ~= 'string' and category ~= nil then return E:Print(format('%s is an invalid DataText.', name)) end
local data = { name = name, category = category }
if type(events) == 'function' then
return E:Print(format('%s is an invalid DataText. Events must be registered as a table or a string.', name))
else
data.events = type(events) == 'string' and { strsplit('[, ]', events) } or events
data.eventFunc = eventFunc
data.objectEvent = objectEvent
end
if updateFunc and type(updateFunc) == 'function' then
data.onUpdate = updateFunc
end
if clickFunc and type(clickFunc) == 'function' then
data.onClick = clickFunc
end
if onEnterFunc and type(onEnterFunc) == 'function' then
data.onEnter = onEnterFunc
end
if onLeaveFunc and type(onLeaveFunc) == 'function' then
data.onLeave = onLeaveFunc
end
if localizedName and type(localizedName) == 'string' then
data.localizedName = localizedName
end
if colorUpdate and type(colorUpdate) == 'function' then
data.colorUpdate = colorUpdate
end
DT.RegisteredDataTexts[name] = data
return data
end
E:RegisterModule(DT:GetName())

View File

@@ -0,0 +1,30 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local date = date
local InCombatLockdown = InCombatLockdown
local FormatShortDate = FormatShortDate
local hexColor, lastPanel
local function OnClick()
if InCombatLockdown() then _G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT) return end
_G.GameTimeFrame:Click()
end
local function OnEvent(self)
local dateTable = date('*t')
self.text:SetText(FormatShortDate(dateTable.day, dateTable.month, dateTable.year):gsub('([/.])', hexColor..'%1|r'))
lastPanel = self
end
local function ValueColorUpdate(hex)
hexColor = hex
if lastPanel ~= nil then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Date', nil, {'UPDATE_INSTANCE_INFO'}, OnEvent, nil, OnClick, nil, nil, nil, nil, ValueColorUpdate)

View File

@@ -0,0 +1,142 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local pairs = pairs
local format = format
local GetDungeonDifficultyID, GetRaidDifficultyID, GetLegacyRaidDifficultyID = GetDungeonDifficultyID, GetRaidDifficultyID, GetLegacyRaidDifficultyID
local SetDungeonDifficultyID, SetRaidDifficultyID, SetLegacyRaidDifficultyID = SetDungeonDifficultyID, SetRaidDifficultyID, SetLegacyRaidDifficultyID
local GetInstanceInfo, GetDifficultyInfo, ResetInstances = GetInstanceInfo, GetDifficultyInfo, ResetInstances
local C_ChallengeMode_GetActiveChallengeMapID = C_ChallengeMode.GetActiveChallengeMapID
local C_ChallengeMode_GetActiveKeystoneInfo = C_ChallengeMode.GetActiveKeystoneInfo
local C_ChallengeMode_IsChallengeModeActive = C_ChallengeMode.IsChallengeModeActive
local C_MythicPlus_IsMythicPlusActive = C_MythicPlus.IsMythicPlusActive
local DungeonTexture, RaidTexture, LegacyTexture = CreateAtlasMarkup('Dungeon', 20, 20), CreateAtlasMarkup('Raid', 20, 20), CreateAtlasMarkup('worldquest-icon-raid', 20, 20)
local DungeonDifficultyID, RaidDifficultyID, LegacyRaidDifficultyID = GetDungeonDifficultyID(), GetRaidDifficultyID(), GetLegacyRaidDifficultyID()
local RightClickMenu, DiffLabel = {
{ text = _G.DUNGEON_DIFFICULTY, isTitle = true, notCheckable = true },
{ text = _G.PLAYER_DIFFICULTY1, checked = function() return GetDungeonDifficultyID() == 1 end, func = function() SetDungeonDifficultyID(1) end },
{ text = _G.PLAYER_DIFFICULTY2, checked = function() return GetDungeonDifficultyID() == 2 end, func = function() SetDungeonDifficultyID(2) end },
{ text = _G.PLAYER_DIFFICULTY6, checked = function() return GetDungeonDifficultyID() == 23 end, func = function() SetDungeonDifficultyID(23) end },
{ text = '', isTitle = true, notCheckable = true };
{ text = _G.RAID_DIFFICULTY, isTitle = true, notCheckable = true},
{ text = _G.PLAYER_DIFFICULTY1, checked = function() return GetRaidDifficultyID() == 14 end, func = function() SetRaidDifficultyID(14) end },
{ text = _G.PLAYER_DIFFICULTY2, checked = function() return GetRaidDifficultyID() == 15 end, func = function() SetRaidDifficultyID(15) end },
{ text = _G.PLAYER_DIFFICULTY6, checked = function() return GetRaidDifficultyID() == 16 end, func = function() SetRaidDifficultyID(16) end },
{ text = '', isTitle = true, notCheckable = true };
{ text = _G.UNIT_FRAME_DROPDOWN_SUBSECTION_TITLE_LEGACY_RAID, isTitle = true, notCheckable = true },
{ text = _G.RAID_DIFFICULTY1, checked = function() return GetLegacyRaidDifficultyID() == 3 end, func = function() SetLegacyRaidDifficultyID(3) end },
{ text = _G.RAID_DIFFICULTY1..' '.._G.PLAYER_DIFFICULTY2, checked = function() return GetLegacyRaidDifficultyID() == 5 end, func = function() SetLegacyRaidDifficultyID(5) end },
{ text = _G.RAID_DIFFICULTY2, checked = function() return GetLegacyRaidDifficultyID() == 4 end, func = function() SetLegacyRaidDifficultyID(4) end },
{ text = _G.RAID_DIFFICULTY2..' '.._G.PLAYER_DIFFICULTY2, checked = function() return GetLegacyRaidDifficultyID() == 6 end, func = function() SetLegacyRaidDifficultyID(6) end },
{ text = '', isTitle = true, notCheckable = true };
{ text = _G.RESET_INSTANCES, notCheckable = true, func = function() ResetInstances() end},
}, {}
for i = 1, 200 do
if GetDifficultyInfo(i) then
local Name = GetDifficultyInfo(i)
if not DiffLabel[i] then DiffLabel[i] = Name end
end
end
local DiffIDLabel = {
['N'] = { 1, 14, 38 },
['H'] = { 2, 15, 39 },
['M'] = { 16, 23, 40 },
['10N'] = { 3 },
['25N'] = { 4 },
['10H'] = { 5 },
['25H'] = { 6 },
['LFR'] = { 7, 17 },
['CM'] = { 8 },
['40'] = { 9 },
['TW'] = { 24, 33, 151 },
['S'] = { 11, 12, 20, 152, 153 },
['E'] = { 18, 19, 30 },
['PvP'] = { 25, 29, 32, 34, 45 },
['WF'] = { 147 },
['WFH'] = { 149 },
}
local IDTexture = {
LEGACY = { 3, 4, 5, 6, 9 },
RAID = { 14, 15, 16 },
}
local Garrison = {
[1152] = true,
[1330] = true,
[1153] = true,
[1154] = true,
[1158] = true,
[1331] = true,
[1159] = true,
[1160] = true,
}
local function GetDiffIDLabel(ID)
for Name, Info in pairs(DiffIDLabel) do
for _, Num in pairs(Info) do
if Num == ID then
return Name
end
end
end
return ID
end
local function GetLabelTexture(ID)
for Name, Info in pairs(IDTexture) do
for _, Num in pairs(Info) do
if Num == ID then
return Name == 'LEGACY' and LegacyTexture or RaidTexture
end
end
end
return DungeonTexture
end
local function OnClick(self)
DT:SetEasyMenuAnchor(DT.EasyMenu, self)
_G.EasyMenu(RightClickMenu, DT.EasyMenu, nil, nil, nil, 'MENU')
end
local function OnEvent(self)
local name, instanceType, difficultyID, _, _, _, _, instanceID = GetInstanceInfo()
local keyStoneLevel = C_MythicPlus_IsMythicPlusActive() and C_ChallengeMode_GetActiveChallengeMapID() and C_ChallengeMode_IsChallengeModeActive() and C_ChallengeMode_GetActiveKeystoneInfo()
if keyStoneLevel then
self.text:SetFormattedText('%s %s +%s', GetLabelTexture(difficultyID), name, keyStoneLevel)
elseif instanceType ~= 'none' and difficultyID and not Garrison[instanceID] then
self.text:SetFormattedText('%s %s %s', GetLabelTexture(difficultyID), name, GetDiffIDLabel(difficultyID))
else
DungeonDifficultyID, RaidDifficultyID, LegacyRaidDifficultyID = GetDungeonDifficultyID(), GetRaidDifficultyID(), GetLegacyRaidDifficultyID()
self.text:SetFormattedText('%s %s %s %s %s %s', DungeonTexture, GetDiffIDLabel(DungeonDifficultyID), RaidTexture, GetDiffIDLabel(RaidDifficultyID), LegacyTexture, GetDiffIDLabel(LegacyRaidDifficultyID))
end
end
local function OnEnter()
if not (DungeonDifficultyID or RaidDifficultyID or LegacyRaidDifficultyID) then return end
DT.tooltip:ClearLines()
DT.tooltip:SetText(L["Current Difficulties:"])
DT.tooltip:AddLine(' ')
if DungeonDifficultyID then
DT.tooltip:AddLine(format('%s %s', DungeonTexture, DiffLabel[DungeonDifficultyID]), 1, 1, 1)
end
if RaidDifficultyID then
DT.tooltip:AddLine(format('%s %s', RaidTexture, DiffLabel[RaidDifficultyID]), 1, 1, 1)
end
if LegacyRaidDifficultyID then
DT.tooltip:AddLine(format('%s %s', LegacyTexture, DiffLabel[LegacyRaidDifficultyID]), 1, 1, 1)
end
DT.tooltip:Show()
end
DT:RegisterDatatext('Difficulty', nil, {'CHAT_MSG_SYSTEM', 'LOADING_SCREEN_DISABLED'}, OnEvent, nil, OnClick, OnEnter, nil, 'Difficulty')

View File

@@ -0,0 +1,87 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local select = select
local wipe = wipe
local format, pairs = format, pairs
local GetInventoryItemDurability = GetInventoryItemDurability
local ToggleCharacter = ToggleCharacter
local InCombatLockdown = InCombatLockdown
local GetInventoryItemTexture = GetInventoryItemTexture
local GetInventoryItemLink = GetInventoryItemLink
local GetMoneyString = GetMoneyString
local DURABILITY = DURABILITY
local REPAIR_COST = REPAIR_COST
local displayString = DURABILITY..': %s%d%%|r'
local tooltipString = '%d%%'
local totalDurability = 0
local invDurability = {}
local totalRepairCost
local slots = {
[1] = _G.INVTYPE_HEAD,
[3] = _G.INVTYPE_SHOULDER,
[5] = _G.INVTYPE_CHEST,
[6] = _G.INVTYPE_WAIST,
[7] = _G.INVTYPE_LEGS,
[8] = _G.INVTYPE_FEET,
[9] = _G.INVTYPE_WRIST,
[10] = _G.INVTYPE_HAND,
[16] = _G.INVTYPE_WEAPONMAINHAND,
[17] = _G.INVTYPE_WEAPONOFFHAND,
}
local function OnEvent(self)
totalDurability = 100
totalRepairCost = 0
wipe(invDurability)
for index in pairs(slots) do
local currentDura, maxDura = GetInventoryItemDurability(index)
if currentDura and maxDura > 0 then
local perc = (currentDura/maxDura)*100
invDurability[index] = perc
if perc < totalDurability then
totalDurability = perc
end
totalRepairCost = totalRepairCost + select(3, E.ScanTooltip:SetInventoryItem('player', index))
end
end
local r, g, b = E:ColorGradient(totalDurability * .01, 1, .1, .1, 1, 1, .1, .1, 1, .1)
local hex = E:RGBToHex(r, g, b)
self.text:SetFormattedText(displayString, hex, totalDurability)
if totalDurability <= E.global.datatexts.settings.Durability.percThreshold then
E:Flash(self, 0.53, true)
else
E:StopFlash(self)
end
end
local function Click()
if InCombatLockdown() then _G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT) return end
ToggleCharacter('PaperDollFrame')
end
local function OnEnter()
DT.tooltip:ClearLines()
for slot, durability in pairs(invDurability) do
DT.tooltip:AddDoubleLine(format('|T%s:14:14:0:0:64:64:4:60:4:60|t %s', GetInventoryItemTexture('player', slot), GetInventoryItemLink('player', slot)), format(tooltipString, durability), 1, 1, 1, E:ColorGradient(durability * 0.01, 1, .1, .1, 1, 1, .1, .1, 1, .1))
end
if totalRepairCost > 0 then
DT.tooltip:AddLine(' ')
DT.tooltip:AddDoubleLine(REPAIR_COST, GetMoneyString(totalRepairCost), .6, .8, 1, 1, 1, 1)
end
DT.tooltip:Show()
end
DT:RegisterDatatext('Durability', nil, {'UPDATE_INVENTORY_DURABILITY', 'MERCHANT_SHOW'}, OnEvent, nil, Click, OnEnter, nil, DURABILITY)

View File

@@ -0,0 +1,80 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local format = format
local UnitXP, UnitXPMax = UnitXP, UnitXPMax
local IsXPUserDisabled, GetXPExhaustion = IsXPUserDisabled, GetXPExhaustion
local IsPlayerAtEffectiveMaxLevel = IsPlayerAtEffectiveMaxLevel
local CurrentXP, XPToLevel, RestedXP, PercentRested
local PercentXP, RemainXP, RemainTotal, RemainBars
local function OnEvent(self)
local displayString = ''
if IsXPUserDisabled() then
displayString = L["Disabled"]
elseif IsPlayerAtEffectiveMaxLevel() then
displayString = L["Max Level"]
else
CurrentXP, XPToLevel, RestedXP = UnitXP('player'), UnitXPMax('player'), GetXPExhaustion()
if XPToLevel <= 0 then XPToLevel = 1 end
local remainXP = XPToLevel - CurrentXP
local remainPercent = remainXP / XPToLevel
-- values we also use in OnEnter
RemainTotal, RemainBars = remainPercent * 100, remainPercent * 20
PercentXP, RemainXP = (CurrentXP / XPToLevel) * 100, E:ShortValue(remainXP)
local textFormat = E.global.datatexts.settings.Experience.textFormat
if textFormat == 'PERCENT' then
displayString = format('%.2f%%', PercentXP)
elseif textFormat == 'CURMAX' then
displayString = format('%s - %s', E:ShortValue(CurrentXP), E:ShortValue(XPToLevel))
elseif textFormat == 'CURPERC' then
displayString = format('%s - %.2f%%', E:ShortValue(CurrentXP), PercentXP)
elseif textFormat == 'CUR' then
displayString = format('%s', E:ShortValue(CurrentXP))
elseif textFormat == 'REM' then
displayString = format('%s', RemainXP)
elseif textFormat == 'CURREM' then
displayString = format('%s - %s', E:ShortValue(CurrentXP), RemainXP)
elseif textFormat == 'CURPERCREM' then
displayString = format('%s - %.2f%% (%s)', E:ShortValue(CurrentXP), PercentXP, RemainXP)
end
if RestedXP and RestedXP > 0 then
PercentRested = (RestedXP / XPToLevel) * 100
if textFormat == 'PERCENT' then
displayString = format('%s R:%.2f%%', displayString, PercentRested)
elseif textFormat == 'CURPERC' then
displayString = format('%s R:%s [%.2f%%]', displayString, E:ShortValue(RestedXP), PercentRested)
elseif textFormat ~= 'NONE' then
displayString = format('%s R:%s', displayString, E:ShortValue(RestedXP))
end
end
end
self.text:SetText(displayString)
end
local function OnEnter()
if IsXPUserDisabled() or IsPlayerAtEffectiveMaxLevel() then return end
DT.tooltip:ClearLines()
DT.tooltip:AddLine(L["Experience"])
DT.tooltip:AddLine(' ')
DT.tooltip:AddDoubleLine(L["XP:"], format(' %d / %d (%.2f%%)', CurrentXP, XPToLevel, PercentXP), 1, 1, 1)
DT.tooltip:AddDoubleLine(L["Remaining:"], format(' %s (%.2f%% - %d '..L["Bars"]..')', RemainXP, RemainTotal, RemainBars), 1, 1, 1)
if RestedXP and RestedXP > 0 then
DT.tooltip:AddDoubleLine(L["Rested:"], format('+%d (%.2f%%)', RestedXP, PercentRested), 1, 1, 1)
end
DT.tooltip:Show()
end
DT:RegisterDatatext('Experience', nil, {'PLAYER_XP_UPDATE', 'DISABLE_XP_GAIN', 'ENABLE_XP_GAIN', 'UPDATE_EXHAUSTION'}, OnEvent, nil, nil, OnEnter, nil, _G.COMBAT_XP_GAIN)

View File

@@ -0,0 +1,589 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local type, ipairs, pairs, select = type, ipairs, pairs, select
local sort, next, wipe, tremove, tinsert = sort, next, wipe, tremove, tinsert
local format, gsub, strfind, strjoin, strmatch = format, gsub, strfind, strjoin, strmatch
local BNet_GetValidatedCharacterName = BNet_GetValidatedCharacterName
local GetMouseFocus = GetMouseFocus
local BNGetInfo = BNGetInfo
local BNGetNumFriends = BNGetNumFriends
local BNInviteFriend = BNInviteFriend
local BNRequestInviteFriend = BNRequestInviteFriend
local BNSetCustomMessage = BNSetCustomMessage
local GetDisplayedInviteType = GetDisplayedInviteType
local GetQuestDifficultyColor = GetQuestDifficultyColor
local IsChatAFK = IsChatAFK
local IsChatDND = IsChatDND
local IsAltKeyDown = IsAltKeyDown
local IsShiftKeyDown = IsShiftKeyDown
local SendChatMessage = SendChatMessage
local SetItemRef = SetItemRef
local ToggleFriendsFrame = ToggleFriendsFrame
local UnitInParty = UnitInParty
local UnitInRaid = UnitInRaid
local C_FriendList_GetNumFriends = C_FriendList.GetNumFriends
local C_FriendList_GetNumOnlineFriends = C_FriendList.GetNumOnlineFriends
local C_FriendList_GetFriendInfoByIndex = C_FriendList.GetFriendInfoByIndex
local ChatFrame_SendBNetTell = ChatFrame_SendBNetTell
local InCombatLockdown = InCombatLockdown
local C_BattleNet_GetFriendAccountInfo = C_BattleNet.GetFriendAccountInfo
local C_BattleNet_GetFriendNumGameAccounts = C_BattleNet.GetFriendNumGameAccounts
local C_BattleNet_GetFriendGameAccountInfo = C_BattleNet.GetFriendGameAccountInfo
local C_PartyInfo_RequestInviteFromUnit = C_PartyInfo.RequestInviteFromUnit
local C_PartyInfo_InviteUnit = C_PartyInfo.InviteUnit
local PRIEST_COLOR = RAID_CLASS_COLORS.PRIEST
-- create a popup
E.PopupDialogs.SET_BN_BROADCAST = {
text = _G.BN_BROADCAST_TOOLTIP,
button1 = _G.ACCEPT,
button2 = _G.CANCEL,
hasEditBox = 1,
editBoxWidth = 350,
maxLetters = 127,
OnAccept = function(self) BNSetCustomMessage(self.editBox:GetText()) end,
OnShow = function(self) self.editBox:SetText(select(4, BNGetInfo()) ) self.editBox:SetFocus() end,
OnHide = _G.ChatEdit_FocusActiveWindow,
EditBoxOnEnterPressed = function(self) BNSetCustomMessage(self:GetText()) self:GetParent():Hide() end,
EditBoxOnEscapePressed = function(self) self:GetParent():Hide() end,
timeout = 0,
exclusive = 1,
whileDead = 1,
hideOnEscape = 1,
preferredIndex = 3
}
local menuList = {
{ text = _G.OPTIONS_MENU, isTitle = true, notCheckable=true},
{ text = _G.INVITE, hasArrow = true, notCheckable=true, },
{ text = _G.CHAT_MSG_WHISPER_INFORM, hasArrow = true, notCheckable=true, },
{ text = _G.PLAYER_STATUS, hasArrow = true, notCheckable=true,
menuList = {
{ text = '|cff2BC226'.._G.AVAILABLE..'|r', notCheckable=true, func = function() if IsChatAFK() then SendChatMessage('', 'AFK') elseif IsChatDND() then SendChatMessage('', 'DND') end end },
{ text = '|cffE7E716'.._G.DND..'|r', notCheckable=true, func = function() if not IsChatDND() then SendChatMessage('', 'DND') end end },
{ text = '|cffFF0000'.._G.AFK..'|r', notCheckable=true, func = function() if not IsChatAFK() then SendChatMessage('', 'AFK') end end },
},
},
{ text = _G.BN_BROADCAST_TOOLTIP, notCheckable=true, func = function() E:StaticPopup_Show('SET_BN_BROADCAST') end },
}
local function inviteClick(_, name, guid)
DT.EasyMenu:Hide()
if not (name and name ~= '') then return end
local isBNet = type(name) == 'number'
if guid then
local inviteType = GetDisplayedInviteType(guid)
if inviteType == 'INVITE' or inviteType == 'SUGGEST_INVITE' then
if isBNet then
BNInviteFriend(name)
else
C_PartyInfo_InviteUnit(name)
end
elseif inviteType == 'REQUEST_INVITE' then
if isBNet then
BNRequestInviteFriend(name)
else
C_PartyInfo_RequestInviteFromUnit(name)
end
end
else
-- if for some reason guid isnt here fallback and just try to invite them
-- this is unlikely but having a fallback doesnt hurt
if isBNet then
BNInviteFriend(name)
else
C_PartyInfo_InviteUnit(name)
end
end
end
local function whisperClick(_, name, battleNet)
DT.EasyMenu:Hide()
if battleNet then
ChatFrame_SendBNetTell(name)
else
SetItemRef( 'player:'..name, format('|Hplayer:%1$s|h[%1$s]|h',name), 'LeftButton' )
end
end
local levelNameString = '|cff%02x%02x%02x%d|r |cff%02x%02x%02x%s|r'
local levelNameClassString = '|cff%02x%02x%02x%d|r %s%s%s'
local characterFriend = _G.CHARACTER_FRIEND
local battleNetString = _G.BATTLENET_OPTIONS_LABEL
local totalOnlineString = strjoin('', _G.FRIENDS_LIST_ONLINE, ': %s/%s')
local tthead = {r=0.4, g=0.78, b=1}
local activezone, inactivezone = {r=0.3, g=1.0, b=0.3}, {r=0.65, g=0.65, b=0.65}
local displayString = ''
local friendTable, BNTable, tableList = {}, {}, {}
local friendOnline, friendOffline = gsub(_G.ERR_FRIEND_ONLINE_SS,'\124Hplayer:%%s\124h%[%%s%]\124h',''), gsub(_G.ERR_FRIEND_OFFLINE_S,'%%s','')
local wowString = _G.BNET_CLIENT_WOW
local retailID = _G.WOW_PROJECT_ID
local WOW_CLASSIC = _G.BNET_FRIEND_TOOLTIP_WOW_CLASSIC
local dataValid, lastPanel = false
local statusTable = {
AFK = ' |cffFFFFFF[|r|cffFF9900'..L["AFK"]..'|r|cffFFFFFF]|r',
DND = ' |cffFFFFFF[|r|cffFF3333'..L["DND"]..'|r|cffFFFFFF]|r'
}
-- Makro for get the client: /run for i,v in pairs(_G) do if type(i)=='string' and i:match('BNET_CLIENT_') then print(i,'=',v) end end
local clientSorted = {}
local clientTags = {
[_G.BNET_CLIENT_WOW] = 'WoW',
[_G.BNET_CLIENT_D3] = 'D3',
[_G.BNET_CLIENT_WTCG] = 'HS',
[_G.BNET_CLIENT_HEROES] = 'HotS',
[_G.BNET_CLIENT_OVERWATCH] = 'OW',
[_G.BNET_CLIENT_SC] = 'SC',
[_G.BNET_CLIENT_SC2] = 'SC2',
[_G.BNET_CLIENT_COD] = 'BO4',
[_G.BNET_CLIENT_COD_MW] = 'MW',
[_G.BNET_CLIENT_COD_MW2] = 'MW2',
[_G.BNET_CLIENT_COD_BOCW] = 'CW',
BSAp = L["Mobile"],
}
local clientIndex = {
[_G.BNET_CLIENT_WOW] = 1,
[_G.BNET_CLIENT_D3] = 2,
[_G.BNET_CLIENT_WTCG] = 3,
[_G.BNET_CLIENT_HEROES] = 4,
[_G.BNET_CLIENT_OVERWATCH] = 5,
[_G.BNET_CLIENT_SC] = 6,
[_G.BNET_CLIENT_SC2] = 7,
[_G.BNET_CLIENT_COD] = 8,
[_G.BNET_CLIENT_COD_MW] = 9,
[_G.BNET_CLIENT_COD_MW2] = 10,
[_G.BNET_CLIENT_COD_BOCW] = 11,
App = 12,
BSAp = 13,
}
local function inGroup(name, realmName)
if realmName and realmName ~= '' and realmName ~= E.myrealm then
name = name..'-'..realmName
end
return (UnitInParty(name) or UnitInRaid(name)) and '|cffaaaaaa*|r' or ''
end
local function SortAlphabeticName(a, b)
if a.name and b.name then
return a.name < b.name
end
end
local function BuildFriendTable(total)
wipe(friendTable)
for i = 1, total do
local info = C_FriendList_GetFriendInfoByIndex(i)
if info and info.connected then
local className = E:UnlocalizedClassName(info.className) or ''
local status = (info.afk and statusTable.AFK) or (info.dnd and statusTable.DND) or ''
friendTable[i] = {
name = info.name, --1
level = info.level, --2
class = className, --3
zone = info.area, --4
online = info.connected, --5
status = status, --6
notes = info.notes, --7
guid = info.guid --8
}
end
end
if next(friendTable) then
sort(friendTable, SortAlphabeticName)
end
end
--Sort: client-> (WoW: project-> faction-> name) ELSE:btag
local function Sort(a, b)
if a.client and b.client then
if (a.client == b.client) then
if (a.client == wowString) and a.wowProjectID and b.wowProjectID then
if (a.wowProjectID == b.wowProjectID) and a.faction and b.faction then
if (a.faction == b.faction) and a.characterName and b.characterName then
return a.characterName < b.characterName
end
return a.faction < b.faction
end
return a.wowProjectID < b.wowProjectID
elseif (a.battleTag and b.battleTag) then
return a.battleTag < b.battleTag
end
end
return a.client < b.client
end
end
--Sort client by statically given index (this is a `pairs by keys` sorting method)
local function clientSort(a, b)
if a and b then
if clientIndex[a] and clientIndex[b] then
return clientIndex[a] < clientIndex[b]
end
return a < b
end
end
local function AddToBNTable(bnIndex, bnetIDAccount, accountName, battleTag, characterName, bnetIDGameAccount, client, isOnline, isBnetAFK, isBnetDND, noteText, wowProjectID, realmName, faction, race, className, zoneName, level, guid, gameText)
className = E:UnlocalizedClassName(className) or ''
characterName = BNet_GetValidatedCharacterName(characterName, battleTag, client) or ''
local obj = {
accountID = bnetIDAccount, --1
accountName = accountName, --2
battleTag = battleTag, --3
characterName = characterName, --4
gameID = bnetIDGameAccount, --5
client = client, --6
isOnline = isOnline, --7
isBnetAFK = isBnetAFK, --8
isBnetDND = isBnetDND, --9
noteText = noteText, --10
wowProjectID = wowProjectID, --11
realmName = realmName, --12
faction = faction, --13
race = race, --14
className = className, --15
zoneName = zoneName, --16
level = level, --17
guid = guid, --18
gameText = gameText --19
}
if strmatch(gameText, WOW_CLASSIC) then
obj.classicText, obj.realmName = strmatch(gameText, '(.-)%s%-%s(.+)')
end
BNTable[bnIndex] = obj
if tableList[client] then
tableList[client][#tableList[client]+1] = BNTable[bnIndex]
else
tableList[client] = {}
tableList[client][1] = BNTable[bnIndex]
end
end
local function PopulateBNTable(bnIndex, bnetIDAccount, accountName, battleTag, characterName, bnetIDGameAccount, client, isOnline, isBnetAFK, isBnetDND, noteText, wowProjectID, realmName, faction, race, class, zoneName, level, guid, gameText, hasFocus)
-- `hasFocus` is not added to BNTable[i]; we only need this to keep our friends datatext in sync with the friends list
for i = 1, bnIndex do
local isAdded, bnInfo = 0, BNTable[i]
if bnInfo and (bnInfo.accountID == bnetIDAccount) then
if bnInfo.client == 'BSAp' then
if client == 'BSAp' then -- unlikely to happen
isAdded = 1
elseif client == 'App' then
isAdded = (hasFocus and 2) or 1
else -- Mobile -> Game
isAdded = 2 --swap data
end
elseif bnInfo.client == 'App' then
if client == 'App' then -- unlikely to happen
isAdded = 1
elseif client == 'BSAp' then
isAdded = (hasFocus and 2) or 1
else -- App -> Game
isAdded = 2 --swap data
end
elseif bnInfo.client then -- Game
if client == 'BSAp' or client == 'App' then -- ignore Mobile and App
isAdded = 1
end
end
end
if isAdded == 2 then -- swap data
if bnInfo.client and tableList[bnInfo.client] then
for n, y in ipairs(tableList[bnInfo.client]) do
if y == bnInfo then
tremove(tableList[bnInfo.client], n)
break -- remove the old one from tableList
end
end
end
AddToBNTable(i, bnetIDAccount, accountName, battleTag, characterName, bnetIDGameAccount, client, isOnline, isBnetAFK, isBnetDND, noteText, wowProjectID, realmName, faction, race, class, zoneName, level, guid, gameText)
end
if isAdded ~= 0 then
return bnIndex
end
end
bnIndex = bnIndex + 1 --bump the index one for a new addition
AddToBNTable(bnIndex, bnetIDAccount, accountName, battleTag, characterName, bnetIDGameAccount, client, isOnline, isBnetAFK, isBnetDND, noteText, wowProjectID, realmName, faction, race, class, zoneName, level, guid, gameText)
return bnIndex
end
local function BuildBNTable(total)
for _, v in pairs(tableList) do wipe(v) end
wipe(BNTable)
wipe(clientSorted)
local bnIndex = 0
for i = 1, total do
local accountInfo = C_BattleNet_GetFriendAccountInfo(i)
if accountInfo and accountInfo.gameAccountInfo and accountInfo.gameAccountInfo.isOnline then
local numGameAccounts = C_BattleNet_GetFriendNumGameAccounts(i)
if numGameAccounts and numGameAccounts > 0 then
for y = 1, numGameAccounts do
local gameAccountInfo = C_BattleNet_GetFriendGameAccountInfo(i, y)
bnIndex = PopulateBNTable(bnIndex, accountInfo.bnetAccountID, accountInfo.accountName, accountInfo.battleTag, gameAccountInfo.characterName, gameAccountInfo.gameAccountID, gameAccountInfo.clientProgram, gameAccountInfo.isOnline, accountInfo.isAFK or gameAccountInfo.isGameAFK, accountInfo.isDND or gameAccountInfo.isGameBusy, accountInfo.note, accountInfo.gameAccountInfo.wowProjectID, gameAccountInfo.realmName, gameAccountInfo.factionName, gameAccountInfo.raceName, gameAccountInfo.className, gameAccountInfo.areaName, gameAccountInfo.characterLevel, gameAccountInfo.playerGuid, gameAccountInfo.richPresence, gameAccountInfo.hasFocus)
end
else
bnIndex = PopulateBNTable(bnIndex, accountInfo.bnetAccountID, accountInfo.accountName, accountInfo.battleTag, accountInfo.gameAccountInfo.characterName, accountInfo.gameAccountInfo.gameAccountID, accountInfo.gameAccountInfo.clientProgram, accountInfo.gameAccountInfo.isOnline, accountInfo.isAFK, accountInfo.isDND, accountInfo.note, accountInfo.gameAccountInfo.wowProjectID)
end
end
end
if next(BNTable) then
sort(BNTable, Sort)
end
for c, v in pairs(tableList) do
if next(v) then
sort(v, Sort)
end
tinsert(clientSorted, c)
end
if next(clientSorted) then
sort(clientSorted, clientSort)
end
end
local function Click(self, btn)
if btn == 'RightButton' then
local menuCountWhispers = 0
local menuCountInvites = 0
menuList[2].menuList = {}
menuList[3].menuList = {}
if not E.global.datatexts.settings.Friends.hideWoW then
for _, info in ipairs(friendTable) do
if info.online then
local shouldSkip = false
if (info.status == statusTable.AFK) and E.global.datatexts.settings.Friends.hideAFK then
shouldSkip = true
elseif (info.status == statusTable.DND) and E.global.datatexts.settings.Friends.hideDND then
shouldSkip = true
end
if not shouldSkip then
local classc, levelc = E:ClassColor(info.class), GetQuestDifficultyColor(info.level)
if not classc then classc = levelc end
menuCountWhispers = menuCountWhispers + 1
menuList[3].menuList[menuCountWhispers] = {text = format(levelNameString,levelc.r*255,levelc.g*255,levelc.b*255,info.level,classc.r*255,classc.g*255,classc.b*255,info.name), arg1 = info.name, notCheckable=true, func = whisperClick}
if inGroup(info.name) == '' then
menuCountInvites = menuCountInvites + 1
menuList[2].menuList[menuCountInvites] = {text = format(levelNameString,levelc.r*255,levelc.g*255,levelc.b*255,info.level,classc.r*255,classc.g*255,classc.b*255,info.name), arg1 = info.name, arg2 = info.guid, notCheckable=true, func = inviteClick}
end
end
end
end
end
for _, info in ipairs(BNTable) do
if info.isOnline then
local shouldSkip = false
if (info.isBnetAFK == true) and E.global.datatexts.settings.Friends.hideAFK then
shouldSkip = true
elseif (info.isBnetDND == true) and E.global.datatexts.settings.Friends.hideDND then
shouldSkip = true
end
if info.client and E.global.datatexts.settings.Friends['hide'..info.client] then
shouldSkip = true
end
if not shouldSkip then
local realID, hasBnet = info.accountName, false
for _, z in ipairs(menuList[3].menuList) do
if z and z.text and (z.text == realID) then
hasBnet = true
break
end
end
if not hasBnet then -- hasBnet will make sure only one is added to whispers but still allow us to add multiple into invites
menuCountWhispers = menuCountWhispers + 1
menuList[3].menuList[menuCountWhispers] = {text = realID, arg1 = realID, arg2 = true, notCheckable=true, func = whisperClick}
end
if (info.client and info.client == wowString) and (E.myfaction == info.faction) and inGroup(info.characterName, info.realmName) == '' then
local classc, levelc = E:ClassColor(info.className), GetQuestDifficultyColor(info.level)
if not classc then classc = levelc end
if info.wowProjectID == retailID then
menuCountInvites = menuCountInvites + 1
menuList[2].menuList[menuCountInvites] = {text = format(levelNameString,levelc.r*255,levelc.g*255,levelc.b*255,info.level,classc.r*255,classc.g*255,classc.b*255,info.characterName), arg1 = info.gameID, arg2 = info.guid, notCheckable=true, func = inviteClick}
end
end
end
end
end
DT:SetEasyMenuAnchor(DT.EasyMenu, self)
_G.EasyMenu(menuList, DT.EasyMenu, nil, nil, nil, 'MENU')
elseif InCombatLockdown() then
_G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT)
else
ToggleFriendsFrame(1)
end
end
local lastTooltipXLineHeader
local function TooltipAddXLine(X, header, ...)
X = (X == true and 'AddDoubleLine') or 'AddLine'
if lastTooltipXLineHeader ~= header then
DT.tooltip[X](DT.tooltip, ' ')
DT.tooltip[X](DT.tooltip, header)
lastTooltipXLineHeader = header
end
DT.tooltip[X](DT.tooltip, ...)
end
local function OnEnter()
DT.tooltip:ClearLines()
lastTooltipXLineHeader = nil
local onlineFriends = C_FriendList_GetNumOnlineFriends()
local numberOfFriends = C_FriendList_GetNumFriends()
local totalBNet, numBNetOnline = BNGetNumFriends()
local totalonline = onlineFriends + numBNetOnline
-- no friends online, quick exit
if totalonline == 0 then return end
if not dataValid then
-- only retrieve information for all on-line members when we actually view the tooltip
if numberOfFriends > 0 then BuildFriendTable(numberOfFriends) end
if totalBNet > 0 then BuildBNTable(totalBNet) end
dataValid = true
end
local totalfriends = numberOfFriends + totalBNet
local zonec, classc, levelc, realmc
local shiftDown = IsShiftKeyDown()
DT.tooltip:AddDoubleLine(L["Friends List"], format(totalOnlineString, totalonline, totalfriends),tthead.r,tthead.g,tthead.b,tthead.r,tthead.g,tthead.b)
if (onlineFriends > 0) and not E.global.datatexts.settings.Friends.hideWoW then
for _, info in ipairs(friendTable) do
if info.online then
local shouldSkip = false
if (info.status == statusTable.AFK) and E.global.datatexts.settings.Friends.hideAFK then
shouldSkip = true
elseif (info.status == statusTable.DND) and E.global.datatexts.settings.Friends.hideDND then
shouldSkip = true
end
if not shouldSkip then
if E.MapInfo.zoneText and (E.MapInfo.zoneText == info.zone) then zonec = activezone else zonec = inactivezone end
classc, levelc = E:ClassColor(info.class), GetQuestDifficultyColor(info.level)
if not classc then classc = levelc end
TooltipAddXLine(true, characterFriend, format(levelNameClassString,levelc.r*255,levelc.g*255,levelc.b*255,info.level,info.name,inGroup(info.name),info.status),info.zone,classc.r,classc.g,classc.b,zonec.r,zonec.g,zonec.b)
end
end
end
end
if numBNetOnline > 0 then
local status
for _, client in ipairs(clientSorted) do
local Table = tableList[client]
local shouldSkip = E.global.datatexts.settings.Friends['hide'..client]
if not shouldSkip then
for _, info in ipairs(Table) do
if info.isOnline then
shouldSkip = false
if info.isBnetAFK == true then
if E.global.datatexts.settings.Friends.hideAFK then
shouldSkip = true
end
status = statusTable.AFK
elseif info.isBnetDND == true then
if E.global.datatexts.settings.Friends.hideDND then
shouldSkip = true
end
status = statusTable.DND
else
status = ''
end
if not shouldSkip then
local header = format('%s (%s)', battleNetString, info.classicText or clientTags[client] or client)
if info.client and info.client == wowString then
classc = E:ClassColor(info.className)
if info.level and info.level ~= '' then
levelc = GetQuestDifficultyColor(info.level)
else
classc, levelc = PRIEST_COLOR, PRIEST_COLOR
end
--Sometimes the friend list is fubar with level 0 unknown friends
if not classc then classc = PRIEST_COLOR end
TooltipAddXLine(true, header, format(levelNameString..'%s%s',levelc.r*255,levelc.g*255,levelc.b*255,info.level,classc.r*255,classc.g*255,classc.b*255,info.characterName,inGroup(info.characterName, info.realmName),status),info.accountName,238,238,238,238,238,238)
if shiftDown then
if E.MapInfo.zoneText and (E.MapInfo.zoneText == info.zoneName) then zonec = activezone else zonec = inactivezone end
if E.myrealm == info.realmName then realmc = activezone else realmc = inactivezone end
TooltipAddXLine(true, header, info.zoneName, info.realmName, zonec.r, zonec.g, zonec.b, realmc.r, realmc.g, realmc.b)
end
else
TooltipAddXLine(true, header, info.characterName..status, info.accountName, .9, .9, .9, .9, .9, .9)
if shiftDown and (info.gameText and info.gameText ~= '') and (info.client and info.client ~= 'App' and info.client ~= 'BSAp') then
TooltipAddXLine(false, header, info.gameText, inactivezone.r, inactivezone.g, inactivezone.b)
end
end
end
end
end
end
end
end
DT.tooltip:Show()
end
local function OnEvent(self, event, message)
local onlineFriends = C_FriendList_GetNumOnlineFriends()
local _, numBNetOnline = BNGetNumFriends()
-- special handler to detect friend coming online or going offline
-- when this is the case, we invalidate our buffered table and update the
-- datatext information
if event == 'CHAT_MSG_SYSTEM' then
if not (strfind(message, friendOnline) or strfind(message, friendOffline)) then return end
end
-- force update when showing tooltip
dataValid = false
if not IsAltKeyDown() and event == 'MODIFIER_STATE_CHANGED' and GetMouseFocus() == self then
OnEnter(self)
end
if E.global.datatexts.settings.Friends.NoLabel then
self.text:SetFormattedText(displayString, onlineFriends + numBNetOnline)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Friends.Label ~= '' and E.global.datatexts.settings.Friends.Label or _G.FRIENDS..': ', onlineFriends + numBNetOnline)
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Friends.NoLabel and '' or '%s', hex, '%d|r')
if lastPanel then
OnEvent(lastPanel, 'ELVUI_COLOR_UPDATE')
end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Friends', _G.SOCIAL_LABEL, {'BN_FRIEND_ACCOUNT_ONLINE', 'BN_FRIEND_ACCOUNT_OFFLINE', 'BN_FRIEND_INFO_CHANGED', 'FRIENDLIST_UPDATE', 'CHAT_MSG_SYSTEM', 'MODIFIER_STATE_CHANGED'}, OnEvent, nil, Click, OnEnter, nil, _G.FRIENDS, nil, ValueColorUpdate)

209
Modules/DataTexts/Gold.lua Normal file
View File

@@ -0,0 +1,209 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local type, wipe, pairs, ipairs, sort = type, wipe, pairs, ipairs, sort
local format, strjoin, tinsert = format, strjoin, tinsert
local GetMoney = GetMoney
local IsControlKeyDown = IsControlKeyDown
local IsLoggedIn = IsLoggedIn
local IsShiftKeyDown = IsShiftKeyDown
local C_WowTokenPublic_UpdateMarketPrice = C_WowTokenPublic.UpdateMarketPrice
local C_WowTokenPublic_GetCurrentMarketPrice = C_WowTokenPublic.GetCurrentMarketPrice
local C_Timer_NewTicker = C_Timer.NewTicker
local BreakUpLargeNumbers = BreakUpLargeNumbers
-- GLOBALS: ElvDB
local Ticker
local CURRENCY = CURRENCY
local MAX_WATCHED_TOKENS = MAX_WATCHED_TOKENS
local Profit, Spent = 0, 0
local resetCountersFormatter = strjoin('', '|cffaaaaaa', L["Reset Session Data: Hold Ctrl + Right Click"], '|r')
local resetInfoFormatter = strjoin('', '|cffaaaaaa', L["Reset Character Data: Hold Shift + Right Click"], '|r')
local PRIEST_COLOR = RAID_CLASS_COLORS.PRIEST
local C_CurrencyInfo_GetBackpackCurrencyInfo = C_CurrencyInfo.GetBackpackCurrencyInfo
local iconString = '|T%s:16:16:0:0:64:64:4:60:4:60|t'
local menuList = {}
local function sortFunction(a, b)
return a.amount > b.amount
end
local function OnEvent(self)
if not IsLoggedIn() then return end
if not Ticker then
C_WowTokenPublic_UpdateMarketPrice()
Ticker = C_Timer_NewTicker(60, C_WowTokenPublic_UpdateMarketPrice)
end
ElvDB = ElvDB or {}
ElvDB.gold = ElvDB.gold or {}
ElvDB.gold[E.myrealm] = ElvDB.gold[E.myrealm] or {}
ElvDB.class = ElvDB.class or {}
ElvDB.class[E.myrealm] = ElvDB.class[E.myrealm] or {}
ElvDB.class[E.myrealm][E.myname] = E.myclass
ElvDB.faction = ElvDB.faction or {}
ElvDB.faction[E.myrealm] = ElvDB.faction[E.myrealm] or {}
ElvDB.faction[E.myrealm][E.myname] = E.myfaction
ElvDB.serverID = ElvDB.serverID or {}
ElvDB.serverID[E.serverID] = ElvDB.serverID[E.serverID] or {}
ElvDB.serverID[E.serverID][E.myrealm] = true
--prevent an error possibly from really old profiles
local oldMoney = ElvDB.gold[E.myrealm][E.myname]
if oldMoney and type(oldMoney) ~= 'number' then
ElvDB.gold[E.myrealm][E.myname] = nil
oldMoney = nil
end
local NewMoney = GetMoney()
ElvDB.gold[E.myrealm][E.myname] = NewMoney
local OldMoney = oldMoney or NewMoney
local Change = NewMoney-OldMoney -- Positive if we gain money
if OldMoney>NewMoney then -- Lost Money
Spent = Spent - Change
else -- Gained Moeny
Profit = Profit + Change
end
self.text:SetText(E:FormatMoney(NewMoney, E.global.datatexts.settings.Gold.goldFormat or "BLIZZARD", not E.global.datatexts.settings.Gold.goldCoins))
end
local function deleteCharacter(self, realm, name)
ElvDB.gold[realm][name] = nil
ElvDB.class[realm][name] = nil
ElvDB.faction[realm][name] = nil
if name == E.myname and realm == E.myrealm then
OnEvent(self)
end
end
local function Click(self, btn)
if btn == 'RightButton' then
if IsShiftKeyDown() then
wipe(menuList)
tinsert(menuList, { text = 'Delete Character', isTitle = true, notCheckable = true })
for realm in pairs(ElvDB.serverID[E.serverID]) do
for name in pairs(ElvDB.gold[realm]) do
tinsert(menuList, {
text = format('%s - %s', name, realm),
notCheckable = true,
func = function()
deleteCharacter(self, realm, name)
end
})
end
end
DT:SetEasyMenuAnchor(DT.EasyMenu, self)
_G.EasyMenu(menuList, DT.EasyMenu, nil, nil, nil, 'MENU')
elseif IsControlKeyDown() then
Profit = 0
Spent = 0
end
else
_G.ToggleAllBags()
end
end
local myGold = {}
local function OnEnter()
DT.tooltip:ClearLines()
local textOnly = not E.global.datatexts.settings.Gold.goldCoins and true or false
local style = E.global.datatexts.settings.Gold.goldFormat or 'BLIZZARD'
DT.tooltip:AddLine(L["Session:"])
DT.tooltip:AddDoubleLine(L["Earned:"], E:FormatMoney(Profit, style, textOnly), 1, 1, 1, 1, 1, 1)
DT.tooltip:AddDoubleLine(L["Spent:"], E:FormatMoney(Spent, style, textOnly), 1, 1, 1, 1, 1, 1)
if Profit < Spent then
DT.tooltip:AddDoubleLine(L["Deficit:"], E:FormatMoney(Profit-Spent, style, textOnly), 1, 0, 0, 1, 1, 1)
elseif (Profit-Spent)>0 then
DT.tooltip:AddDoubleLine(L["Profit:"], E:FormatMoney(Profit-Spent, style, textOnly), 0, 1, 0, 1, 1, 1)
end
DT.tooltip:AddLine(' ')
local totalGold, totalHorde, totalAlliance = 0, 0, 0
DT.tooltip:AddLine(L["Character: "])
wipe(myGold)
for realm in pairs(ElvDB.serverID[E.serverID]) do
for k, _ in pairs(ElvDB.gold[realm]) do
if ElvDB.gold[realm][k] then
local color = E:ClassColor(ElvDB.class[realm][k]) or PRIEST_COLOR
tinsert(myGold,
{
name = k,
realm = realm,
amount = ElvDB.gold[realm][k],
amountText = E:FormatMoney(ElvDB.gold[realm][k], style, textOnly),
faction = ElvDB.faction[realm][k] or '',
r = color.r, g = color.g, b = color.b,
}
)
end
if ElvDB.faction[realm][k] == 'Alliance' then
totalAlliance = totalAlliance+ElvDB.gold[realm][k]
elseif ElvDB.faction[realm][k] == 'Horde' then
totalHorde = totalHorde+ElvDB.gold[realm][k]
end
totalGold = totalGold+ElvDB.gold[realm][k]
end
end
sort(myGold, sortFunction)
for _, g in ipairs(myGold) do
local nameLine = ''
if g.faction ~= '' and g.faction ~= 'Neutral' then
nameLine = format('|TInterface/FriendsFrame/PlusManz-%s:14|t ', g.faction)
end
local toonName = format('%s%s%s', nameLine, g.name, (g.realm and g.realm ~= E.myrealm and ' - '..g.realm) or '')
DT.tooltip:AddDoubleLine((g.name == E.myname and toonName..' |TInterface/COMMON/Indicator-Green:14|t') or toonName, g.amountText, g.r, g.g, g.b, 1, 1, 1)
end
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(L["Server: "])
if totalAlliance > 0 and totalHorde > 0 then
if totalAlliance ~= 0 then DT.tooltip:AddDoubleLine(L["Alliance: "], E:FormatMoney(totalAlliance, style, textOnly), 0, .376, 1, 1, 1, 1) end
if totalHorde ~= 0 then DT.tooltip:AddDoubleLine(L["Horde: "], E:FormatMoney(totalHorde, style, textOnly), 1, .2, .2, 1, 1, 1) end
DT.tooltip:AddLine(' ')
end
DT.tooltip:AddDoubleLine(L["Total: "], E:FormatMoney(totalGold, style, textOnly), 1, 1, 1, 1, 1, 1)
DT.tooltip:AddLine(' ')
DT.tooltip:AddDoubleLine(L["WoW Token:"], E:FormatMoney(C_WowTokenPublic_GetCurrentMarketPrice() or 0, style, textOnly), 0, .8, 1, 1, 1, 1)
for i = 1, MAX_WATCHED_TOKENS do
local info = C_CurrencyInfo_GetBackpackCurrencyInfo(i)
if info then
if i == 1 then
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(CURRENCY)
end
if info.quantity then
DT.tooltip:AddDoubleLine(format('%s %s', format(iconString, info.iconFileID), info.name), BreakUpLargeNumbers(info.quantity), 1, 1, 1, 1, 1, 1)
end
end
end
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(resetCountersFormatter)
DT.tooltip:AddLine(resetInfoFormatter)
DT.tooltip:Show()
end
DT:RegisterDatatext('Gold', nil, {'PLAYER_MONEY', 'SEND_MAIL_MONEY_CHANGED', 'SEND_MAIL_COD_CHANGED', 'PLAYER_TRADE_MONEY', 'TRADE_MONEY_CHANGED'}, OnEvent, nil, Click, OnEnter, nil, L["Gold"])

318
Modules/DataTexts/Guild.lua Normal file
View File

@@ -0,0 +1,318 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local ipairs, select, sort, unpack, wipe, ceil = ipairs, select, sort, unpack, wipe, ceil
local format, strfind, strjoin, strsplit, strmatch = format, strfind, strjoin, strsplit, strmatch
local GetDisplayedInviteType = GetDisplayedInviteType
local GetGuildFactionInfo = GetGuildFactionInfo
local GetGuildInfo = GetGuildInfo
local GetGuildRosterInfo = GetGuildRosterInfo
local GetGuildRosterMOTD = GetGuildRosterMOTD
local GetMouseFocus = GetMouseFocus
local GetNumGuildApplicants = GetNumGuildApplicants
local GetNumGuildMembers = GetNumGuildMembers
local GetQuestDifficultyColor = GetQuestDifficultyColor
local C_GuildInfo_GuildRoster = C_GuildInfo.GuildRoster
local IsInGuild = IsInGuild
local IsShiftKeyDown = IsShiftKeyDown
local LoadAddOn = LoadAddOn
local SetItemRef = SetItemRef
local ToggleGuildFrame = ToggleGuildFrame
local UnitInParty = UnitInParty
local UnitInRaid = UnitInRaid
local InCombatLockdown = InCombatLockdown
local IsAltKeyDown = IsAltKeyDown
local C_PartyInfo_InviteUnit = C_PartyInfo.InviteUnit
local C_PartyInfo_RequestInviteFromUnit = C_PartyInfo.RequestInviteFromUnit
local COMBAT_FACTION_CHANGE = COMBAT_FACTION_CHANGE
local REMOTE_CHAT = REMOTE_CHAT
local GUILD_MOTD = GUILD_MOTD
local GUILD = GUILD
local tthead, ttsubh, ttoff = {r=0.4, g=0.78, b=1}, {r=0.75, g=0.9, b=1}, {r=.3,g=1,b=.3}
local activezone, inactivezone = {r=0.3, g=1.0, b=0.3}, {r=0.65, g=0.65, b=0.65}
local displayString = ''
local noGuildString = ''
local guildInfoString = '%s'
local guildInfoString2 = GUILD..': %d/%d'
local guildMotDString = '%s |cffaaaaaa- |cffffffff%s'
local levelNameString = '|cff%02x%02x%02x%d|r |cff%02x%02x%02x%s|r'
local levelNameStatusString = '|cff%02x%02x%02x%d|r %s%s %s'
local nameRankString = '%s |cff999999-|cffffffff %s'
local standingString = E:RGBToHex(ttsubh.r, ttsubh.g, ttsubh.b)..'%s:|r |cFFFFFFFF%s/%s (%s%%)'
local moreMembersOnlineString = strjoin('', '+ %d ', _G.FRIENDS_LIST_ONLINE, '...')
local noteString = strjoin('', '|cff999999 ', _G.LABEL_NOTE, ':|r %s')
local officerNoteString = strjoin('', '|cff999999 ', _G.GUILD_RANK1_DESC, ':|r %s')
local guildTable, guildMotD, lastPanel = {}, ''
local function sortByRank(a, b)
if a and b then
if a.rankIndex == b.rankIndex then
return a.name < b.name
end
return a.rankIndex < b.rankIndex
end
end
local function sortByName(a, b)
if a and b then
return a.name < b.name
end
end
local function SortGuildTable(shift)
if shift then
sort(guildTable, sortByRank)
else
sort(guildTable, sortByName)
end
end
local onlinestatusstring = '|cffFFFFFF[|r|cffFF0000%s|r|cffFFFFFF]|r'
local onlinestatus = {
[0] = '',
[1] = format(onlinestatusstring, L["AFK"]),
[2] = format(onlinestatusstring, L["DND"]),
}
local mobilestatus = {
[0] = [[|TInterface\ChatFrame\UI-ChatIcon-ArmoryChat:14:14:0:0:16:16:0:16:0:16:73:177:73|t]],
[1] = [[|TInterface\ChatFrame\UI-ChatIcon-ArmoryChat-AwayMobile:14:14:0:0:16:16:0:16:0:16|t]],
[2] = [[|TInterface\ChatFrame\UI-ChatIcon-ArmoryChat-BusyMobile:14:14:0:0:16:16:0:16:0:16|t]],
}
local function inGroup(name)
return (UnitInParty(name) or UnitInRaid(name)) and '|cffaaaaaa*|r' or ''
end
local function BuildGuildTable()
wipe(guildTable)
local totalMembers = GetNumGuildMembers()
for i = 1, totalMembers do
local name, rank, rankIndex, level, _, zone, note, officerNote, connected, memberstatus, className, _, _, isMobile, _, _, guid = GetGuildRosterInfo(i)
if not name then return end
local statusInfo = isMobile and mobilestatus[memberstatus] or onlinestatus[memberstatus]
zone = (isMobile and not connected) and REMOTE_CHAT or zone
if connected or isMobile then
guildTable[#guildTable + 1] = {
name = E:StripMyRealm(name), --1
rank = rank, --2
level = level, --3
zone = zone, --4
note = note, --5
officerNote = officerNote, --6
online = connected, --7
status = statusInfo, --8
class = className, --9
rankIndex = rankIndex, --10
isMobile = isMobile, --11
guid = guid --12
}
end
end
end
local function UpdateGuildMessage()
guildMotD = GetGuildRosterMOTD()
end
local FRIEND_ONLINE = select(2, strsplit(' ', _G.ERR_FRIEND_ONLINE_SS, 2))
local resendRequest = false
local eventHandlers = {
PLAYER_GUILD_UPDATE = C_GuildInfo_GuildRoster,
CHAT_MSG_SYSTEM = function(_, arg1)
if FRIEND_ONLINE ~= nil and arg1 and strfind(arg1, FRIEND_ONLINE) then
resendRequest = true
end
end,
-- when we enter the world and guildframe is not available then
-- load guild frame, update guild message and guild xp
PLAYER_ENTERING_WORLD = function()
if not _G.GuildFrame and IsInGuild() then
LoadAddOn('Blizzard_GuildUI')
C_GuildInfo_GuildRoster()
end
end,
-- Guild Roster updated, so rebuild the guild table
GUILD_ROSTER_UPDATE = function(self)
if resendRequest then
resendRequest = false
return C_GuildInfo_GuildRoster()
else
BuildGuildTable()
UpdateGuildMessage()
if GetMouseFocus() == self then
self:GetScript('OnEnter')(self, nil, true)
end
end
end,
-- our guild message of the day changed
GUILD_MOTD = function(_, arg1)
guildMotD = arg1
end
}
local menuList = {
{ text = _G.OPTIONS_MENU, isTitle = true, notCheckable=true},
{ text = _G.INVITE, hasArrow = true, notCheckable=true,},
{ text = _G.CHAT_MSG_WHISPER_INFORM, hasArrow = true, notCheckable=true,}
}
local function inviteClick(_, name, guid)
DT.EasyMenu:Hide()
if not (name and name ~= '') then return end
if guid then
local inviteType = GetDisplayedInviteType(guid)
if inviteType == 'INVITE' or inviteType == 'SUGGEST_INVITE' then
C_PartyInfo_InviteUnit(name)
elseif inviteType == 'REQUEST_INVITE' then
C_PartyInfo_RequestInviteFromUnit(name)
end
else
-- if for some reason guid isnt here fallback and just try to invite them
-- this is unlikely but having a fallback doesnt hurt
C_PartyInfo_InviteUnit(name)
end
end
local function whisperClick(_, playerName)
DT.EasyMenu:Hide()
SetItemRef( 'player:'..playerName, format('|Hplayer:%1$s|h[%1$s]|h',playerName), 'LeftButton' )
end
local function Click(self, btn)
if btn == 'RightButton' and IsInGuild() then
local menuCountWhispers = 0
local menuCountInvites = 0
menuList[2].menuList = {}
menuList[3].menuList = {}
for _, info in ipairs(guildTable) do
if (info.online or info.isMobile) and info.name ~= E.myname then
local classc, levelc = E:ClassColor(info.class), GetQuestDifficultyColor(info.level)
if not classc then classc = levelc end
local name = format(levelNameString, levelc.r*255,levelc.g*255,levelc.b*255, info.level, classc.r*255,classc.g*255,classc.b*255, info.name)
if inGroup(info.name) ~= '' then
name = name..' |cffaaaaaa*|r'
elseif not (info.isMobile and info.zone == REMOTE_CHAT) then
menuCountInvites = menuCountInvites + 1
menuList[2].menuList[menuCountInvites] = {text = name, arg1 = info.name, arg2 = info.guid, notCheckable=true, func = inviteClick}
end
menuCountWhispers = menuCountWhispers + 1
menuList[3].menuList[menuCountWhispers] = {text = name, arg1 = info.name, notCheckable=true, func = whisperClick}
end
end
DT:SetEasyMenuAnchor(DT.EasyMenu, self)
_G.EasyMenu(menuList, DT.EasyMenu, nil, nil, nil, 'MENU')
elseif InCombatLockdown() then
_G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT)
else
ToggleGuildFrame()
end
end
local function OnEnter(_, _, noUpdate)
if not IsInGuild() then return end
DT.tooltip:ClearLines()
local shiftDown = IsShiftKeyDown()
local total, _, online = GetNumGuildMembers()
if #guildTable == 0 then BuildGuildTable() end
SortGuildTable(shiftDown)
local guildName, guildRank = GetGuildInfo('player')
local applicants = GetNumGuildApplicants()
if guildName and guildRank then
DT.tooltip:AddDoubleLine(format(guildInfoString, guildName), format(guildInfoString2..(applicants > 0 and ' |cFFFFFFFF(|cff33ff33%d|r|cFFFFFFFF)|r' or ''), online, total, applicants), tthead.r, tthead.g, tthead.b, tthead.r, tthead.g, tthead.b)
DT.tooltip:AddLine(guildRank, unpack(tthead))
end
if guildMotD ~= '' then
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(format(guildMotDString, GUILD_MOTD, guildMotD), ttsubh.r, ttsubh.g, ttsubh.b, 1)
end
local _, _, standingID, barMin, barMax, barValue = GetGuildFactionInfo()
if standingID ~= 8 then -- Not Max Rep
barMax = barMax - barMin
barValue = barValue - barMin
DT.tooltip:AddLine(format(standingString, COMBAT_FACTION_CHANGE, E:ShortValue(barValue), E:ShortValue(barMax), ceil((barValue / barMax) * 100)))
end
local zonec
DT.tooltip:AddLine(' ')
for i, info in ipairs(guildTable) do
-- if more then 30 guild members are online, we don't Show any more, but inform user there are more
if 30 - i < 1 then
if online - 30 > 1 then DT.tooltip:AddLine(format(moreMembersOnlineString, online - 30), ttsubh.r, ttsubh.g, ttsubh.b) end
break
end
if E.MapInfo.zoneText and (E.MapInfo.zoneText == info.zone) then zonec = activezone else zonec = inactivezone end
local classc, levelc = E:ClassColor(info.class), GetQuestDifficultyColor(info.level)
if not classc then classc = levelc end
if shiftDown then
DT.tooltip:AddDoubleLine(format(nameRankString, info.name, info.rank), info.zone, classc.r, classc.g, classc.b, zonec.r, zonec.g, zonec.b)
if info.note ~= '' then DT.tooltip:AddLine(format(noteString, info.note), ttsubh.r, ttsubh.g, ttsubh.b, 1) end
if info.officerNote ~= '' then DT.tooltip:AddLine(format(officerNoteString, info.officerNote), ttoff.r, ttoff.g, ttoff.b, 1) end
else
DT.tooltip:AddDoubleLine(format(levelNameStatusString, levelc.r*255, levelc.g*255, levelc.b*255, info.level, strmatch(info.name,'([^%-]+).*'), inGroup(info.name), info.status), info.zone, classc.r,classc.g,classc.b, zonec.r,zonec.g,zonec.b)
end
end
if not noUpdate then
C_GuildInfo_GuildRoster()
end
DT.tooltip:Show()
end
local function OnEvent(self, event, ...)
lastPanel = self
if IsInGuild() then
local func = eventHandlers[event]
if func then func(self, ...) end
if not IsAltKeyDown() and event == 'MODIFIER_STATE_CHANGED' and GetMouseFocus() == self then
OnEnter(self)
end
if E.global.datatexts.settings.Guild.NoLabel then
self.text:SetFormattedText(displayString, #guildTable)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Guild.Label ~= '' and E.global.datatexts.settings.Guild.Label or GUILD..': ', #guildTable)
end
else
self.text:SetText(noGuildString)
end
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Guild.NoLabel and '' or '%s', hex, '%d|r')
noGuildString = hex..L["No Guild"]
if lastPanel then
OnEvent(lastPanel, 'ELVUI_COLOR_UPDATE')
end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Guild', _G.SOCIAL_LABEL, {'CHAT_MSG_SYSTEM', 'GUILD_ROSTER_UPDATE', 'PLAYER_GUILD_UPDATE', 'GUILD_MOTD', 'MODIFIER_STATE_CHANGED'}, OnEvent, nil, Click, OnEnter, nil, GUILD, nil, ValueColorUpdate)

65
Modules/DataTexts/HPS.lua Normal file
View File

@@ -0,0 +1,65 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local time, max, strjoin = time, max, strjoin
local CombatLogGetCurrentEventInfo = CombatLogGetCurrentEventInfo
local UnitGUID = UnitGUID
local timeStamp, combatTime, healTotal = 0, 0, 0
local lastSegment, petGUID = 0
local displayString, lastPanel = ''
local events = {SPELL_HEAL = true, SPELL_PERIODIC_HEAL = true}
local function Reset()
timeStamp, combatTime, healTotal = 0, 0, 0
end
local function GetHPS(self)
local hps
if healTotal == 0 or combatTime == 0 then
hps = 0
else
hps = healTotal / combatTime
end
self.text:SetFormattedText(displayString, L["HPS"], E:ShortValue(hps))
end
local function OnEvent(self, event)
lastPanel = self
if event == 'UNIT_PET' then
petGUID = UnitGUID('pet')
elseif event == 'PLAYER_REGEN_DISABLED' or event == 'PLAYER_LEAVE_COMBAT' then
local now = time()
if now - lastSegment > 20 then
Reset()
end
lastSegment = now
elseif event == 'COMBAT_LOG_EVENT_UNFILTERED' then
local timestamp, Event, _, sourceGUID, _, _, _, _, _, _, _, _, _, _, lastHealAmount, overHeal = CombatLogGetCurrentEventInfo()
if not events[Event] then return end
if sourceGUID == E.myguid or sourceGUID == petGUID then
if timeStamp == 0 then timeStamp = timestamp end
lastSegment = timeStamp
combatTime = timestamp - timeStamp
healTotal = healTotal + max(0, lastHealAmount - overHeal)
end
end
GetHPS(self)
end
local function OnClick(self)
Reset()
GetHPS(self)
end
local function ValueColorUpdate(hex)
displayString = strjoin('', '%s: ', hex, '%s')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('HPS', nil, {'UNIT_PET', 'COMBAT_LOG_EVENT_UNFILTERED', 'PLAYER_LEAVE_COMBAT', 'PLAYER_REGEN_DISABLED'}, OnEvent, nil, OnClick, nil, nil, L["HPS"], nil, ValueColorUpdate)

View File

@@ -0,0 +1,65 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local format, strjoin = format, strjoin
local GetHaste = GetHaste
local GetCombatRating = GetCombatRating
local GetCombatRatingBonus = GetCombatRatingBonus
local BreakUpLargeNumbers = BreakUpLargeNumbers
local GetPVPGearStatRules = GetPVPGearStatRules
local STAT_HASTE = STAT_HASTE
local CR_HASTE_MELEE = CR_HASTE_MELEE
local HIGHLIGHT_FONT_COLOR_CODE = HIGHLIGHT_FONT_COLOR_CODE
local FONT_COLOR_CODE_CLOSE = FONT_COLOR_CODE_CLOSE
local PAPERDOLLFRAME_TOOLTIP_FORMAT = PAPERDOLLFRAME_TOOLTIP_FORMAT
local STAT_HASTE_TOOLTIP = STAT_HASTE_TOOLTIP
local STAT_HASTE_BASE_TOOLTIP = STAT_HASTE_BASE_TOOLTIP
local RED_FONT_COLOR_CODE = RED_FONT_COLOR_CODE
local STAT_CATEGORY_ENHANCEMENTS = STAT_CATEGORY_ENHANCEMENTS
local displayString, lastPanel = ''
local function OnEnter()
DT.tooltip:ClearLines()
local rating = CR_HASTE_MELEE
local classTooltip = _G['STAT_HASTE_'..E.myclass..'_TOOLTIP']
local haste = GetHaste()
local hasteFormatString
if haste < 0 and not GetPVPGearStatRules() then
hasteFormatString = RED_FONT_COLOR_CODE..'%s'..FONT_COLOR_CODE_CLOSE
else
hasteFormatString = '%s'
end
if not classTooltip then
classTooltip = STAT_HASTE_TOOLTIP
end
DT.tooltip:AddLine(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_HASTE)..' '..format(hasteFormatString, format('%.2F%%', haste))..FONT_COLOR_CODE_CLOSE)
DT.tooltip:AddLine(classTooltip..format(STAT_HASTE_BASE_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(rating)), GetCombatRatingBonus(rating)))
DT.tooltip:Show()
end
local function OnEvent(self)
local haste = GetHaste()
if E.global.datatexts.settings.Haste.NoLabel then
self.text:SetFormattedText(displayString, haste)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Haste.Label ~= '' and E.global.datatexts.settings.Haste.Label or STAT_HASTE..': ', haste)
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Haste.NoLabel and '' or '%s', hex, '%.'..E.global.datatexts.settings.Haste.decimalLength..'f%%|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Haste', STAT_CATEGORY_ENHANCEMENTS, {'UNIT_STATS', 'UNIT_AURA', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE', 'UNIT_SPELL_HASTE'}, OnEvent, nil, nil, OnEnter, nil, STAT_HASTE, nil, ValueColorUpdate)

View File

@@ -0,0 +1,27 @@
local E, L, V, P, G = unpack(select(2, ...)); --Inport: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local strjoin = strjoin
local UnitStat = UnitStat
local ITEM_MOD_INTELLECT_SHORT = ITEM_MOD_INTELLECT_SHORT
local LE_UNIT_STAT_INTELLECT = LE_UNIT_STAT_INTELLECT
local STAT_CATEGORY_ATTRIBUTES = STAT_CATEGORY_ATTRIBUTES
local displayString, lastPanel = ''
local function OnEvent(self)
self.text:SetFormattedText(displayString, ITEM_MOD_INTELLECT_SHORT, UnitStat('player', LE_UNIT_STAT_INTELLECT))
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', '%s: ', hex, '%.f|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Intellect', STAT_CATEGORY_ATTRIBUTES, { 'UNIT_STATS', 'UNIT_AURA', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE' }, OnEvent, nil, nil, nil, nil, ITEM_MOD_INTELLECT_SHORT, nil, ValueColorUpdate)

View File

@@ -0,0 +1,65 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local ipairs = ipairs
local strjoin = strjoin
local format = format
local pi = math.pi
local ITEM_LEVEL_ABBR = ITEM_LEVEL_ABBR
local LFG_LIST_ITEM_LEVEL_INSTR_PVP_SHORT = LFG_LIST_ITEM_LEVEL_INSTR_PVP_SHORT
local STAT_AVERAGE_ITEM_LEVEL = STAT_AVERAGE_ITEM_LEVEL
local GMSURVEYRATING3 = GMSURVEYRATING3
local GetAverageItemLevel= GetAverageItemLevel
local GetInventoryItemLink = GetInventoryItemLink
local GetInventoryItemTexture = GetInventoryItemTexture
local iconString = '|T%s:13:15:0:0:50:50:4:46:4:46|t %s'
local slotID = { 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }
local title, lastPanel = ''
local function colorize(num)
if num >= 0 then
return .1, 1, .1
else
return E:ColorGradient(-(pi/num), 1, .1, .1, 1, 1, .1, .1, 1, .1)
end
end
local function OnEvent(self)
local avg, avgEquipped = GetAverageItemLevel()
local same = avg == avgEquipped
self.text:SetFormattedText(title .. (same and '%0.2f|r' or '%0.2f / %0.2f|r'), ITEM_LEVEL_ABBR, avgEquipped, (not same and avg) or '0')
end
local function OnEnter(self)
DT.tooltip:ClearLines()
local avg, avgEquipped, avgPvp = GetAverageItemLevel()
DT.tooltip:AddDoubleLine(STAT_AVERAGE_ITEM_LEVEL, format('%0.2f', avg), 1, 1, 1, .1, 1, .1)
DT.tooltip:AddDoubleLine(GMSURVEYRATING3, format('%0.2f', avgEquipped), 1, 1, 1, colorize(avgEquipped - avg))
DT.tooltip:AddDoubleLine(LFG_LIST_ITEM_LEVEL_INSTR_PVP_SHORT, format('%0.2f', avgPvp), 1, 1, 1, colorize(avgPvp - avg))
DT.tooltip:AddLine(' ')
for _, k in ipairs(slotID) do
local info = E:GetGearSlotInfo('player', k)
local ilvl = (info and info ~= 'tooSoon') and info.iLvl
if ilvl then
local link = GetInventoryItemLink('player', k)
local icon = GetInventoryItemTexture('player', k)
DT.tooltip:AddDoubleLine(format(iconString, icon, link), ilvl, 1, 1, 1, colorize(ilvl - avg))
end
end
lastPanel = self
DT.tooltip:Show()
end
local function ValueColorUpdate(hex)
title = strjoin('', '%s: ', hex)
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Item Level', 'Stats', {'PLAYER_AVG_ITEM_LEVEL_UPDATE'}, OnEvent, nil, nil, OnEnter, nil, _G.LFG_LIST_ITEM_LEVEL_INSTR_SHORT, nil, ValueColorUpdate)

View File

@@ -0,0 +1,44 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local format, strjoin = format, strjoin
local BreakUpLargeNumbers = BreakUpLargeNumbers
local GetCombatRating = GetCombatRating
local GetCombatRatingBonus = GetCombatRatingBonus
local GetLifesteal = GetLifesteal
local CR_LIFESTEAL = CR_LIFESTEAL
local CR_LIFESTEAL_TOOLTIP = CR_LIFESTEAL_TOOLTIP
local FONT_COLOR_CODE_CLOSE = FONT_COLOR_CODE_CLOSE
local HIGHLIGHT_FONT_COLOR_CODE = HIGHLIGHT_FONT_COLOR_CODE
local PAPERDOLLFRAME_TOOLTIP_FORMAT = PAPERDOLLFRAME_TOOLTIP_FORMAT
local STAT_CATEGORY_ENHANCEMENTS = STAT_CATEGORY_ENHANCEMENTS
local STAT_LIFESTEAL = STAT_LIFESTEAL
local displayString, lastPanel = ''
local function OnEnter()
DT.tooltip:ClearLines()
local text = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_LIFESTEAL)..' '..format('%.2F%%', GetLifesteal())..FONT_COLOR_CODE_CLOSE
local tooltip = format(CR_LIFESTEAL_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_LIFESTEAL)), GetCombatRatingBonus(CR_LIFESTEAL))
DT.tooltip:AddDoubleLine(text, nil, 1, 1, 1)
DT.tooltip:AddLine(tooltip, nil, nil, nil, true)
DT.tooltip:Show()
end
local function OnEvent(self)
local lifesteal = GetLifesteal()
self.text:SetFormattedText(displayString, STAT_LIFESTEAL, lifesteal)
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', '%s: ', hex, '%.2f%%|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Leech', STAT_CATEGORY_ENHANCEMENTS, {'UNIT_STATS', 'UNIT_AURA', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE', 'PLAYER_DAMAGE_DONE_MODS'}, OnEvent, nil, nil, OnEnter, nil, STAT_LIFESTEAL, nil, ValueColorUpdate)

View File

@@ -0,0 +1,44 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Script file='DataTexts.lua'/>
<Script file='Agility.lua'/>
<Script file='Armor.lua'/>
<Script file='Avoidance.lua'/>
<Script file='Bags.lua'/>
<Script file='BattleStats.lua'/>
<Script file='CallToArms.lua'/>
<Script file='CombatTime.lua'/>
<Script file='ConfigElvUI.lua'/>
<Script file='Coordinates.lua'/>
<Script file='Crit.lua'/>
<Script file='Currencies.lua'/>
<Script file='CustomCurrency.lua'/>
<Script file='Date.lua'/>
<Script file='Difficulty.lua'/>
<Script file='DPS.lua'/>
<Script file='Durability.lua'/>
<Script file='Experience.lua'/>
<Script file='Friends.lua'/>
<Script file='Gold.lua'/>
<Script file='Guild.lua'/>
<Script file='Haste.lua'/>
<Script file='HPS.lua'/>
<Script file='Intellect.lua'/>
<Script file='ItemLevel.lua'/>
<Script file='Leech.lua'/>
<Script file='Mail.lua'/>
<Script file='ManaRegen.lua'/>
<Script file='Mastery.lua'/>
<Script file='Missions.lua'/>
<Script file='MovementSpeed.lua'/>
<Script file='PrimaryStat.lua'/>
<Script file='Quickjoin.lua'/>
<Script file='Reputation.lua'/>
<Script file='SpecSwitch.lua'/>
<Script file='Speed.lua'/>
<Script file='Stamina.lua'/>
<Script file='Strength.lua'/>
<Script file='System.lua'/>
<Script file='Time.lua'/>
<Script file='Versatility.lua'/>
</Ui>

View File

@@ -0,0 +1,42 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local next = next
local pairs = pairs
local strjoin = strjoin
local HasNewMail = HasNewMail
local GetLatestThreeSenders = GetLatestThreeSenders
local HAVE_MAIL_FROM = HAVE_MAIL_FROM
local MAIL_LABEL = MAIL_LABEL
local displayString, lastPanel = ''
local function OnEvent(self)
lastPanel = self
self.text:SetFormattedText(displayString, HasNewMail() and 'New Mail' or 'No Mail')
end
local function OnEnter()
DT.tooltip:ClearLines()
local senders = { GetLatestThreeSenders() }
if not next(senders) then return end
DT.tooltip:AddLine(HasNewMail() and HAVE_MAIL_FROM or MAIL_LABEL, 1, 1, 1)
DT.tooltip:AddLine(' ')
for _, sender in pairs(senders) do
DT.tooltip:AddLine(sender)
end
DT.tooltip:Show()
end
local function ValueColorUpdate(hex)
displayString = strjoin(hex, '%s|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Mail', nil, {'MAIL_INBOX_UPDATE', 'UPDATE_PENDING_MAIL', 'MAIL_CLOSED', 'MAIL_SHOW'}, OnEvent, nil, nil, OnEnter, nil, MAIL_LABEL, nil, ValueColorUpdate)

View File

@@ -0,0 +1,30 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local strjoin = strjoin
local GetManaRegen = GetManaRegen
local InCombatLockdown = InCombatLockdown
local STAT_CATEGORY_ATTRIBUTES = STAT_CATEGORY_ATTRIBUTES
local MANA_REGEN = MANA_REGEN
local displayString, lastPanel = ''
local function OnEvent(self)
local baseMR, castingMR = GetManaRegen()
if InCombatLockdown() then
self.text:SetFormattedText(displayString, MANA_REGEN, castingMR*5)
else
self.text:SetFormattedText(displayString, MANA_REGEN, baseMR*5)
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', '%s: ', hex, '%.2f|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Mana Regen', STAT_CATEGORY_ATTRIBUTES, {'UNIT_STATS', 'UNIT_AURA', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE'}, OnEvent, nil, nil, nil, nil, MANA_REGEN, nil, ValueColorUpdate)

View File

@@ -0,0 +1,49 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local strjoin = strjoin
local GetMasteryEffect = GetMasteryEffect
local GetSpecialization = GetSpecialization
local GetSpecializationMasterySpells = GetSpecializationMasterySpells
local STAT_CATEGORY_ENHANCEMENTS = STAT_CATEGORY_ENHANCEMENTS
local STAT_MASTERY = STAT_MASTERY
local displayString, lastPanel = ''
local function OnEnter()
DT.tooltip:ClearLines()
local primaryTalentTree = GetSpecialization()
if primaryTalentTree then
local masterySpell, masterySpell2 = GetSpecializationMasterySpells(primaryTalentTree)
if masterySpell then
DT.tooltip:AddSpellByID(masterySpell)
end
if masterySpell2 then
DT.tooltip:AddLine(' ')
DT.tooltip:AddSpellByID(masterySpell2)
end
DT.tooltip:Show()
end
end
local function OnEvent(self)
lastPanel = self
local masteryRating = GetMasteryEffect()
if E.global.datatexts.settings.Mastery.NoLabel then
self.text:SetFormattedText(displayString, masteryRating)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Mastery.Label ~= '' and E.global.datatexts.settings.Mastery.Label or STAT_MASTERY..': ', masteryRating)
end
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Mastery.NoLabel and '' or '%s', hex, '%.'..E.global.datatexts.settings.Mastery.decimalLength..'f%%|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Mastery', STAT_CATEGORY_ENHANCEMENTS, {'MASTERY_UPDATE'}, OnEvent, nil, nil, OnEnter, nil, STAT_MASTERY, nil, ValueColorUpdate)

View File

@@ -0,0 +1,357 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local next, wipe, ipairs = next, wipe, ipairs
local format, sort, select = format, sort, select
local GetMouseFocus = GetMouseFocus
local HideUIPanel = HideUIPanel
local IsShiftKeyDown = IsShiftKeyDown
local InCombatLockdown = InCombatLockdown
local BreakUpLargeNumbers = BreakUpLargeNumbers
local ShowGarrisonLandingPage = ShowGarrisonLandingPage
local C_Garrison_HasGarrison = C_Garrison.HasGarrison
local C_Garrison_GetBuildings = C_Garrison.GetBuildings
local C_Garrison_GetInProgressMissions = C_Garrison.GetInProgressMissions
local C_Garrison_GetLandingPageShipmentInfo = C_Garrison.GetLandingPageShipmentInfo
local C_Garrison_GetCompleteTalent = C_Garrison.GetCompleteTalent
local C_Garrison_GetFollowerShipments = C_Garrison.GetFollowerShipments
local C_Garrison_GetLandingPageShipmentInfoByContainerID = C_Garrison.GetLandingPageShipmentInfoByContainerID
local C_Garrison_RequestLandingPageShipmentInfo = C_Garrison.RequestLandingPageShipmentInfo
local C_Garrison_GetCompleteMissions = C_Garrison.GetCompleteMissions
local C_Garrison_GetLooseShipments = C_Garrison.GetLooseShipments
local C_Garrison_GetTalentTreeIDsByClassID = C_Garrison.GetTalentTreeIDsByClassID
local C_Garrison_GetTalentTreeInfo = C_Garrison.GetTalentTreeInfo
local C_QuestLog_IsQuestFlaggedCompleted = C_QuestLog.IsQuestFlaggedCompleted
local C_IslandsQueue_GetIslandsWeeklyQuestID = C_IslandsQueue.GetIslandsWeeklyQuestID
local C_CurrencyInfo_GetCurrencyInfo = C_CurrencyInfo.GetCurrencyInfo
local C_Covenants_GetActiveCovenantID = C_Covenants.GetActiveCovenantID
local C_CovenantCallings_AreCallingsUnlocked = C_CovenantCallings.AreCallingsUnlocked
local CovenantCalling_Create = CovenantCalling_Create
local GetMaxLevelForExpansionLevel = GetMaxLevelForExpansionLevel
local GetQuestObjectiveInfo = GetQuestObjectiveInfo
local SecondsToTime = SecondsToTime
local IsAltKeyDown = IsAltKeyDown
local GARRISON_LANDING_NEXT = GARRISON_LANDING_NEXT
local CAPACITANCE_WORK_ORDERS = CAPACITANCE_WORK_ORDERS
local FOLLOWERLIST_LABEL_TROOPS = FOLLOWERLIST_LABEL_TROOPS
local GARRISON_EMPTY_IN_PROGRESS_LIST = GARRISON_EMPTY_IN_PROGRESS_LIST
local GARRISON_LANDING_SHIPMENT_COUNT = GARRISON_LANDING_SHIPMENT_COUNT
local GOAL_COMPLETED = GOAL_COMPLETED
local GREEN_FONT_COLOR = GREEN_FONT_COLOR
local ISLANDS_HEADER = ISLANDS_HEADER
local ISLANDS_QUEUE_FRAME_TITLE = ISLANDS_QUEUE_FRAME_TITLE
local ISLANDS_QUEUE_WEEKLY_QUEST_PROGRESS = ISLANDS_QUEUE_WEEKLY_QUEST_PROGRESS
local LE_EXPANSION_BATTLE_FOR_AZEROTH = LE_EXPANSION_BATTLE_FOR_AZEROTH
local LE_FOLLOWER_TYPE_GARRISON_6_0 = Enum.GarrisonFollowerType.FollowerType_6_0
local LE_FOLLOWER_TYPE_GARRISON_7_0 = Enum.GarrisonFollowerType.FollowerType_7_0
local LE_FOLLOWER_TYPE_GARRISON_8_0 = Enum.GarrisonFollowerType.FollowerType_8_0
local LE_FOLLOWER_TYPE_GARRISON_6_2 = Enum.GarrisonFollowerType.FollowerType_6_2
local LE_FOLLOWER_TYPE_GARRISON_9_0 = Enum.GarrisonFollowerType.FollowerType_9_0
local LE_GARRISON_TYPE_6_0 = Enum.GarrisonType.Type_6_0
local LE_GARRISON_TYPE_7_0 = Enum.GarrisonType.Type_7_0
local LE_GARRISON_TYPE_8_0 = Enum.GarrisonType.Type_8_0
local LE_GARRISON_TYPE_9_0 = Enum.GarrisonType.Type_9_0
local RESEARCH_TIME_LABEL = RESEARCH_TIME_LABEL
local DATE_COMPLETED = DATE_COMPLETED:gsub('(%%s)', '|cFF33FF33%1|r') -- 'Completed: |cFF33FF33%s|r'
local EXPANSION_NAME5 = EXPANSION_NAME5 -- 'Warlords of Draenor'
local EXPANSION_NAME6 = EXPANSION_NAME6 -- 'Legion'
local EXPANSION_NAME7 = EXPANSION_NAME7 -- 'Battle for Azeroth'
local EXPANSION_NAME8 = EXPANSION_NAME8 -- 'Shadowlands'
local MAIN_CURRENCY = 1813
local iconString = '|T%s:16:16:0:0:64:64:4:60:4:60|t'
local numMissions = 0
local callingsData = {}
local covenantTreeIDs = {
[1] = {308, 312, 316, 320, 327},
[2] = {309, 314, 317, 324, 326},
[3] = {307, 311, 315, 319, 328},
[4] = {310, 313, 318, 321, 329}
}
local function sortFunction(a, b)
return a.missionEndTime < b.missionEndTime
end
local function LandingPage(_, ...)
if not C_Garrison_HasGarrison(...) then
return
end
HideUIPanel(_G.GarrisonLandingPage)
ShowGarrisonLandingPage(...)
end
local menuList = {
{text = _G.GARRISON_LANDING_PAGE_TITLE, func = LandingPage, arg1 = LE_GARRISON_TYPE_6_0, notCheckable = true},
{text = _G.ORDER_HALL_LANDING_PAGE_TITLE, func = LandingPage, arg1 = LE_GARRISON_TYPE_7_0, notCheckable = true},
{text = _G.WAR_CAMPAIGN, func = LandingPage, arg1 = LE_GARRISON_TYPE_8_0, notCheckable = true},
{text = _G.GARRISON_TYPE_9_0_LANDING_PAGE_TITLE, func = LandingPage, arg1 = LE_GARRISON_TYPE_9_0, notCheckable = true},
}
local data = {}
local function AddInProgressMissions(garrisonType)
wipe(data)
C_Garrison_GetInProgressMissions(data, garrisonType)
if next(data) then
sort(data, sortFunction) -- Sort by time left, lowest first
for _, mission in ipairs(data) do
local timeLeft = mission.timeLeftSeconds
local r, g, b = 1, 1, 1
if mission.isRare then
r, g, b = 0.09, 0.51, 0.81
end
if timeLeft and timeLeft == 0 then
DT.tooltip:AddDoubleLine(mission.name, GOAL_COMPLETED, r, g, b, GREEN_FONT_COLOR:GetRGB())
else
DT.tooltip:AddDoubleLine(mission.name, SecondsToTime(timeLeft), r, g, b, 1, 1, 1)
end
end
else
DT.tooltip:AddLine(GARRISON_EMPTY_IN_PROGRESS_LIST, 1, 1, 1)
end
end
local function AddFollowerInfo(garrisonType)
data = C_Garrison_GetFollowerShipments(garrisonType)
if next(data) then
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(FOLLOWERLIST_LABEL_TROOPS) -- 'Troops'
for _, followerShipments in ipairs(data) do
local name, _, _, shipmentsReady, shipmentsTotal, _, _, timeleftString = C_Garrison_GetLandingPageShipmentInfoByContainerID(followerShipments)
if name and shipmentsReady and shipmentsTotal then
if timeleftString then
DT.tooltip:AddDoubleLine(name, format(GARRISON_LANDING_SHIPMENT_COUNT, shipmentsReady, shipmentsTotal) .. ' ' .. format(GARRISON_LANDING_NEXT,timeleftString), 1, 1, 1, 1, 1, 1)
else
DT.tooltip:AddDoubleLine(name, format(GARRISON_LANDING_SHIPMENT_COUNT, shipmentsReady, shipmentsTotal), 1, 1, 1, 1, 1, 1)
end
end
end
end
end
local covenantInfo = {}
local function AddTalentInfo(garrisonType, currentCovenant)
if garrisonType == LE_GARRISON_TYPE_9_0 then
local current = covenantTreeIDs[currentCovenant]
if current then
wipe(covenantInfo)
data = E:CopyTable(covenantInfo, current)
else
wipe(data)
end
else
data = C_Garrison_GetTalentTreeIDsByClassID(garrisonType, E.myClassID)
end
if next(data) then
-- This is a talent that has completed, but has not been seen in the talent UI yet.
-- No longer provide relevant output in SL. Still used by old content.
local completeTalentID = C_Garrison_GetCompleteTalent(garrisonType)
if completeTalentID > 0 then
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(RESEARCH_TIME_LABEL) -- 'Research Time:'
for _, treeID in ipairs(data) do
local treeInfo = C_Garrison_GetTalentTreeInfo(treeID)
for _, talent in ipairs(treeInfo.talents) do
if talent.isBeingResearched or (talent.id == completeTalentID and garrisonType ~= LE_GARRISON_TYPE_9_0)then
if talent.timeRemaining and talent.timeRemaining == 0 then
DT.tooltip:AddDoubleLine(talent.name, GOAL_COMPLETED, 1, 1, 1, GREEN_FONT_COLOR:GetRGB())
else
DT.tooltip:AddDoubleLine(talent.name, SecondsToTime(talent.timeRemaining), 1, 1, 1, 1, 1, 1)
end
end
end
end
end
end
end
local function GetInfo(id)
local info = C_CurrencyInfo_GetCurrencyInfo(id)
return info.quantity, info.name, (info.iconFileID and format(iconString, info.iconFileID)) or '136012'
end
local function AddInfo(id)
local quantity, _, icon = GetInfo(id)
return format('%s %s', icon, BreakUpLargeNumbers(quantity))
end
local function OnEnter()
DT.tooltip:ClearLines()
DT.tooltip:AddLine(EXPANSION_NAME8, 1, .5, 0)
DT.tooltip:AddDoubleLine(L["Mission(s) Report:"], AddInfo(1813), nil, nil, nil, 1, 1, 1)
AddInProgressMissions(LE_FOLLOWER_TYPE_GARRISON_9_0)
if C_CovenantCallings_AreCallingsUnlocked() then
local questNum = 0
for _, calling in ipairs(callingsData) do
local callingObj = CovenantCalling_Create(calling)
if callingObj:GetState() == 0 then
questNum = questNum + 1
end
end
if questNum > 0 then
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(format('%s %s', questNum, L["Calling Quest(s) available."]))
end
end
local currentCovenant = C_Covenants_GetActiveCovenantID()
if currentCovenant and currentCovenant > 0 then
AddTalentInfo(LE_GARRISON_TYPE_9_0, currentCovenant)
end
if IsShiftKeyDown() then
-- Battle for Azeroth
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(EXPANSION_NAME7, 1, .5, 0)
DT.tooltip:AddDoubleLine(L["Mission(s) Report:"], AddInfo(1560), nil, nil, nil, 1, 1, 1)
AddInProgressMissions(LE_FOLLOWER_TYPE_GARRISON_8_0)
-- Island Expeditions
if E.mylevel >= GetMaxLevelForExpansionLevel(LE_EXPANSION_BATTLE_FOR_AZEROTH) then
local questID = C_IslandsQueue_GetIslandsWeeklyQuestID()
if questID then
local _, _, finished, numFulfilled, numRequired = GetQuestObjectiveInfo(questID, 1, false)
local text, r1, g1, b1
if finished or C_QuestLog_IsQuestFlaggedCompleted(questID) then
text = GOAL_COMPLETED
r1, g1, b1 = GREEN_FONT_COLOR:GetRGB()
else
text = ISLANDS_QUEUE_WEEKLY_QUEST_PROGRESS:format(numFulfilled, numRequired)
r1, g1, b1 = 1, 1, 1
end
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(ISLANDS_HEADER .. ':')
DT.tooltip:AddDoubleLine(ISLANDS_QUEUE_FRAME_TITLE, text, 1, 1, 1, r1, g1, b1)
end
end
AddFollowerInfo(LE_GARRISON_TYPE_7_0)
AddTalentInfo(LE_GARRISON_TYPE_7_0)
-- Legion
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(EXPANSION_NAME6, 1, .5, 0)
DT.tooltip:AddDoubleLine(L["Mission(s) Report:"], AddInfo(1220), nil, nil, nil, 1, 1, 1)
AddInProgressMissions(LE_FOLLOWER_TYPE_GARRISON_7_0)
AddFollowerInfo(LE_GARRISON_TYPE_7_0)
-- 'Loose Work Orders' (i.e. research, equipment)
data = C_Garrison_GetLooseShipments(LE_GARRISON_TYPE_7_0)
if next(data) then
DT.tooltip:AddLine(CAPACITANCE_WORK_ORDERS) -- 'Work Orders'
for _, looseShipments in ipairs(data) do
local name, _, _, shipmentsReady, shipmentsTotal, _, _, timeleftString = C_Garrison_GetLandingPageShipmentInfoByContainerID(looseShipments)
if name then
if timeleftString then
DT.tooltip:AddDoubleLine(name, format(GARRISON_LANDING_SHIPMENT_COUNT, shipmentsReady, shipmentsTotal) .. ' ' .. format(GARRISON_LANDING_NEXT,timeleftString), 1, 1, 1, 1, 1, 1)
else
DT.tooltip:AddDoubleLine(name, format(GARRISON_LANDING_SHIPMENT_COUNT, shipmentsReady, shipmentsTotal), 1, 1, 1, 1, 1, 1)
end
end
end
end
AddTalentInfo(LE_GARRISON_TYPE_7_0)
-- Warlords of Draenor
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(EXPANSION_NAME5, 1, .5, 0)
DT.tooltip:AddDoubleLine(L["Mission(s) Report:"], AddInfo(824), nil, nil, nil, 1, 1, 1)
AddInProgressMissions(LE_FOLLOWER_TYPE_GARRISON_6_0)
DT.tooltip:AddLine(' ')
DT.tooltip:AddDoubleLine(L["Naval Mission(s) Report:"], AddInfo(1101), nil, nil, nil, 1, 1 , 1)
AddInProgressMissions(LE_FOLLOWER_TYPE_GARRISON_6_2)
--Buildings
data = C_Garrison_GetBuildings(LE_GARRISON_TYPE_6_0)
if next(data) then
local AddLine = true
for _, buildings in ipairs(data) do
local name, _, _, shipmentsReady, shipmentsTotal, _, _, timeleftString = C_Garrison_GetLandingPageShipmentInfo(buildings.buildingID)
if name and shipmentsTotal then
if AddLine then
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(L["Building(s) Report:"])
AddLine = false
end
if timeleftString then
DT.tooltip:AddDoubleLine(name, format(GARRISON_LANDING_SHIPMENT_COUNT, shipmentsReady, shipmentsTotal) .. ' ' .. format(GARRISON_LANDING_NEXT,timeleftString), 1, 1, 1, 1, 1, 1)
else
DT.tooltip:AddDoubleLine(name, format(GARRISON_LANDING_SHIPMENT_COUNT, shipmentsReady, shipmentsTotal), 1, 1, 1, 1, 1, 1)
end
end
end
end
else
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine('Hold Shift - Show Previous Expansion', .66, .66, .66)
end
DT.tooltip:Show()
end
local function OnClick(self)
if InCombatLockdown() then _G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT) return end
DT:SetEasyMenuAnchor(DT.EasyMenu, self)
_G.EasyMenu(menuList, DT.EasyMenu, nil, nil, nil, 'MENU')
end
local function OnEvent(self, event, ...)
if event == 'CURRENCY_DISPLAY_UPDATE' and select(1, ...) ~= MAIN_CURRENCY then
return
end
if event == 'COVENANT_CALLINGS_UPDATED' then
wipe(callingsData)
callingsData = ...
end
if event == 'GARRISON_SHIPMENT_RECEIVED' or (event == 'SHIPMENT_UPDATE' and select(1, ...) == true) then
C_Garrison_RequestLandingPageShipmentInfo()
end
if event == 'GARRISON_MISSION_NPC_OPENED' then
self:RegisterEvent('GARRISON_MISSION_LIST_UPDATE')
elseif event == 'GARRISON_MISSION_NPC_CLOSED' then
self:UnregisterEvent('GARRISON_MISSION_LIST_UPDATE')
end
if event == 'GARRISON_LANDINGPAGE_SHIPMENTS' or event == 'GARRISON_MISSION_FINISHED' or event == 'GARRISON_MISSION_NPC_CLOSED' or event == 'GARRISON_MISSION_LIST_UPDATE' then
numMissions = #C_Garrison_GetCompleteMissions(LE_FOLLOWER_TYPE_GARRISON_9_0)
+ #C_Garrison_GetCompleteMissions(LE_FOLLOWER_TYPE_GARRISON_8_0)
+ #C_Garrison_GetCompleteMissions(LE_FOLLOWER_TYPE_GARRISON_7_0)
+ #C_Garrison_GetCompleteMissions(LE_FOLLOWER_TYPE_GARRISON_6_0)
+ #C_Garrison_GetCompleteMissions(LE_FOLLOWER_TYPE_GARRISON_6_2)
end
if numMissions > 0 then
self.text:SetFormattedText(DATE_COMPLETED, numMissions)
else
self.text:SetText(AddInfo(MAIN_CURRENCY))
end
if event == 'MODIFIER_STATE_CHANGED' and not IsAltKeyDown() and GetMouseFocus() == self then
OnEnter(self)
end
end
DT:RegisterDatatext('Missions', nil, {'CURRENCY_DISPLAY_UPDATE', 'GARRISON_LANDINGPAGE_SHIPMENTS', 'GARRISON_TALENT_UPDATE', 'GARRISON_TALENT_COMPLETE', 'GARRISON_SHIPMENT_RECEIVED', 'SHIPMENT_UPDATE', 'GARRISON_MISSION_FINISHED', 'GARRISON_MISSION_NPC_CLOSED', 'GARRISON_MISSION_NPC_OPENED', 'MODIFIER_STATE_CHANGED', 'COVENANT_CALLINGS_UPDATED'}, OnEvent, nil, OnClick, OnEnter, nil, _G.GARRISON_MISSIONS)

View File

@@ -0,0 +1,65 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local strjoin = strjoin
local IsFalling = IsFalling
local IsFlying = IsFlying
local IsSwimming = IsSwimming
local GetUnitSpeed = GetUnitSpeed
local STAT_CATEGORY_ENHANCEMENTS = STAT_CATEGORY_ENHANCEMENTS
local BASE_MOVEMENT_SPEED = BASE_MOVEMENT_SPEED
local STAT_MOVEMENT_SPEED = STAT_MOVEMENT_SPEED
local displayString, lastPanel = ''
local beforeFalling, wasFlying
local delayed
local function DelayUpdate()
if not lastPanel then return end
local _, runSpeed, flightSpeed, swimSpeed = GetUnitSpeed('player')
local speed
if IsSwimming() then
speed = swimSpeed
wasFlying = false
elseif IsFlying() then
speed = flightSpeed
wasFlying = true
else
speed = runSpeed
wasFlying = false
end
if IsFalling() and wasFlying and beforeFalling then
speed = beforeFalling
else
beforeFalling = speed
end
local percent = speed / BASE_MOVEMENT_SPEED * 100
if E.global.datatexts.settings.MovementSpeed.NoLabel then
lastPanel.text:SetFormattedText(displayString, percent)
else
lastPanel.text:SetFormattedText(displayString, E.global.datatexts.settings.MovementSpeed.Label ~= '' and E.global.datatexts.settings.MovementSpeed.Label or STAT_MOVEMENT_SPEED, percent)
end
delayed = nil
end
local function OnEvent(self)
if not delayed then
delayed = E:Delay(0.05, DelayUpdate)
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.MovementSpeed.NoLabel and '' or '%s: ', hex, '%.'..E.global.datatexts.settings.MovementSpeed.decimalLength..'f%%|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('MovementSpeed', STAT_CATEGORY_ENHANCEMENTS, {'UNIT_STATS', 'UNIT_AURA', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE', 'UNIT_SPELL_HASTE'}, OnEvent, nil, nil, nil, nil, STAT_MOVEMENT_SPEED, nil, ValueColorUpdate)

View File

@@ -0,0 +1,31 @@
local E, L, V, P, G = unpack(select(2, ...)); --Inport: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local strjoin = strjoin
local UnitStat = UnitStat
local GetSpecialization = GetSpecialization
local STAT_CATEGORY_ATTRIBUTES = STAT_CATEGORY_ATTRIBUTES
local PRIMARY_STAT = SPEC_FRAME_PRIMARY_STAT:gsub('[:%s]-%%s$','')
local displayString, lastPanel = ''
local function OnEvent(self)
local StatID = DT.SPECIALIZATION_CACHE[GetSpecialization()] and DT.SPECIALIZATION_CACHE[GetSpecialization()].statID
local name = StatID and _G['SPELL_STAT'..StatID..'_NAME']
if name then
self.text:SetFormattedText(displayString, name..': ', UnitStat('player', StatID))
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', '%s', hex, '%.f|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Primary Stat', STAT_CATEGORY_ATTRIBUTES, { 'UNIT_STATS', 'UNIT_AURA', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_TALENT_UPDATE' }, OnEvent, nil, nil, nil, nil, PRIMARY_STAT, nil, ValueColorUpdate)

View File

@@ -0,0 +1,125 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local CH = E:GetModule('Chat')
local next, pairs, select, type = next, pairs, select, type
local format, strjoin, wipe, gsub = format, strjoin, wipe, gsub
local ToggleQuickJoinPanel = ToggleQuickJoinPanel
local SocialQueueUtil_GetQueueName = SocialQueueUtil_GetQueueName
local SocialQueueUtil_GetRelationshipInfo = SocialQueueUtil_GetRelationshipInfo
local C_SocialQueue_GetAllGroups = C_SocialQueue.GetAllGroups
local C_SocialQueue_GetGroupMembers = C_SocialQueue.GetGroupMembers
local C_SocialQueue_GetGroupQueues = C_SocialQueue.GetGroupQueues
local C_LFGList_GetSearchResultInfo = C_LFGList.GetSearchResultInfo
local UNKNOWN, QUICK_JOIN = UNKNOWN, QUICK_JOIN
local displayString = ''
local quickJoin = {}
local function OnEnter()
if not next(quickJoin) then return end
DT.tooltip:ClearLines()
DT.tooltip:AddLine(QUICK_JOIN, nil, nil, nil, true)
DT.tooltip:AddLine(' ')
for name, activity in pairs(quickJoin) do
DT.tooltip:AddDoubleLine(name, activity, nil, nil, nil, 1, 1, 1)
end
DT.tooltip:Show()
end
local function Update(self)
wipe(quickJoin)
if not self then return end
local quickJoinGroups = C_SocialQueue_GetAllGroups()
for _, guid in pairs(quickJoinGroups) do
local players = C_SocialQueue_GetGroupMembers(guid)
if players then
local firstMember, numMembers, extraCount = players[1], #players, ''
local playerName, nameColor = SocialQueueUtil_GetRelationshipInfo(firstMember.guid, nil, firstMember.clubId)
if numMembers > 1 then extraCount = format(' +%s', numMembers - 1) end
local queues = C_SocialQueue_GetGroupQueues(guid)
local firstQueue, numQueues = queues and queues[1], queues and #queues or 0
local isLFGList = firstQueue and firstQueue.queueData and firstQueue.queueData.queueType == 'lfglist'
local coloredName = (playerName and playerName ~= '' and format('%s%s|r%s', nameColor, playerName, extraCount)) or format('{%s%s}', UNKNOWN, extraCount)
local activity
if isLFGList and firstQueue and firstQueue.eligible then
local activityName, isLeader, leaderName
if firstQueue.queueData.lfgListID then
local searchResultInfo = C_LFGList_GetSearchResultInfo(firstQueue.queueData.lfgListID)
if searchResultInfo then
activityName, leaderName = searchResultInfo.name, searchResultInfo.leaderName
isLeader = CH:SocialQueueIsLeader(playerName, leaderName)
end
end
if isLeader then
coloredName = format([[|TInterface\GroupFrame\UI-Group-LeaderIcon:16:16|t%s]], coloredName)
end
activity = activityName or UNKNOWN
if numQueues > 1 then
activity = format('[+%s]%s', numQueues - 1, activity)
end
elseif firstQueue then
local output, queueCount = '', 0
for _, queue in pairs(queues) do
if type(queue) == 'table' and queue.eligible then
local queueName = (queue.queueData and SocialQueueUtil_GetQueueName(queue.queueData)) or ''
if queueName ~= '' then
if output == '' then
output = gsub(queueName,'\n.+','') -- grab only the first queue name
queueCount = queueCount + select(2, gsub(queueName,'\n','')) -- collect additional on single queue
else
queueCount = queueCount + 1 + select(2, gsub(queueName,'\n','')) -- collect additional on additional queues
end
end
end
end
if output ~= '' then
if queueCount > 0 then
activity = format('%s[+%s]', output, queueCount)
else
activity = output
end
end
end
quickJoin[coloredName] = activity
end
end
if E.global.datatexts.settings.QuickJoin.NoLabel then
self.text:SetFormattedText(displayString, #quickJoinGroups)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.QuickJoin.Label ~= '' and E.global.datatexts.settings.QuickJoin.Label or QUICK_JOIN..': ', #quickJoinGroups)
end
end
local delayed, lastPanel
local function throttle()
if lastPanel then Update(lastPanel) end
delayed = nil
end
local function OnEvent(self, event)
if lastPanel ~= self then lastPanel = self end
if delayed then return end
-- use a nonarg passing function, so that it goes through c_timer instead of the waitframe
delayed = E:Delay(event == 'ELVUI_FORCE_UPDATE' and 0 or 1, throttle)
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.QuickJoin.NoLabel and '' or '%s', hex, '%d|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('QuickJoin', _G.SOCIAL_LABEL, {"SOCIAL_QUEUE_UPDATE"}, OnEvent, nil, ToggleQuickJoinPanel, OnEnter, nil, QUICK_JOIN, nil, ValueColorUpdate)

View File

@@ -0,0 +1,114 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local format = format
local C_Reputation_GetFactionParagonInfo = C_Reputation.GetFactionParagonInfo
local C_Reputation_IsFactionParagon = C_Reputation.IsFactionParagon
local GetFriendshipReputation = GetFriendshipReputation
local ToggleCharacter = ToggleCharacter
local GetWatchedFactionInfo = GetWatchedFactionInfo
local REPUTATION, STANDING = REPUTATION, STANDING
local function OnEvent(self)
local name, reaction, min, max, value, factionID = GetWatchedFactionInfo()
if not name then return end
local friendshipID = GetFriendshipReputation(factionID);
local isFriend, friendText, standingLabel
local isCapped
if friendshipID then
local _, friendRep, _, _, _, _, friendTextLevel, friendThreshold, nextFriendThreshold = GetFriendshipReputation(factionID);
isFriend, reaction, friendText = true, 5, friendTextLevel
if nextFriendThreshold then
min, max, value = friendThreshold, nextFriendThreshold, friendRep;
else
isCapped = true;
end
elseif C_Reputation_IsFactionParagon(factionID) then
local currentValue, threshold, _, hasRewardPending = C_Reputation_GetFactionParagonInfo(factionID)
if currentValue and threshold then
min, max = 0, threshold
value = currentValue % threshold
if hasRewardPending then
value = value + threshold
end
end
else
if reaction == _G.MAX_REPUTATION_REACTION then
isCapped = true
end
end
local color = _G.FACTION_BAR_COLORS[reaction]
local text = ''
local textFormat = E.global.datatexts.settings.Reputation.textFormat
standingLabel = E:RGBToHex(color.r, color.g, color.b, nil, _G['FACTION_STANDING_LABEL'..reaction]..'|r')
--Prevent a division by zero
local maxMinDiff = max - min
if maxMinDiff == 0 then
maxMinDiff = 1
end
if isCapped then
text = format('%s: [%s]', name, isFriend and friendText or standingLabel)
else
if textFormat == 'PERCENT' then
text = format('%s: %d%% [%s]', name, ((value - min) / (maxMinDiff) * 100), isFriend and friendText or standingLabel)
elseif textFormat == 'CURMAX' then
text = format('%s: %s - %s [%s]', name, E:ShortValue(value - min), E:ShortValue(max - min), isFriend and friendText or standingLabel)
elseif textFormat == 'CURPERC' then
text = format('%s: %s - %d%% [%s]', name, E:ShortValue(value - min), ((value - min) / (maxMinDiff) * 100), isFriend and friendText or standingLabel)
elseif textFormat == 'CUR' then
text = format('%s: %s [%s]', name, E:ShortValue(value - min), isFriend and friendText or standingLabel)
elseif textFormat == 'REM' then
text = format('%s: %s [%s]', name, E:ShortValue((max - min) - (value-min)), isFriend and friendText or standingLabel)
elseif textFormat == 'CURREM' then
text = format('%s: %s - %s [%s]', name, E:ShortValue(value - min), E:ShortValue((max - min) - (value-min)), isFriend and friendText or standingLabel)
elseif textFormat == 'CURPERCREM' then
text = format('%s: %s - %d%% (%s) [%s]', name, E:ShortValue(value - min), ((value - min) / (maxMinDiff) * 100), E:ShortValue((max - min) - (value-min)), isFriend and friendText or standingLabel)
end
end
self.text:SetText(text)
end
local function OnEnter()
DT.tooltip:ClearLines()
local name, reaction, min, max, value, factionID = GetWatchedFactionInfo()
if factionID and C_Reputation_IsFactionParagon(factionID) then
local currentValue, threshold, _, hasRewardPending = C_Reputation_GetFactionParagonInfo(factionID)
if currentValue and threshold then
min, max = 0, threshold
value = currentValue % threshold
if hasRewardPending then
value = value + threshold
end
end
end
if name then
DT.tooltip:AddLine(name)
DT.tooltip:AddLine(' ')
local friendID, friendTextLevel, _
if factionID then friendID, _, _, _, _, _, friendTextLevel = GetFriendshipReputation(factionID) end
DT.tooltip:AddDoubleLine(STANDING..':', (friendID and friendTextLevel) or _G['FACTION_STANDING_LABEL'..reaction], 1, 1, 1)
if reaction ~= _G.MAX_REPUTATION_REACTION or C_Reputation_IsFactionParagon(factionID) then
DT.tooltip:AddDoubleLine(REPUTATION..':', format('%d / %d (%d%%)', value - min, max - min, (value - min) / ((max - min == 0) and max or (max - min)) * 100), 1, 1, 1)
end
DT.tooltip:Show()
end
end
local function OnClick()
ToggleCharacter('ReputationFrame')
end
DT:RegisterDatatext('Reputation', nil, {'UPDATE_FACTION', 'COMBAT_TEXT_UPDATE'}, OnEvent, nil, OnClick, OnEnter, nil, REPUTATION)

View File

@@ -0,0 +1,160 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local ipairs, wipe = ipairs, wipe
local format, next, strjoin = format, next, strjoin
local GetLootSpecialization = GetLootSpecialization
local GetNumSpecializations = GetNumSpecializations
local GetPvpTalentInfoByID = GetPvpTalentInfoByID
local GetSpecialization = GetSpecialization
local GetSpecializationInfo = GetSpecializationInfo
local GetTalentInfo = GetTalentInfo
local HideUIPanel = HideUIPanel
local IsShiftKeyDown = IsShiftKeyDown
local SetLootSpecialization = SetLootSpecialization
local SetSpecialization = SetSpecialization
local ShowUIPanel = ShowUIPanel
local LOOT = LOOT
local TALENTS = TALENTS
local PVP_TALENTS = PVP_TALENTS
local SELECT_LOOT_SPECIALIZATION = SELECT_LOOT_SPECIALIZATION
local LOOT_SPECIALIZATION_DEFAULT = LOOT_SPECIALIZATION_DEFAULT
local C_SpecializationInfo_GetAllSelectedPvpTalentIDs = C_SpecializationInfo.GetAllSelectedPvpTalentIDs
local displayString, lastPanel, active = ''
local activeString = strjoin('', '|cff00FF00' , _G.ACTIVE_PETS, '|r')
local inactiveString = strjoin('', '|cffFF0000', _G.FACTION_INACTIVE, '|r')
local menuList = {
{ text = SELECT_LOOT_SPECIALIZATION, isTitle = true, notCheckable = true },
{ checked = function() return GetLootSpecialization() == 0 end, func = function() SetLootSpecialization(0) end },
}
local specList = {
{ text = _G.SPECIALIZATION, isTitle = true, notCheckable = true },
}
local mainIcon = '|T%s:16:16:0:0:64:64:4:60:4:60|t'
local function OnEvent(self)
lastPanel = self
if #menuList == 2 then
for index = 1, GetNumSpecializations() do
local id, name, _, icon = GetSpecializationInfo(index)
if id then
menuList[index + 2] = { text = name, checked = function() return GetLootSpecialization() == id end, func = function() SetLootSpecialization(id) end }
specList[index + 1] = { text = format('|T%s:14:14:0:0:64:64:4:60:4:60|t %s', icon, name), checked = function() return GetSpecialization() == index end, func = function() SetSpecialization(index) end }
end
end
end
local specIndex = GetSpecialization()
local specialization = GetLootSpecialization()
local info = DT.SPECIALIZATION_CACHE[specIndex]
if not info then
self.text:SetText('N/A')
return
end
active = specIndex
local spec = format(mainIcon, info.icon)
if specialization == 0 or info.id == specialization then
self.text:SetFormattedText('%s %s', spec, info.name)
else
info = DT.SPECIALIZATION_CACHE[specialization]
self.text:SetFormattedText('%s: %s %s: %s', L["Spec"], spec, LOOT, format(mainIcon, info.icon))
end
end
local listIcon = '|T%s:16:16:0:0:50:50:4:46:4:46|t'
local function AddTexture(texture)
return texture and format(listIcon, texture) or ''
end
local function OnEnter()
DT.tooltip:ClearLines()
for i, info in ipairs(DT.SPECIALIZATION_CACHE) do
DT.tooltip:AddLine(strjoin(' ', format(displayString, info.name), AddTexture(info.icon), (i == active and activeString or inactiveString)), 1, 1, 1)
end
DT.tooltip:AddLine(' ')
local specialization = GetLootSpecialization()
local sameSpec = specialization == 0 and GetSpecialization()
local specIndex = DT.SPECIALIZATION_CACHE[sameSpec or specialization]
if specIndex and specIndex.name then
DT.tooltip:AddLine(format('|cffFFFFFF%s:|r %s', SELECT_LOOT_SPECIALIZATION, sameSpec and format(LOOT_SPECIALIZATION_DEFAULT, specIndex.name) or specIndex.name))
end
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(TALENTS, 0.69, 0.31, 0.31)
for i = 1, _G.MAX_TALENT_TIERS do
for j = 1, 3 do
local _, name, icon, selected = GetTalentInfo(i, j, 1)
if selected then
DT.tooltip:AddLine(AddTexture(icon)..' '..name)
end
end
end
local pvpTalents = C_SpecializationInfo_GetAllSelectedPvpTalentIDs()
if next(pvpTalents) then
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(PVP_TALENTS, 0.69, 0.31, 0.31)
for i, talentID in next, pvpTalents do
if i > 4 then break end
local _, name, icon, _, _, _, unlocked = GetPvpTalentInfoByID(talentID)
if name and unlocked then
DT.tooltip:AddLine(AddTexture(icon)..' '..name)
end
end
end
DT.tooltip:AddLine(' ')
DT.tooltip:AddLine(L["|cffFFFFFFLeft Click:|r Change Talent Specialization"])
DT.tooltip:AddLine(L["|cffFFFFFFShift + Left Click:|r Show Talent Specialization UI"])
DT.tooltip:AddLine(L["|cffFFFFFFRight Click:|r Change Loot Specialization"])
DT.tooltip:Show()
end
local function OnClick(self, button)
local specIndex = GetSpecialization()
if not specIndex then return end
if button == 'LeftButton' then
if not _G.PlayerTalentFrame then
_G.LoadAddOn('Blizzard_TalentUI')
end
if IsShiftKeyDown() then
if not _G.PlayerTalentFrame:IsShown() then
ShowUIPanel(_G.PlayerTalentFrame)
else
HideUIPanel(_G.PlayerTalentFrame)
end
else
DT:SetEasyMenuAnchor(DT.EasyMenu, self)
_G.EasyMenu(specList, DT.EasyMenu, nil, nil, nil, 'MENU')
end
else
local _, specName = GetSpecializationInfo(specIndex)
menuList[2].text = format(LOOT_SPECIALIZATION_DEFAULT, specName)
DT:SetEasyMenuAnchor(DT.EasyMenu, self)
_G.EasyMenu(menuList, DT.EasyMenu, nil, nil, nil, 'MENU')
end
end
local function ValueColorUpdate()
displayString = strjoin('', '|cffFFFFFF%s:|r ')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Talent/Loot Specialization', nil, {'CHARACTER_POINTS_CHANGED', 'PLAYER_TALENT_UPDATE', 'ACTIVE_TALENT_GROUP_CHANGED', 'PLAYER_LOOT_SPEC_UPDATED'}, OnEvent, nil, OnClick, OnEnter, nil, L["Talent/Loot Specialization"])

View File

@@ -0,0 +1,49 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local format, strjoin = format, strjoin
local BreakUpLargeNumbers = BreakUpLargeNumbers
local GetCombatRating = GetCombatRating
local GetCombatRatingBonus = GetCombatRatingBonus
local GetSpeed = GetSpeed
local CR_SPEED = CR_SPEED
local CR_SPEED_TOOLTIP = CR_SPEED_TOOLTIP
local FONT_COLOR_CODE_CLOSE = FONT_COLOR_CODE_CLOSE
local HIGHLIGHT_FONT_COLOR_CODE = HIGHLIGHT_FONT_COLOR_CODE
local PAPERDOLLFRAME_TOOLTIP_FORMAT = PAPERDOLLFRAME_TOOLTIP_FORMAT
local STAT_SPEED = STAT_SPEED
local STAT_CATEGORY_ENHANCEMENTS = STAT_CATEGORY_ENHANCEMENTS
local displayString, lastPanel = ''
local function OnEnter()
DT.tooltip:ClearLines()
local text = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_SPEED)..' '..format('%.2F%%', GetSpeed())..FONT_COLOR_CODE_CLOSE
local tooltip = format(CR_SPEED_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_SPEED)), GetCombatRatingBonus(CR_SPEED))
DT.tooltip:AddDoubleLine(text, nil, 1, 1, 1)
DT.tooltip:AddLine(tooltip, nil, nil, nil, true)
DT.tooltip:Show()
end
local function OnEvent(self)
local speed = GetSpeed()
if E.global.datatexts.settings.Speed.NoLabel then
self.text:SetFormattedText(displayString, speed)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Speed.Label ~= '' and E.global.datatexts.settings.Speed.Label or STAT_SPEED, speed)
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Speed.NoLabel and '' or '%s:', hex, '%.'..E.global.datatexts.settings.Speed.decimalLength..'f%%|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Speed', STAT_CATEGORY_ENHANCEMENTS, {"UNIT_STATS", "UNIT_AURA", "ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE", "PLAYER_DAMAGE_DONE_MODS"}, OnEvent, nil, nil, OnEnter, nil, STAT_SPEED, nil, ValueColorUpdate)

View File

@@ -0,0 +1,30 @@
local E, L, V, P, G = unpack(select(2, ...))
local DT = E:GetModule('DataTexts')
local strjoin = strjoin
local UnitStat = UnitStat
local STAT_CATEGORY_ATTRIBUTES = STAT_CATEGORY_ATTRIBUTES
local ITEM_MOD_STAMINA_SHORT = ITEM_MOD_STAMINA_SHORT
local LE_UNIT_STAT_STAMINA = LE_UNIT_STAT_STAMINA
local displayString, lastPanel = ''
local function OnEvent(self)
if E.global.datatexts.settings.Stamina.NoLabel then
self.text:SetFormattedText(displayString, UnitStat("player", LE_UNIT_STAT_STAMINA))
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Stamina.Label ~= '' and E.global.datatexts.settings.Stamina.Label or ITEM_MOD_STAMINA_SHORT..': ', UnitStat("player", LE_UNIT_STAT_STAMINA))
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Stamina.NoLabel and '' or '%s', hex, '%d|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Stamina', STAT_CATEGORY_ATTRIBUTES, { "UNIT_STATS", "UNIT_AURA", "ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE" }, OnEvent, nil, nil, nil, nil, ITEM_MOD_STAMINA_SHORT, nil, ValueColorUpdate)

View File

@@ -0,0 +1,30 @@
local E, L, V, P, G = unpack(select(2, ...))
local DT = E:GetModule('DataTexts')
local strjoin = strjoin
local UnitStat = UnitStat
local ITEM_MOD_STRENGTH_SHORT = ITEM_MOD_STRENGTH_SHORT
local LE_UNIT_STAT_STRENGTH = LE_UNIT_STAT_STRENGTH
local STAT_CATEGORY_ATTRIBUTES = STAT_CATEGORY_ATTRIBUTES
local displayString, lastPanel = ''
local function OnEvent(self)
if E.global.datatexts.settings.Strength.NoLabel then
self.text:SetFormattedText(displayString, UnitStat("player", LE_UNIT_STAT_STRENGTH))
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Strength.Label ~= '' and E.global.datatexts.settings.Strength.Label or ITEM_MOD_STRENGTH_SHORT..': ', UnitStat("player", LE_UNIT_STAT_STRENGTH))
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Strength.NoLabel and '' or '%s', hex, '%d|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Strength', STAT_CATEGORY_ATTRIBUTES, { "UNIT_STATS", "UNIT_AURA", "ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE" }, OnEvent, nil, nil, nil, nil, ITEM_MOD_STRENGTH_SHORT, nil, ValueColorUpdate)

View File

@@ -0,0 +1,271 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local collectgarbage = collectgarbage
local tremove, tinsert, sort, wipe, type = tremove, tinsert, sort, wipe, type
local ipairs, pairs, floor, format, strmatch = ipairs, pairs, floor, format, strmatch
local GetAddOnCPUUsage = GetAddOnCPUUsage
local GetAddOnInfo = GetAddOnInfo
local GetAddOnMemoryUsage = GetAddOnMemoryUsage
local GetAvailableBandwidth = GetAvailableBandwidth
local GetFileStreamingStatus = GetFileStreamingStatus
local GetBackgroundLoadingStatus = GetBackgroundLoadingStatus
local GetDownloadedPercentage = GetDownloadedPercentage
local SetCVar = SetCVar
local GetCVar = GetCVar
local ReloadUI = ReloadUI
local GetCVarBool = GetCVarBool
local GetFramerate = GetFramerate
local GetNetIpTypes = GetNetIpTypes
local GetNetStats = GetNetStats
local GetNumAddOns = GetNumAddOns
local IsAddOnLoaded = IsAddOnLoaded
local IsShiftKeyDown = IsShiftKeyDown
local IsControlKeyDown = IsControlKeyDown
local ResetCPUUsage = ResetCPUUsage
local UpdateAddOnCPUUsage = UpdateAddOnCPUUsage
local UpdateAddOnMemoryUsage = UpdateAddOnMemoryUsage
local InCombatLockdown = InCombatLockdown
local UNKNOWN = UNKNOWN
local statusColors = {
'|cff0CD809',
'|cffE8DA0F',
'|cffFF9000',
'|cffD80909'
}
local enteredFrame = false
local bandwidthString = '%.2f Mbps'
local percentageString = '%.2f%%'
local homeLatencyString = '%d ms'
local kiloByteString = '%d kb'
local megaByteString = '%.2f mb'
local profilingString = '%s%s|r |cffffffff/|r %s%s|r'
local cpuProfiling = GetCVar('scriptProfile') == '1'
local CombineAddOns = {
['DBM-Core'] = '^<DBM>',
['DataStore'] = '^DataStore',
['Altoholic'] = '^Altoholic',
['AtlasLoot'] = '^AtlasLoot',
['Details'] = '^Details!',
['RaiderIO'] = '^RaiderIO',
['BigWigs'] = '^BigWigs',
}
local function formatMem(memory)
local mult = 10^1
if memory >= 1024 then
return format(megaByteString, ((memory/1024) * mult) / mult)
else
return format(kiloByteString, (memory * mult) / mult)
end
end
local infoTable = {}
DT.SystemInfo = infoTable
local function BuildAddonList()
local addOnCount = GetNumAddOns()
if addOnCount == #infoTable then return end
wipe(infoTable)
for i = 1, addOnCount do
local name, title, _, loadable, reason = GetAddOnInfo(i)
if loadable or reason == 'DEMAND_LOADED' then
tinsert(infoTable, {name = name, index = i, title = title})
end
end
end
local function OnClick()
if IsShiftKeyDown() then
if IsControlKeyDown() then
SetCVar('scriptProfile', GetCVarBool('scriptProfile') and 0 or 1)
ReloadUI()
else
collectgarbage('collect')
ResetCPUUsage()
end
end
end
local function displayData(data, totalMEM, totalCPU)
if not data then return end
local name, mem, cpu = data.title, data.mem, data.cpu
if cpu then
local memRed, cpuRed = mem / totalMEM, cpu / totalCPU
local memGreen, cpuGreen = (1 - memRed) + .5, (1 - cpuRed) + .5
DT.tooltip:AddDoubleLine(name, format(profilingString, E:RGBToHex(memRed, memGreen, 0), formatMem(mem), E:RGBToHex(cpuRed, cpuGreen, 0), format(homeLatencyString, cpu)), 1, 1, 1)
else
local red = mem / totalMEM
local green = (1 - red) + .5
DT.tooltip:AddDoubleLine(name, formatMem(mem), 1, 1, 1, red or 1, green or 1, 0)
end
end
local function displaySort(a, b)
return a.sort > b.sort
end
local infoDisplay, ipTypes = {}, {'IPv4', 'IPv6'}
local function OnEnter(_, slow)
DT.tooltip:ClearLines()
enteredFrame = true
local _, _, homePing, worldPing = GetNetStats()
DT.tooltip:AddDoubleLine(L["Home Latency:"], format(homeLatencyString, homePing), .69, .31, .31, .84, .75, .65)
DT.tooltip:AddDoubleLine(L["World Latency:"], format(homeLatencyString, worldPing), .69, .31, .31, .84, .75, .65)
if GetCVarBool('useIPv6') then
local ipTypeHome, ipTypeWorld = GetNetIpTypes()
DT.tooltip:AddDoubleLine(L["Home Protocol:"], ipTypes[ipTypeHome or 0] or UNKNOWN, .69, .31, .31, .84, .75, .65)
DT.tooltip:AddDoubleLine(L["World Protocol:"], ipTypes[ipTypeWorld or 0] or UNKNOWN, .69, .31, .31, .84, .75, .65)
end
local Downloading = GetFileStreamingStatus() ~= 0 or GetBackgroundLoadingStatus() ~= 0
if Downloading then
DT.tooltip:AddDoubleLine(L["Bandwidth"] , format(bandwidthString, GetAvailableBandwidth()), .69, .31, .31, .84, .75, .65)
DT.tooltip:AddDoubleLine(L["Download"] , format(percentageString, GetDownloadedPercentage() * 100), .69, .31, .31, .84, .75, .65)
DT.tooltip:AddLine(' ')
end
if slow == 1 or not slow then
UpdateAddOnMemoryUsage()
end
if cpuProfiling and not slow then
UpdateAddOnCPUUsage()
end
wipe(infoDisplay)
local count, totalMEM, totalCPU = 0, 0, 0
local showByCPU = cpuProfiling and not IsShiftKeyDown()
for _, data in ipairs(infoTable) do
local i = data.index
if IsAddOnLoaded(i) then
local mem = GetAddOnMemoryUsage(i)
totalMEM = totalMEM + mem
local cpu
if cpuProfiling then
cpu = GetAddOnCPUUsage(i)
totalCPU = totalCPU + cpu
end
data.sort = (showByCPU and cpu) or mem
data.cpu = showByCPU and cpu
data.mem = mem
count = count + 1
infoDisplay[count] = data
if data.name == 'ElvUI' or data.name == 'ElvUI_OptionsUI' then
infoTable[data.name] = data
end
end
end
DT.tooltip:AddDoubleLine(L["AddOn Memory:"], formatMem(totalMEM), .69, .31, .31, .84, .75, .65)
if cpuProfiling then
DT.tooltip:AddDoubleLine(L["Total CPU:"], format(homeLatencyString, totalCPU), .69, .31, .31, .84, .75, .65)
end
DT.tooltip:AddLine(' ')
if not E.global.datatexts.settings.System.ShowOthers then
displayData(infoTable.ElvUI, totalMEM, totalCPU)
displayData(infoTable.ElvUI_OptionsUI, totalMEM, totalCPU)
DT.tooltip:AddLine(' ')
else
for addon, searchString in pairs(CombineAddOns) do
local addonIndex, memoryUsage, cpuUsage = 0, 0, 0
for i, data in pairs(infoDisplay) do
if data and data.name == addon then
addonIndex = i
break
end
end
for k, data in pairs(infoDisplay) do
if type(data) == 'table' then
local name, mem, cpu = data.title, data.mem, data.cpu
local stripName = E:StripString(data.title)
if name and (strmatch(stripName, searchString) or data.name == addon) then
if data.name ~= addon and stripName ~= addon then
memoryUsage = memoryUsage + mem;
if showByCPU and cpuProfiling then
cpuUsage = cpuUsage + cpu;
end
infoDisplay[k] = false
end
end
end
end
if addonIndex > 0 and infoDisplay[addonIndex] then
if memoryUsage > 0 then infoDisplay[addonIndex].mem = memoryUsage end
if cpuProfiling and cpuUsage > 0 then infoDisplay[addonIndex].cpu = cpuUsage end
end
end
for i = count, 1, -1 do
local data = infoDisplay[i]
if type(data) == 'boolean' then
tremove(infoDisplay, i)
end
end
sort(infoDisplay, displaySort)
for i = 1, count do
displayData(infoDisplay[i], totalMEM, totalCPU)
end
DT.tooltip:AddLine(' ')
if showByCPU then
DT.tooltip:AddLine(L["(Hold Shift) Memory Usage"])
end
end
DT.tooltip:AddLine(L["(Shift Click) Collect Garbage"])
DT.tooltip:AddLine(L["(Ctrl & Shift Click) Toggle CPU Profiling"])
DT.tooltip:Show()
end
local function OnLeave()
enteredFrame = false
end
local wait, count = 10, 0 -- initial delay for update (let the ui load)
local function OnUpdate(self, elapsed)
wait = wait - elapsed
if wait < 0 then
wait = 1
local framerate = floor(GetFramerate())
local _, _, _, latency = GetNetStats()
local fps = framerate >= 30 and 1 or (framerate >= 20 and framerate < 30) and 2 or (framerate >= 10 and framerate < 20) and 3 or 4
local ping = latency < 150 and 1 or (latency >= 150 and latency < 300) and 2 or (latency >= 300 and latency < 500) and 3 or 4
self.text:SetFormattedText(E.global.datatexts.settings.System.NoLabel and '%s%d|r | %s%d|r' or 'FPS: %s%d|r MS: %s%d|r', statusColors[fps], framerate, statusColors[ping], latency)
if not enteredFrame then return end
if InCombatLockdown() then
if count > 3 then
OnEnter(self)
count = 0
else
OnEnter(self, count)
count = count + 1
end
else
OnEnter(self)
end
end
end
DT:RegisterDatatext('System', nil, nil, BuildAddonList, OnUpdate, OnClick, OnEnter, OnLeave, L["System"])

View File

@@ -0,0 +1,38 @@
----------------------------------------------------------------------------------
-- This file is a blank datatext example template, this file will not be loaded.
----------------------------------------------------------------------------------
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local function Update(self, t)
end
local function OnEvent(self, event, ...)
end
local function Click()
end
local function OnEnter(self)
DT.tooltip:ClearLines()
-- code goes here
DT.tooltip:Show()
end
--[[
DT:RegisterDatatext(name, events, eventFunc, updateFunc, clickFunc, onEnterFunc, onLeaveFunc, localizedName)
name - name of the datatext (required)
events - must be a table with string values of event names to register
eventFunc - function that gets fired when an event gets triggered
updateFunc - onUpdate script target function
click - function to fire when clicking the datatext
onEnterFunc - function to fire OnEnter
onLeaveFunc - function to fire OnLeave, if not provided one will be set for you that hides the tooltip.
localizedName - localized name of the datetext
]]
DT:RegisterDatatext('DTName', 'Category', {'EVENT1', 'EVENT2', 'EVENT3'}, OnEvent, Update, Click, OnEnter)

319
Modules/DataTexts/Time.lua Normal file
View File

@@ -0,0 +1,319 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local _G = _G
local next, unpack = next, unpack
local format, strjoin = format, strjoin
local sort, tinsert = sort, tinsert
local date, utf8sub = date, string.utf8sub
local EJ_GetCurrentTier = EJ_GetCurrentTier
local EJ_GetInstanceByIndex = EJ_GetInstanceByIndex
local EJ_GetNumTiers = EJ_GetNumTiers
local EJ_SelectTier = EJ_SelectTier
local GetDifficultyInfo = GetDifficultyInfo
local C_DateAndTime_GetCurrentCalendarTime = C_DateAndTime.GetCurrentCalendarTime
local GetLocale = GetLocale
local GetNumSavedInstances = GetNumSavedInstances
local GetNumSavedWorldBosses = GetNumSavedWorldBosses
local GetNumWorldPVPAreas = GetNumWorldPVPAreas
local GetSavedInstanceInfo = GetSavedInstanceInfo
local GetSavedWorldBossInfo = GetSavedWorldBossInfo
local GetWorldPVPAreaInfo = GetWorldPVPAreaInfo
local RequestRaidInfo = RequestRaidInfo
local SecondsToTime = SecondsToTime
local InCombatLockdown = InCombatLockdown
local C_Map_GetAreaInfo = C_Map.GetAreaInfo
local QUEUE_TIME_UNAVAILABLE = QUEUE_TIME_UNAVAILABLE
local TIMEMANAGER_TOOLTIP_LOCALTIME = TIMEMANAGER_TOOLTIP_LOCALTIME
local TIMEMANAGER_TOOLTIP_REALMTIME = TIMEMANAGER_TOOLTIP_REALMTIME
local VOICE_CHAT_BATTLEGROUND = VOICE_CHAT_BATTLEGROUND
local WINTERGRASP_IN_PROGRESS = WINTERGRASP_IN_PROGRESS
local WORLD_BOSSES_TEXT = RAID_INFO_WORLD_BOSS
local APM = { _G.TIMEMANAGER_PM, _G.TIMEMANAGER_AM }
local ukDisplayFormat, europeDisplayFormat = '', ''
local europeDisplayFormat_nocolor = strjoin('', '%02d', ':|r%02d')
local ukDisplayFormat_nocolor = strjoin('', '', '%d', ':|r%02d', ' %s|r')
local lockoutInfoFormat = '%s%s %s |cffaaaaaa(%s, %s/%s)'
local lockoutInfoFormatNoEnc = '%s%s %s |cffaaaaaa(%s)'
local formatBattleGroundInfo = '%s: '
local lockoutColorExtended, lockoutColorNormal = { r=0.3,g=1,b=0.3 }, { r=.8,g=.8,b=.8 }
local enteredFrame = false
local Update, lastPanel
local function ValueColorUpdate(hex)
europeDisplayFormat = strjoin('', '%02d', hex, ':|r%02d')
ukDisplayFormat = strjoin('', '', '%d', hex, ':|r%02d', hex, ' %s|r')
if lastPanel ~= nil then
Update(lastPanel, 20000)
end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
local function ConvertTime(h, m)
local AmPm
if E.global.datatexts.settings.Time.time24 == true then
return h, m, -1
else
if h >= 12 then
if h > 12 then h = h - 12 end
AmPm = 1
else
if h == 0 then h = 12 end
AmPm = 2
end
end
return h, m, AmPm
end
local function CalculateTimeValues(tooltip)
if (tooltip and E.global.datatexts.settings.Time.localTime) or (not tooltip and not E.global.datatexts.settings.Time.localTime) then
local dateTable = C_DateAndTime_GetCurrentCalendarTime()
return ConvertTime(dateTable.hour, dateTable.minute)
else
local dateTable = date('*t')
return ConvertTime(dateTable.hour, dateTable.min)
end
end
local function Click()
if InCombatLockdown() then _G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT) return end
_G.GameTimeFrame:Click()
end
local function OnLeave()
enteredFrame = false
end
local InstanceNameByID = {
-- NOTE: for some reason the instanceID from EJ_GetInstanceByIndex doesn't match,
-- the instanceID from GetInstanceInfo, so use the collectIDs to find the ID to add.
[749] = C_Map_GetAreaInfo(3845) -- 'The Eye' -> 'Tempest Keep'
}
local locale = GetLocale()
if locale == 'deDE' then -- O.O
InstanceNameByID[1023] = 'Belagerung von Boralus' -- 'Die Belagerung von Boralus'
InstanceNameByID[1041] = 'Königsruh' -- 'Die Königsruh'
InstanceNameByID[1021] = 'Kronsteiganwesen' -- 'Das Kronsteiganwesen'
end
local instanceIconByName = {}
local collectIDs, collectedIDs = false -- for testing; mouse over the dt to show the tinspect table
local function GetInstanceImages(index, raid)
local instanceID, name, _, _, buttonImage = EJ_GetInstanceByIndex(index, raid)
while instanceID do
if collectIDs then
if not collectedIDs then
collectedIDs = {}
end
collectedIDs[instanceID] = name
end
instanceIconByName[InstanceNameByID[instanceID] or name] = buttonImage
index = index + 1
instanceID, name, _, _, buttonImage = EJ_GetInstanceByIndex(index, raid)
end
end
local krcntw = locale == 'koKR' or locale == 'zhCN' or locale == 'zhTW'
local difficultyTag = { -- Raid Finder, Normal, Heroic, Mythic
(krcntw and _G.PLAYER_DIFFICULTY3) or utf8sub(_G.PLAYER_DIFFICULTY3, 1, 1), -- R
(krcntw and _G.PLAYER_DIFFICULTY1) or utf8sub(_G.PLAYER_DIFFICULTY1, 1, 1), -- N
(krcntw and _G.PLAYER_DIFFICULTY2) or utf8sub(_G.PLAYER_DIFFICULTY2, 1, 1), -- H
(krcntw and _G.PLAYER_DIFFICULTY6) or utf8sub(_G.PLAYER_DIFFICULTY6, 1, 1) -- M
}
local function sortFunc(a,b) return a[1] < b[1] end
local collectedInstanceImages = false
local function OnEnter()
DT.tooltip:ClearLines()
if not enteredFrame then
enteredFrame = true
RequestRaidInfo()
end
if not collectedInstanceImages then
local numTiers = (EJ_GetNumTiers() or 0)
if numTiers > 0 then
local currentTier = EJ_GetCurrentTier()
-- Loop through the expansions to collect the textures
for i=1, numTiers do
EJ_SelectTier(i)
GetInstanceImages(1, false); -- Populate for dungeon icons
GetInstanceImages(1, true); -- Populate for raid icons
end
if collectIDs then
E:Dump(collectedIDs, true)
end
-- Set it back to the previous tier
if currentTier then
EJ_SelectTier(currentTier)
end
collectedInstanceImages = true
end
end
local addedHeader = false
for i = 1, GetNumWorldPVPAreas() do
local _, localizedName, isActive, _, startTime, canEnter = GetWorldPVPAreaInfo(i)
if isActive then
startTime = WINTERGRASP_IN_PROGRESS
elseif not startTime then
startTime = QUEUE_TIME_UNAVAILABLE
elseif startTime ~= 0 then
startTime = SecondsToTime(startTime, false, nil, 3)
end
if canEnter and startTime ~= 0 then
if not addedHeader then
DT.tooltip:AddLine(VOICE_CHAT_BATTLEGROUND)
addedHeader = true
end
DT.tooltip:AddDoubleLine(format(formatBattleGroundInfo, localizedName), startTime, 1, 1, 1, lockoutColorNormal.r, lockoutColorNormal.g, lockoutColorNormal.b)
end
end
local lockedInstances = {raids = {}, dungeons = {}}
for i = 1, GetNumSavedInstances() do
local name, _, _, difficulty, locked, extended, _, isRaid = GetSavedInstanceInfo(i)
if (locked or extended) and name then
local isLFR, isHeroicOrMythicDungeon = (difficulty == 7 or difficulty == 17), (difficulty == 2 or difficulty == 23)
local _, _, isHeroic, _, displayHeroic, displayMythic = GetDifficultyInfo(difficulty)
local sortName = name .. (displayMythic and 4 or (isHeroic or displayHeroic) and 3 or isLFR and 1 or 2)
local difficultyLetter = (displayMythic and difficultyTag[4] or (isHeroic or displayHeroic) and difficultyTag[3] or isLFR and difficultyTag[1] or difficultyTag[2])
local buttonImg = instanceIconByName[name] and format('|T%s:16:16:0:0:96:96:0:64:0:64|t ', instanceIconByName[name]) or ''
if isRaid then
tinsert(lockedInstances.raids, {sortName, difficultyLetter, buttonImg, {GetSavedInstanceInfo(i)}})
elseif isHeroicOrMythicDungeon then
tinsert(lockedInstances.dungeons, {sortName, difficultyLetter, buttonImg, {GetSavedInstanceInfo(i)}})
end
end
end
if next(lockedInstances.raids) then
if DT.tooltip:NumLines() > 0 then
DT.tooltip:AddLine(' ')
end
DT.tooltip:AddLine(L["Saved Raid(s)"])
sort(lockedInstances.raids, sortFunc)
for i = 1, #lockedInstances.raids do
local difficultyLetter = lockedInstances.raids[i][2]
local buttonImg = lockedInstances.raids[i][3]
local name, _, reset, _, _, extended, _, _, maxPlayers, _, numEncounters, encounterProgress = unpack(lockedInstances.raids[i][4])
local lockoutColor = extended and lockoutColorExtended or lockoutColorNormal
if numEncounters and numEncounters > 0 and (encounterProgress and encounterProgress > 0) then
DT.tooltip:AddDoubleLine(format(lockoutInfoFormat, buttonImg, maxPlayers, difficultyLetter, name, encounterProgress, numEncounters), SecondsToTime(reset, false, nil, 3), 1, 1, 1, lockoutColor.r, lockoutColor.g, lockoutColor.b)
else
DT.tooltip:AddDoubleLine(format(lockoutInfoFormatNoEnc, buttonImg, maxPlayers, difficultyLetter, name), SecondsToTime(reset, false, nil, 3), 1, 1, 1, lockoutColor.r, lockoutColor.g, lockoutColor.b)
end
end
end
if next(lockedInstances.dungeons) then
if DT.tooltip:NumLines() > 0 then
DT.tooltip:AddLine(' ')
end
DT.tooltip:AddLine(L["Saved Dungeon(s)"])
sort(lockedInstances.dungeons, sortFunc)
for i = 1,#lockedInstances.dungeons do
local difficultyLetter = lockedInstances.dungeons[i][2]
local buttonImg = lockedInstances.dungeons[i][3]
local name, _, reset, _, _, extended, _, _, maxPlayers, _, numEncounters, encounterProgress = unpack(lockedInstances.dungeons[i][4])
local lockoutColor = extended and lockoutColorExtended or lockoutColorNormal
if numEncounters and numEncounters > 0 and (encounterProgress and encounterProgress > 0) then
DT.tooltip:AddDoubleLine(format(lockoutInfoFormat, buttonImg, maxPlayers, difficultyLetter, name, encounterProgress, numEncounters), SecondsToTime(reset, false, nil, 3), 1, 1, 1, lockoutColor.r, lockoutColor.g, lockoutColor.b)
else
DT.tooltip:AddDoubleLine(format(lockoutInfoFormatNoEnc, buttonImg, maxPlayers, difficultyLetter, name), SecondsToTime(reset, false, nil, 3), 1, 1, 1, lockoutColor.r, lockoutColor.g, lockoutColor.b)
end
end
end
local addedLine = false
local worldbossLockoutList = {}
for i = 1, GetNumSavedWorldBosses() do
local name, _, reset = GetSavedWorldBossInfo(i)
tinsert(worldbossLockoutList, {name, reset})
end
sort(worldbossLockoutList, sortFunc)
for i = 1,#worldbossLockoutList do
local name, reset = unpack(worldbossLockoutList[i])
if reset then
if not addedLine then
if DT.tooltip:NumLines() > 0 then
DT.tooltip:AddLine(' ')
end
DT.tooltip:AddLine(WORLD_BOSSES_TEXT)
addedLine = true
end
DT.tooltip:AddDoubleLine(name, SecondsToTime(reset, true, nil, 3), 1, 1, 1, 0.8, 0.8, 0.8)
end
end
local Hr, Min, AmPm = CalculateTimeValues(true)
if DT.tooltip:NumLines() > 0 then
DT.tooltip:AddLine(' ')
end
if AmPm == -1 then
DT.tooltip:AddDoubleLine(E.global.datatexts.settings.Time.localTime and TIMEMANAGER_TOOLTIP_REALMTIME or TIMEMANAGER_TOOLTIP_LOCALTIME, format(europeDisplayFormat_nocolor, Hr, Min), 1, 1, 1, lockoutColorNormal.r, lockoutColorNormal.g, lockoutColorNormal.b)
else
DT.tooltip:AddDoubleLine(E.global.datatexts.settings.Time.localTime and TIMEMANAGER_TOOLTIP_REALMTIME or TIMEMANAGER_TOOLTIP_LOCALTIME, format(ukDisplayFormat_nocolor, Hr, Min, APM[AmPm]), 1, 1, 1, lockoutColorNormal.r, lockoutColorNormal.g, lockoutColorNormal.b)
end
DT.tooltip:Show()
end
local function OnEvent(self, event)
if event == 'UPDATE_INSTANCE_INFO' and enteredFrame then
OnEnter(self)
end
end
function Update(self, t)
self.timeElapsed = (self.timeElapsed or 5) - t
if self.timeElapsed > 0 then return end
self.timeElapsed = 5
if _G.GameTimeFrame.flashInvite then
E:Flash(self, 0.53, true)
else
E:StopFlash(self)
end
if enteredFrame then
OnEnter(self)
end
local Hr, Min, AmPm = CalculateTimeValues()
if AmPm == -1 then
self.text:SetFormattedText(europeDisplayFormat, Hr, Min)
else
self.text:SetFormattedText(ukDisplayFormat, Hr, Min, APM[AmPm])
end
lastPanel = self
end
DT:RegisterDatatext('Time', nil, {'UPDATE_INSTANCE_INFO'}, OnEvent, Update, Click, OnEnter, OnLeave, nil, nil, ValueColorUpdate)

View File

@@ -0,0 +1,53 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local DT = E:GetModule('DataTexts')
local format, strjoin = format, strjoin
local BreakUpLargeNumbers = BreakUpLargeNumbers
local GetCombatRating = GetCombatRating
local GetCombatRatingBonus = GetCombatRatingBonus
local GetVersatilityBonus = GetVersatilityBonus
local CR_VERSATILITY_DAMAGE_DONE = CR_VERSATILITY_DAMAGE_DONE
local CR_VERSATILITY_DAMAGE_TAKEN = CR_VERSATILITY_DAMAGE_TAKEN
local CR_VERSATILITY_TOOLTIP = CR_VERSATILITY_TOOLTIP
local FONT_COLOR_CODE_CLOSE = FONT_COLOR_CODE_CLOSE
local HIGHLIGHT_FONT_COLOR_CODE = HIGHLIGHT_FONT_COLOR_CODE
local STAT_VERSATILITY = STAT_VERSATILITY
local VERSATILITY_TOOLTIP_FORMAT = VERSATILITY_TOOLTIP_FORMAT
local STAT_CATEGORY_ENHANCEMENTS = STAT_CATEGORY_ENHANCEMENTS
local displayString, lastPanel = ''
local function OnEnter()
DT.tooltip:ClearLines()
local versatility = GetCombatRating(CR_VERSATILITY_DAMAGE_DONE)
local versatilityDamageBonus = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_DONE) + GetVersatilityBonus(CR_VERSATILITY_DAMAGE_DONE)
local versatilityDamageTakenReduction = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_TAKEN) + GetVersatilityBonus(CR_VERSATILITY_DAMAGE_TAKEN)
local text = HIGHLIGHT_FONT_COLOR_CODE..format(VERSATILITY_TOOLTIP_FORMAT, STAT_VERSATILITY, versatilityDamageBonus, versatilityDamageTakenReduction)..FONT_COLOR_CODE_CLOSE
local tooltip = format(CR_VERSATILITY_TOOLTIP, versatilityDamageBonus, versatilityDamageTakenReduction, BreakUpLargeNumbers(versatility), versatilityDamageBonus, versatilityDamageTakenReduction)
DT.tooltip:AddDoubleLine(text, nil, 1, 1, 1)
DT.tooltip:AddLine(tooltip, nil, nil, nil, true)
DT.tooltip:Show()
end
local function OnEvent(self)
local versatility = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_DONE) + GetVersatilityBonus(CR_VERSATILITY_DAMAGE_DONE)
if E.global.datatexts.settings.Versatility.NoLabel then
self.text:SetFormattedText(displayString, versatility)
else
self.text:SetFormattedText(displayString, E.global.datatexts.settings.Versatility.Label ~= '' and E.global.datatexts.settings.Versatility.Label or STAT_VERSATILITY, versatility)
end
lastPanel = self
end
local function ValueColorUpdate(hex)
displayString = strjoin('', E.global.datatexts.settings.Versatility.NoLabel and '' or '%s: ', hex, '%.'..E.global.datatexts.settings.Versatility.decimalLength..'f%%|r')
if lastPanel then OnEvent(lastPanel) end
end
E.valueColorUpdateFuncs[ValueColorUpdate] = true
DT:RegisterDatatext('Versatility', STAT_CATEGORY_ENHANCEMENTS, {"UNIT_STATS", "UNIT_AURA", "ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE", "PLAYER_DAMAGE_DONE_MODS"}, OnEvent, nil, nil, OnEnter, nil, STAT_VERSATILITY, nil, ValueColorUpdate)

15
Modules/Load_Modules.xml Normal file
View File

@@ -0,0 +1,15 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Include file='Maps\Load_Maps.xml'/>
<Include file='Auras\Load_Auras.xml'/>
<Include file='Nameplates\Load_Nameplates.xml'/>
<Include file='Tooltip\Load_Tooltip.xml'/>
<Include file='DataTexts\Load_DataTexts.xml'/>
<Include file='DataBars\Load_DataBars.xml'/>
<Include file='ActionBars\Load_ActionBars.xml'/>
<Include file='UnitFrames\Load_UnitFrames.xml'/>
<Include file='Chat\Load_Chat.xml'/>
<Include file='Bags\Load_Bags.xml'/>
<Include file='Misc\Load_Misc.xml'/>
<Include file='Skins\Load_Skins.xml'/>
<Include file='Blizzard\Load_Blizzard.xml'/>
</Ui>

View File

@@ -0,0 +1,4 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Script file='Minimap.lua'/>
<Script file='Worldmap.lua'/>
</Ui>

428
Modules/Maps/Minimap.lua Normal file
View File

@@ -0,0 +1,428 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule('Minimap')
local LSM = E.Libs.LSM
local _G = _G
local pairs = pairs
local tinsert = tinsert
local utf8sub = string.utf8sub
local CloseAllWindows = CloseAllWindows
local CloseMenus = CloseMenus
local PlaySound = PlaySound
local CreateFrame = CreateFrame
local GarrisonLandingPageMinimapButton_OnClick = GarrisonLandingPageMinimapButton_OnClick
local GetMinimapZoneText = GetMinimapZoneText
local GetZonePVPInfo = GetZonePVPInfo
local InCombatLockdown = InCombatLockdown
local IsAddOnLoaded = IsAddOnLoaded
local IsShiftKeyDown = IsShiftKeyDown
local MainMenuMicroButton_SetNormal = MainMenuMicroButton_SetNormal
local ShowUIPanel, HideUIPanel = ShowUIPanel, HideUIPanel
local ToggleAchievementFrame = ToggleAchievementFrame
local ToggleCharacter = ToggleCharacter
local ToggleCollectionsJournal = ToggleCollectionsJournal
local ToggleFrame = ToggleFrame
local ToggleFriendsFrame = ToggleFriendsFrame
local ToggleGuildFrame = ToggleGuildFrame
local ToggleHelpFrame = ToggleHelpFrame
local ToggleLFDParentFrame = ToggleLFDParentFrame
local hooksecurefunc = hooksecurefunc
local Minimap = _G.Minimap
-- GLOBALS: GetMinimapShape
--Create the new minimap tracking dropdown frame and initialize it
local ElvUIMiniMapTrackingDropDown = CreateFrame('Frame', 'ElvUIMiniMapTrackingDropDown', _G.UIParent, 'UIDropDownMenuTemplate')
ElvUIMiniMapTrackingDropDown:SetID(1)
ElvUIMiniMapTrackingDropDown:SetClampedToScreen(true)
ElvUIMiniMapTrackingDropDown:Hide()
_G.UIDropDownMenu_Initialize(ElvUIMiniMapTrackingDropDown, _G.MiniMapTrackingDropDown_Initialize, 'MENU')
ElvUIMiniMapTrackingDropDown.noResize = true
--Create the minimap micro menu
local menuFrame = CreateFrame('Frame', 'MinimapRightClickMenu', E.UIParent, 'BackdropTemplate')
local menuList = {
{text = _G.CHARACTER_BUTTON,
func = function() ToggleCharacter('PaperDollFrame') end},
{text = _G.SPELLBOOK_ABILITIES_BUTTON,
func = function()
if not _G.SpellBookFrame:IsShown() then
ShowUIPanel(_G.SpellBookFrame)
else
HideUIPanel(_G.SpellBookFrame)
end
end},
{text = _G.TALENTS_BUTTON,
func = function()
if not _G.PlayerTalentFrame then
_G.TalentFrame_LoadUI()
end
local PlayerTalentFrame = _G.PlayerTalentFrame
if not PlayerTalentFrame:IsShown() then
ShowUIPanel(PlayerTalentFrame)
else
HideUIPanel(PlayerTalentFrame)
end
end},
{text = _G.COLLECTIONS,
func = ToggleCollectionsJournal},
{text = _G.CHAT_CHANNELS,
func = _G.ToggleChannelFrame},
{text = _G.TIMEMANAGER_TITLE,
func = function() ToggleFrame(_G.TimeManagerFrame) end},
{text = _G.ACHIEVEMENT_BUTTON,
func = ToggleAchievementFrame},
{text = _G.SOCIAL_BUTTON,
func = ToggleFriendsFrame},
{text = L["Calendar"],
func = function() _G.GameTimeFrame:Click() end},
{text = _G.GARRISON_TYPE_8_0_LANDING_PAGE_TITLE,
func = function() GarrisonLandingPageMinimapButton_OnClick(_G.GarrisonLandingPageMinimapButton) end},
{text = _G.ACHIEVEMENTS_GUILD_TAB,
func = ToggleGuildFrame},
{text = _G.LFG_TITLE,
func = ToggleLFDParentFrame},
{text = _G.ENCOUNTER_JOURNAL,
func = function()
if not IsAddOnLoaded('Blizzard_EncounterJournal') then
_G.EncounterJournal_LoadUI()
end
ToggleFrame(_G.EncounterJournal)
end},
{text = _G.MAINMENU_BUTTON,
func = function()
if not _G.GameMenuFrame:IsShown() then
if _G.VideoOptionsFrame:IsShown() then
_G.VideoOptionsFrameCancel:Click()
elseif _G.AudioOptionsFrame:IsShown() then
_G.AudioOptionsFrameCancel:Click()
elseif _G.InterfaceOptionsFrame:IsShown() then
_G.InterfaceOptionsFrameCancel:Click()
end
CloseMenus()
CloseAllWindows()
PlaySound(850) --IG_MAINMENU_OPEN
ShowUIPanel(_G.GameMenuFrame)
else
PlaySound(854) --IG_MAINMENU_QUIT
HideUIPanel(_G.GameMenuFrame)
MainMenuMicroButton_SetNormal()
end
end}
}
tinsert(menuList, {text = _G.BLIZZARD_STORE, func = function() _G.StoreMicroButton:Click() end})
tinsert(menuList, {text = _G.HELP_BUTTON, func = ToggleHelpFrame})
function M:HandleGarrisonButton()
local button = _G.GarrisonLandingPageMinimapButton
if button then
local db = E.db.general.minimap.icons.classHall
local scale, pos = db.scale or 1, db.position or 'BOTTOMLEFT'
button:ClearAllPoints()
button:Point(pos, Minimap, pos, db.xOffset or 0, db.yOffset or 0)
button:SetScale(scale)
local box = _G.GarrisonLandingPageTutorialBox
if box then
box:SetScale(1/scale)
box:SetClampedToScreen(true)
end
end
end
function M:GetLocTextColor()
local pvpType = GetZonePVPInfo()
if pvpType == 'arena' then
return 0.84, 0.03, 0.03
elseif pvpType == 'friendly' then
return 0.05, 0.85, 0.03
elseif pvpType == 'contested' then
return 0.9, 0.85, 0.05
elseif pvpType == 'hostile' then
return 0.84, 0.03, 0.03
elseif pvpType == 'sanctuary' then
return 0.035, 0.58, 0.84
elseif pvpType == 'combat' then
return 0.84, 0.03, 0.03
else
return 0.9, 0.85, 0.05
end
end
function M:SetupHybridMinimap()
local MapCanvas = _G.HybridMinimap.MapCanvas
MapCanvas:SetMaskTexture(E.Media.Textures.White8x8)
MapCanvas:SetScript('OnMouseWheel', M.Minimap_OnMouseWheel)
MapCanvas:SetScript('OnMouseDown', M.MapCanvas_OnMouseDown)
MapCanvas:SetScript('OnMouseUp', E.noop)
end
function M:ADDON_LOADED(_, addon)
if addon == 'Blizzard_TimeManager' then
_G.TimeManagerClockButton:Kill()
elseif addon == 'Blizzard_FeedbackUI' then
_G.FeedbackUIButton:Kill()
elseif addon == 'Blizzard_HybridMinimap' then
M:SetupHybridMinimap()
end
end
function M:Minimap_OnMouseDown(btn)
_G.HideDropDownMenu(1, nil, ElvUIMiniMapTrackingDropDown)
menuFrame:Hide()
local position = self:GetPoint()
if btn == 'MiddleButton' or (btn == 'RightButton' and IsShiftKeyDown()) then
if InCombatLockdown() then _G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT) return end
if position:match('LEFT') then
E:DropDown(menuList, menuFrame)
else
E:DropDown(menuList, menuFrame, -160, 0)
end
elseif btn == 'RightButton' then
_G.ToggleDropDownMenu(1, nil, ElvUIMiniMapTrackingDropDown, 'cursor')
else
_G.Minimap_OnClick(self)
end
end
function M:MapCanvas_OnMouseDown(btn)
_G.HideDropDownMenu(1, nil, ElvUIMiniMapTrackingDropDown)
menuFrame:Hide()
local position = self:GetPoint()
if btn == 'MiddleButton' or (btn == 'RightButton' and IsShiftKeyDown()) then
if InCombatLockdown() then _G.UIErrorsFrame:AddMessage(E.InfoColor.._G.ERR_NOT_IN_COMBAT) return end
if position:match('LEFT') then
E:DropDown(menuList, menuFrame)
else
E:DropDown(menuList, menuFrame, -160, 0)
end
elseif btn == 'RightButton' then
_G.ToggleDropDownMenu(1, nil, ElvUIMiniMapTrackingDropDown, 'cursor')
end
end
function M:Minimap_OnMouseWheel(d)
if d > 0 then
_G.MinimapZoomIn:Click()
elseif d < 0 then
_G.MinimapZoomOut:Click()
end
end
function M:Update_ZoneText()
if E.db.general.minimap.locationText == 'HIDE' then return end
Minimap.location:FontTemplate(LSM:Fetch('font', E.db.general.minimap.locationFont), E.db.general.minimap.locationFontSize, E.db.general.minimap.locationFontOutline)
Minimap.location:SetText(utf8sub(GetMinimapZoneText(), 1, 46))
Minimap.location:SetTextColor(M:GetLocTextColor())
end
do
local isResetting
local function ResetZoom()
Minimap:SetZoom(0)
_G.MinimapZoomIn:Enable(); --Reset enabled state of buttons
_G.MinimapZoomOut:Disable()
isResetting = false
end
local function SetupZoomReset()
if E.db.general.minimap.resetZoom.enable and not isResetting then
isResetting = true
E:Delay(E.db.general.minimap.resetZoom.time, ResetZoom)
end
end
hooksecurefunc(Minimap, 'SetZoom', SetupZoomReset)
end
function M:UpdateSettings()
if not E.private.general.minimap.enable then return end
E.MinimapSize = E.db.general.minimap.size or Minimap:GetWidth()
local MinimapPanel, MMHolder = _G.MinimapPanel, _G.MMHolder
MinimapPanel:SetShown(E.db.datatexts.panels.MinimapPanel.enable)
local borderWidth, borderHeight = E.PixelMode and 2 or 6, E.PixelMode and 2 or 8
local panelSize, joinPanel = (MinimapPanel:IsShown() and MinimapPanel:GetHeight()) or (E.PixelMode and 1 or -1), 1
local height, width = E.MinimapSize + (panelSize - joinPanel), E.MinimapSize
MMHolder:Size(width + borderWidth, height + borderHeight)
_G.MinimapMover:Size(width + borderWidth, height + borderHeight)
local mmOffset = E.PixelMode and 1 or 3
Minimap:ClearAllPoints()
Minimap:Point('TOPRIGHT', MMHolder, 'TOPRIGHT', -mmOffset, -mmOffset)
Minimap:Size(E.MinimapSize, E.MinimapSize)
Minimap.location:Width(E.MinimapSize)
if E.db.general.minimap.locationText ~= 'SHOW' then
Minimap.location:Hide()
else
Minimap.location:Show()
end
M.HandleGarrisonButton()
local GameTimeFrame = _G.GameTimeFrame
if GameTimeFrame then
if E.private.general.minimap.hideCalendar then
GameTimeFrame:Hide()
else
local pos = E.db.general.minimap.icons.calendar.position or 'TOPRIGHT'
local scale = E.db.general.minimap.icons.calendar.scale or 1
GameTimeFrame:ClearAllPoints()
GameTimeFrame:Point(pos, Minimap, pos, E.db.general.minimap.icons.calendar.xOffset or 0, E.db.general.minimap.icons.calendar.yOffset or 0)
GameTimeFrame:SetScale(scale)
GameTimeFrame:Show()
end
end
local MiniMapMailFrame = _G.MiniMapMailFrame
if MiniMapMailFrame then
local pos = E.db.general.minimap.icons.mail.position or 'TOPRIGHT'
local scale = E.db.general.minimap.icons.mail.scale or 1
MiniMapMailFrame:ClearAllPoints()
MiniMapMailFrame:Point(pos, Minimap, pos, E.db.general.minimap.icons.mail.xOffset or 3, E.db.general.minimap.icons.mail.yOffset or 4)
MiniMapMailFrame:SetScale(scale)
end
local QueueStatusMinimapButton = _G.QueueStatusMinimapButton
if QueueStatusMinimapButton then
local pos = E.db.general.minimap.icons.lfgEye.position or 'BOTTOMRIGHT'
local scale = E.db.general.minimap.icons.lfgEye.scale or 1
QueueStatusMinimapButton:ClearAllPoints()
QueueStatusMinimapButton:Point(pos, Minimap, pos, E.db.general.minimap.icons.lfgEye.xOffset or 3, E.db.general.minimap.icons.lfgEye.yOffset or 0)
QueueStatusMinimapButton:SetScale(scale)
_G.QueueStatusFrame:SetScale(scale)
end
local MiniMapInstanceDifficulty = _G.MiniMapInstanceDifficulty
local GuildInstanceDifficulty = _G.GuildInstanceDifficulty
if MiniMapInstanceDifficulty and GuildInstanceDifficulty then
local pos = E.db.general.minimap.icons.difficulty.position or 'TOPLEFT'
local scale = E.db.general.minimap.icons.difficulty.scale or 1
local x = E.db.general.minimap.icons.difficulty.xOffset or 0
local y = E.db.general.minimap.icons.difficulty.yOffset or 0
MiniMapInstanceDifficulty:ClearAllPoints()
MiniMapInstanceDifficulty:Point(pos, Minimap, pos, x, y)
MiniMapInstanceDifficulty:SetScale(scale)
GuildInstanceDifficulty:ClearAllPoints()
GuildInstanceDifficulty:Point(pos, Minimap, pos, x, y)
GuildInstanceDifficulty:SetScale(scale)
end
local MiniMapChallengeMode = _G.MiniMapChallengeMode
if MiniMapChallengeMode then
local pos = E.db.general.minimap.icons.challengeMode.position or 'TOPLEFT'
local scale = E.db.general.minimap.icons.challengeMode.scale or 1
MiniMapChallengeMode:ClearAllPoints()
MiniMapChallengeMode:Point(pos, Minimap, pos, E.db.general.minimap.icons.challengeMode.xOffset or 8, E.db.general.minimap.icons.challengeMode.yOffset or -8)
MiniMapChallengeMode:SetScale(scale)
end
end
local function MinimapPostDrag()
_G.MinimapBackdrop:ClearAllPoints()
_G.MinimapBackdrop:SetAllPoints(_G.Minimap)
end
function M:GetMinimapShape()
return 'SQUARE'
end
function M:SetGetMinimapShape()
GetMinimapShape = M.GetMinimapShape --This is just to support for other mods
Minimap:Size(E.db.general.minimap.size, E.db.general.minimap.size)
end
function M:Initialize()
if not E.private.general.minimap.enable then return end
self.Initialized = true
menuFrame:SetTemplate('Transparent')
local mmholder = CreateFrame('Frame', 'MMHolder', Minimap)
mmholder:Point('TOPRIGHT', E.UIParent, 'TOPRIGHT', -3, -3)
mmholder:Size(Minimap:GetSize())
Minimap:SetQuestBlobRingAlpha(0)
Minimap:SetArchBlobRingAlpha(0)
Minimap:CreateBackdrop()
Minimap:SetFrameLevel(Minimap:GetFrameLevel() + 2)
Minimap:ClearAllPoints()
Minimap:Point('TOPRIGHT', mmholder, 'TOPRIGHT', -E.Border, -E.Border)
Minimap:HookScript('OnEnter', function(mm) if E.db.general.minimap.locationText == 'MOUSEOVER' then mm.location:Show() end end)
Minimap:HookScript('OnLeave', function(mm) if E.db.general.minimap.locationText == 'MOUSEOVER' then mm.location:Hide() end end)
Minimap.location = Minimap:CreateFontString(nil, 'OVERLAY')
Minimap.location:FontTemplate(nil, nil, 'OUTLINE')
Minimap.location:Point('TOP', Minimap, 'TOP', 0, -2)
Minimap.location:SetJustifyH('CENTER')
Minimap.location:SetJustifyV('MIDDLE')
if E.db.general.minimap.locationText ~= 'SHOW' then
Minimap.location:Hide()
end
local frames = {
_G.MinimapBorder,
_G.MinimapBorderTop,
_G.MinimapZoomIn,
_G.MinimapZoomOut,
_G.MinimapNorthTag,
_G.MinimapZoneTextButton,
_G.MiniMapTracking,
_G.MiniMapMailBorder
}
for _, frame in pairs(frames) do
frame:Kill()
end
_G.MiniMapMailIcon:SetTexture(E.Media.Textures.Mail)
-- Every GarrisonLandingPageMinimapButton_UpdateIcon() call reanchor the button
hooksecurefunc('GarrisonLandingPageMinimapButton_UpdateIcon', M.HandleGarrisonButton)
--Hide the BlopRing on Minimap
Minimap:SetArchBlobRingScalar(0)
Minimap:SetQuestBlobRingScalar(0)
if E.private.general.minimap.hideClassHallReport then
_G.GarrisonLandingPageMinimapButton:Kill()
_G.GarrisonLandingPageMinimapButton.IsShown = function() return true end
end
_G.QueueStatusMinimapButtonBorder:Hide()
_G.QueueStatusFrame:SetClampedToScreen(true)
_G.MiniMapWorldMapButton:Hide()
_G.MiniMapInstanceDifficulty:SetParent(Minimap)
_G.GuildInstanceDifficulty:SetParent(Minimap)
_G.MiniMapChallengeMode:SetParent(Minimap)
if _G.TimeManagerClockButton then _G.TimeManagerClockButton:Kill() end
if _G.FeedbackUIButton then _G.FeedbackUIButton:Kill() end
if _G.HybridMinimap then M:SetupHybridMinimap() end
E:CreateMover(_G.MMHolder, 'MinimapMover', L["Minimap"], nil, nil, MinimapPostDrag, nil, nil, 'maps,minimap')
_G.MinimapCluster:EnableMouse(false)
Minimap:EnableMouseWheel(true)
Minimap:SetScript('OnMouseWheel', M.Minimap_OnMouseWheel)
Minimap:SetScript('OnMouseDown', M.Minimap_OnMouseDown)
Minimap:SetScript('OnMouseUp', E.noop)
self:RegisterEvent('PLAYER_ENTERING_WORLD', 'Update_ZoneText')
self:RegisterEvent('ZONE_CHANGED_NEW_AREA', 'Update_ZoneText')
self:RegisterEvent('ZONE_CHANGED_INDOORS', 'Update_ZoneText')
self:RegisterEvent('ZONE_CHANGED', 'Update_ZoneText')
self:RegisterEvent('ADDON_LOADED')
self:UpdateSettings()
end
E:RegisterModule(M:GetName())

264
Modules/Maps/Worldmap.lua Normal file
View File

@@ -0,0 +1,264 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule('WorldMap')
local _G = _G
local strfind = strfind
local CreateFrame = CreateFrame
local SetUIPanelAttribute = SetUIPanelAttribute
local MOUSE_LABEL = MOUSE_LABEL:gsub('|[TA].-|[ta]','')
local PLAYER = PLAYER
local hooksecurefunc = hooksecurefunc
local IsPlayerMoving = IsPlayerMoving
local PlayerMovementFrameFader = PlayerMovementFrameFader
-- GLOBALS: CoordsHolder
local INVERTED_POINTS = {
TOPLEFT = 'BOTTOMLEFT',
TOPRIGHT = 'BOTTOMRIGHT',
BOTTOMLEFT = 'TOPLEFT',
BOTTOMRIGHT = 'TOPRIGHT',
TOP = 'BOTTOM',
BOTTOM = 'TOP',
}
-- this will be updated later
local smallerMapScale = 0.8
function M:SetLargeWorldMap()
local WorldMapFrame = _G.WorldMapFrame
WorldMapFrame:SetParent(E.UIParent)
WorldMapFrame:SetScale(1)
WorldMapFrame.ScrollContainer.Child:SetScale(smallerMapScale)
if WorldMapFrame:GetAttribute('UIPanelLayout-area') ~= 'center' then
SetUIPanelAttribute(WorldMapFrame, 'area', 'center');
end
if WorldMapFrame:GetAttribute('UIPanelLayout-allowOtherPanels') ~= true then
SetUIPanelAttribute(WorldMapFrame, 'allowOtherPanels', true)
end
WorldMapFrame:OnFrameSizeChanged()
if WorldMapFrame:GetMapID() then
WorldMapFrame.NavBar:Refresh()
end
end
function M:UpdateMaximizedSize()
local WorldMapFrame = _G.WorldMapFrame
local width, height = WorldMapFrame:GetSize()
local magicNumber = (1 - smallerMapScale) * 100
WorldMapFrame:Size((width * smallerMapScale) - (magicNumber + 2), (height * smallerMapScale) - 2)
end
function M:SynchronizeDisplayState()
local WorldMapFrame = _G.WorldMapFrame
if WorldMapFrame:IsMaximized() then
WorldMapFrame:ClearAllPoints()
WorldMapFrame:Point('CENTER', E.UIParent)
end
end
function M:SetSmallWorldMap()
local WorldMapFrame = _G.WorldMapFrame
if not WorldMapFrame:IsMaximized() then
WorldMapFrame:ClearAllPoints()
WorldMapFrame:Point('TOPLEFT', E.UIParent, 'TOPLEFT', 16, -94)
end
end
local inRestrictedArea = false
function M:UpdateRestrictedArea()
if E.MapInfo.x and E.MapInfo.y then
inRestrictedArea = false
else
inRestrictedArea = true
CoordsHolder.playerCoords:SetFormattedText('%s: %s', PLAYER, 'N/A')
end
end
function M:UpdateCoords(OnShow)
local WorldMapFrame = _G.WorldMapFrame
if not WorldMapFrame:IsShown() then return end
if WorldMapFrame.ScrollContainer:IsMouseOver() then
local x, y = WorldMapFrame.ScrollContainer:GetNormalizedCursorPosition()
if x and y and x >= 0 and y >= 0 then
CoordsHolder.mouseCoords:SetFormattedText('%s: %.2f, %.2f', MOUSE_LABEL, x * 100, y * 100)
else
CoordsHolder.mouseCoords:SetText('')
end
else
CoordsHolder.mouseCoords:SetText('')
end
if not inRestrictedArea and (OnShow or E.MapInfo.coordsWatching) then
if E.MapInfo.x and E.MapInfo.y then
CoordsHolder.playerCoords:SetFormattedText('%s: %.2f, %.2f', PLAYER, (E.MapInfo.xText or 0), (E.MapInfo.yText or 0))
else
CoordsHolder.playerCoords:SetFormattedText('%s: %s', PLAYER, 'N/A')
end
end
end
function M:PositionCoords()
local db = E.global.general.WorldMapCoordinates
local position = db.position
local xOffset = db.xOffset
local yOffset = db.yOffset
local x, y = 5, 5
if strfind(position, 'RIGHT') then x = -5 end
if strfind(position, 'TOP') then y = -5 end
CoordsHolder.playerCoords:ClearAllPoints()
CoordsHolder.playerCoords:Point(position, _G.WorldMapFrame.BorderFrame, position, x + xOffset, y + yOffset)
CoordsHolder.mouseCoords:ClearAllPoints()
CoordsHolder.mouseCoords:Point(position, CoordsHolder.playerCoords, INVERTED_POINTS[position], 0, y)
end
function M:MapShouldFade()
-- normally we would check GetCVarBool('mapFade') here instead of the setting
return E.global.general.fadeMapWhenMoving and not _G.WorldMapFrame:IsMouseOver()
end
function M:MapFadeOnUpdate(elapsed)
self.elapsed = (self.elapsed or 0) + elapsed
if self.elapsed > 0.1 then
self.elapsed = 0
local object = self.FadeObject
local settings = object and object.FadeSettings
if not settings then return end
local fadeOut = IsPlayerMoving() and (not settings.fadePredicate or settings.fadePredicate())
local endAlpha = (fadeOut and (settings.minAlpha or 0.5)) or settings.maxAlpha or 1
local startAlpha = _G.WorldMapFrame:GetAlpha()
object.timeToFade = settings.durationSec or 0.5
object.startAlpha = startAlpha
object.endAlpha = endAlpha
object.diffAlpha = endAlpha - startAlpha
if object.fadeTimer then
object.fadeTimer = nil
end
E:UIFrameFade(_G.WorldMapFrame, object)
end
end
local fadeFrame
function M:StopMapFromFading()
if fadeFrame then
fadeFrame:Hide()
end
end
function M:EnableMapFading(frame)
if not fadeFrame then
fadeFrame = CreateFrame('FRAME')
fadeFrame:SetScript('OnUpdate', M.MapFadeOnUpdate)
frame:HookScript('OnHide', M.StopMapFromFading)
end
if not fadeFrame.FadeObject then fadeFrame.FadeObject = {} end
if not fadeFrame.FadeObject.FadeSettings then fadeFrame.FadeObject.FadeSettings = {} end
local settings = fadeFrame.FadeObject.FadeSettings
settings.fadePredicate = M.MapShouldFade
settings.durationSec = E.global.general.fadeMapDuration
settings.minAlpha = E.global.general.mapAlphaWhenMoving
settings.maxAlpha = 1
fadeFrame:Show()
end
function M:UpdateMapFade(minAlpha, maxAlpha, durationSec, fadePredicate) -- self is frame
if self:IsShown() and (self == _G.WorldMapFrame and fadePredicate ~= M.MapShouldFade) then
-- blizzard spams code in OnUpdate and doesnt finish their functions, so we shut their fader down :L
PlayerMovementFrameFader.RemoveFrame(self)
-- replacement function which is complete :3
if E.global.general.fadeMapWhenMoving then
M:EnableMapFading(self)
end
-- we can't use the blizzard function because `durationSec` was never finished being implimented?
-- PlayerMovementFrameFader.AddDeferredFrame(self, E.global.general.mapAlphaWhenMoving, 1, E.global.general.fadeMapDuration, M.MapShouldFade)
end
end
function M:Initialize()
self.Initialized = true
if not E.private.general.worldMap then
return
end
local WorldMapFrame = _G.WorldMapFrame
if E.global.general.WorldMapCoordinates.enable then
local CoordsHolder = CreateFrame('Frame', 'CoordsHolder', WorldMapFrame)
CoordsHolder:SetFrameLevel(WorldMapFrame.BorderFrame:GetFrameLevel() + 10)
CoordsHolder:SetFrameStrata(WorldMapFrame.BorderFrame:GetFrameStrata())
CoordsHolder.playerCoords = CoordsHolder:CreateFontString(nil, 'OVERLAY')
CoordsHolder.mouseCoords = CoordsHolder:CreateFontString(nil, 'OVERLAY')
CoordsHolder.playerCoords:SetTextColor(1, 1 ,0)
CoordsHolder.mouseCoords:SetTextColor(1, 1 ,0)
CoordsHolder.playerCoords:SetFontObject(_G.NumberFontNormal)
CoordsHolder.mouseCoords:SetFontObject(_G.NumberFontNormal)
CoordsHolder.playerCoords:SetText(PLAYER..': 0, 0')
CoordsHolder.mouseCoords:SetText(MOUSE_LABEL..': 0, 0')
WorldMapFrame:HookScript('OnShow', function()
if not M.CoordsTimer then
M:UpdateCoords(true)
M.CoordsTimer = M:ScheduleRepeatingTimer('UpdateCoords', 0.1)
end
end)
WorldMapFrame:HookScript('OnHide', function()
M:CancelTimer(M.CoordsTimer)
M.CoordsTimer = nil
end)
M:PositionCoords()
E:RegisterEventForObject('LOADING_SCREEN_DISABLED', E.MapInfo, M.UpdateRestrictedArea)
E:RegisterEventForObject('ZONE_CHANGED_NEW_AREA', E.MapInfo, M.UpdateRestrictedArea)
E:RegisterEventForObject('ZONE_CHANGED_INDOORS', E.MapInfo, M.UpdateRestrictedArea)
E:RegisterEventForObject('ZONE_CHANGED', E.MapInfo, M.UpdateRestrictedArea)
end
if E.global.general.smallerWorldMap then
smallerMapScale = E.global.general.smallerWorldMapScale
WorldMapFrame.BlackoutFrame.Blackout:SetTexture()
WorldMapFrame.BlackoutFrame:EnableMouse(false)
self:SecureHook(WorldMapFrame, 'Maximize', 'SetLargeWorldMap')
self:SecureHook(WorldMapFrame, 'Minimize', 'SetSmallWorldMap')
self:SecureHook(WorldMapFrame, 'SynchronizeDisplayState')
self:SecureHook(WorldMapFrame, 'UpdateMaximizedSize')
self:SecureHookScript(WorldMapFrame, 'OnShow', function()
if WorldMapFrame:IsMaximized() then
WorldMapFrame:UpdateMaximizedSize()
self:SetLargeWorldMap()
else
self:SetSmallWorldMap()
end
M:Unhook(WorldMapFrame, 'OnShow', nil)
end)
end
-- This lets us control the maps fading function
hooksecurefunc(PlayerMovementFrameFader, 'AddDeferredFrame', M.UpdateMapFade)
-- Enable/Disable map fading when moving
-- currently we dont need to touch this cvar because we have our own control for this currently
-- see the comment in `M:UpdateMapFade` about `durationSec` for more information
-- SetCVar('mapFade', E.global.general.fadeMapWhenMoving and 1 or 0)
end
E:RegisterInitialModule(M:GetName())

346
Modules/Misc/AFK.lua Normal file
View File

@@ -0,0 +1,346 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local AFK = E:GetModule('AFK')
local CH = E:GetModule('Chat')
local _G = _G
local floor = floor
local unpack = unpack
local tostring, pcall = tostring, pcall
local format, strsub, gsub = format, strsub, gsub
local Chat_GetChatCategory = Chat_GetChatCategory
local ChatFrame_GetMobileEmbeddedTexture = ChatFrame_GetMobileEmbeddedTexture
local ChatHistory_GetAccessID = ChatHistory_GetAccessID
local CloseAllWindows = CloseAllWindows
local CreateFrame = CreateFrame
local GetBattlefieldStatus = GetBattlefieldStatus
local GetGuildInfo = GetGuildInfo
local GetScreenHeight = GetScreenHeight
local GetScreenWidth = GetScreenWidth
local GetTime = GetTime
local InCombatLockdown = InCombatLockdown
local IsInGuild = IsInGuild
local IsShiftKeyDown = IsShiftKeyDown
local MoveViewLeftStart = MoveViewLeftStart
local MoveViewLeftStop = MoveViewLeftStop
local PVEFrame_ToggleFrame = PVEFrame_ToggleFrame
local RemoveExtraSpaces = RemoveExtraSpaces
local Screenshot = Screenshot
local SetCVar = SetCVar
local UnitCastingInfo = UnitCastingInfo
local UnitIsAFK = UnitIsAFK
local CinematicFrame = CinematicFrame
local MovieFrame = MovieFrame
local C_PetBattles_IsInBattle = C_PetBattles.IsInBattle
local DNDstr = _G.DND
local AFKstr = _G.AFK
local CAMERA_SPEED = 0.035
local ignoreKeys = {
LALT = true,
LSHIFT = true,
RSHIFT = true,
}
local printKeys = {
PRINTSCREEN = true,
}
if IsMacClient() then
printKeys[_G.KEY_PRINTSCREEN_MAC] = true
end
function AFK:UpdateTimer()
local time = GetTime() - self.startTime
AFK.AFKMode.bottom.time:SetFormattedText('%02d:%02d', floor(time/60), time % 60)
end
function AFK:SetAFK(status)
if status then
MoveViewLeftStart(CAMERA_SPEED)
AFK.AFKMode:Show()
CloseAllWindows()
_G.UIParent:Hide()
if IsInGuild() then
local guildName, guildRankName = GetGuildInfo('player')
AFK.AFKMode.bottom.guild:SetFormattedText('%s-%s', guildName, guildRankName)
else
AFK.AFKMode.bottom.guild:SetText(L["No Guild"])
end
AFK.AFKMode.bottom.LogoTop:SetVertexColor(unpack(E.media.rgbvaluecolor))
AFK.AFKMode.bottom.model.curAnimation = 'wave'
AFK.AFKMode.bottom.model.startTime = GetTime()
AFK.AFKMode.bottom.model.duration = 2.3
AFK.AFKMode.bottom.model:SetUnit('player')
AFK.AFKMode.bottom.model.isIdle = nil
AFK.AFKMode.bottom.model:SetAnimation(67)
AFK.AFKMode.bottom.model.idleDuration = 40
AFK.startTime = GetTime()
AFK.timer = AFK:ScheduleRepeatingTimer('UpdateTimer', 1)
AFK.AFKMode.chat:RegisterEvent('CHAT_MSG_WHISPER')
AFK.AFKMode.chat:RegisterEvent('CHAT_MSG_BN_WHISPER')
AFK.AFKMode.chat:RegisterEvent('CHAT_MSG_GUILD')
AFK.isAFK = true
elseif AFK.isAFK then
_G.UIParent:Show()
AFK.AFKMode:Hide()
MoveViewLeftStop()
AFK:CancelTimer(AFK.timer)
AFK:CancelTimer(AFK.animTimer)
AFK.AFKMode.bottom.time:SetText('00:00')
AFK.AFKMode.chat:UnregisterAllEvents()
AFK.AFKMode.chat:Clear()
if _G.PVEFrame:IsShown() then --odd bug, frame is blank
PVEFrame_ToggleFrame()
PVEFrame_ToggleFrame()
end
AFK.isAFK = false
end
end
function AFK:OnEvent(event, ...)
if event == 'PLAYER_REGEN_DISABLED' or event == 'LFG_PROPOSAL_SHOW' or event == 'UPDATE_BATTLEFIELD_STATUS' then
if event ~= 'UPDATE_BATTLEFIELD_STATUS' or (GetBattlefieldStatus(...) == 'confirm') then
AFK:SetAFK(false)
end
if event == 'PLAYER_REGEN_DISABLED' then
AFK:RegisterEvent('PLAYER_REGEN_ENABLED', 'OnEvent')
end
return
end
if event == 'PLAYER_REGEN_ENABLED' then
AFK:UnregisterEvent('PLAYER_REGEN_ENABLED')
end
if not E.db.general.afk or (InCombatLockdown() or CinematicFrame:IsShown() or MovieFrame:IsShown()) then return end
if UnitCastingInfo('player') then --Don't activate afk if player is crafting stuff, check back in 30 seconds
AFK:ScheduleTimer('OnEvent', 30)
return
end
AFK:SetAFK(UnitIsAFK('player') and not C_PetBattles_IsInBattle())
end
function AFK:Toggle()
if E.db.general.afk then
AFK:RegisterEvent('PLAYER_FLAGS_CHANGED', 'OnEvent')
AFK:RegisterEvent('PLAYER_REGEN_DISABLED', 'OnEvent')
AFK:RegisterEvent('LFG_PROPOSAL_SHOW', 'OnEvent')
AFK:RegisterEvent('UPDATE_BATTLEFIELD_STATUS', 'OnEvent')
SetCVar('autoClearAFK', '1')
else
AFK:UnregisterEvent('PLAYER_FLAGS_CHANGED')
AFK:UnregisterEvent('PLAYER_REGEN_DISABLED')
AFK:UnregisterEvent('LFG_PROPOSAL_SHOW')
AFK:UnregisterEvent('UPDATE_BATTLEFIELD_STATUS')
end
end
local function OnKeyDown(_, key)
if ignoreKeys[key] then return end
if printKeys[key] then
Screenshot()
else
AFK:SetAFK(false)
AFK:ScheduleTimer('OnEvent', 60)
end
end
local function Chat_OnMouseWheel(self, delta)
if delta == 1 then
if IsShiftKeyDown() then
self:ScrollToTop()
else
self:ScrollUp()
end
elseif delta == -1 then
if IsShiftKeyDown() then
self:ScrollToBottom()
else
self:ScrollDown()
end
end
end
local function Chat_OnEvent(self, event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)
local type = strsub(event, 10)
local info = _G.ChatTypeInfo[type]
local coloredName
if event == 'CHAT_MSG_BN_WHISPER' then
coloredName = CH:GetBNFriendColor(arg2, arg13)
else
coloredName = CH:GetColoredName(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)
end
arg1 = RemoveExtraSpaces(arg1)
local chatTarget, body
local chatGroup = Chat_GetChatCategory(type)
if chatGroup == 'BN_CONVERSATION' then
chatTarget = tostring(arg8)
elseif chatGroup == 'WHISPER' or chatGroup == 'BN_WHISPER' then
if not(strsub(arg2, 1, 2) == '|K') then
chatTarget = arg2:upper()
else
chatTarget = arg2
end
end
local playerLink
if type ~= 'BN_WHISPER' and type ~= 'BN_CONVERSATION' then
playerLink = '|Hplayer:'..arg2..':'..arg11..':'..chatGroup..(chatTarget and ':'..chatTarget or '')..'|h'
else
playerLink = '|HBNplayer:'..arg2..':'..arg13..':'..arg11..':'..chatGroup..(chatTarget and ':'..chatTarget or '')..'|h'
end
local message = arg1
if arg14 then --isMobile
message = ChatFrame_GetMobileEmbeddedTexture(info.r, info.g, info.b)..message
end
--Escape any % characters, as it may otherwise cause an 'invalid option in format' error in the next step
message = gsub(message, '%%', '%%%%')
local success
success, body = pcall(format, _G['CHAT_'..type..'_GET']..message, playerLink..'['..coloredName..']'..'|h')
if not success then
E:Print('An error happened in the AFK Chat module. Please screenshot this message and report it. Info:', type, message, _G['CHAT_'..type..'_GET'])
end
local accessID = ChatHistory_GetAccessID(chatGroup, chatTarget)
local typeID = ChatHistory_GetAccessID(type, chatTarget, arg12 == '' and arg13 or arg12)
if CH.db.shortChannels then
body = body:gsub('|Hchannel:(.-)|h%[(.-)%]|h', CH.ShortChannel)
body = body:gsub('^(.-|h) '..L["whispers"], '%1')
body = body:gsub('<'..AFKstr..'>', '[|cffFF0000'..L["AFK"]..'|r] ')
body = body:gsub('<'..DNDstr..'>', '[|cffE7E716'..L["DND"]..'|r] ')
body = body:gsub('%[BN_CONVERSATION:', '%['..'')
end
self:AddMessage(body, info.r, info.g, info.b, info.id, false, accessID, typeID)
end
function AFK:LoopAnimations()
local ElvUIAFKPlayerModel = _G.ElvUIAFKPlayerModel
if ElvUIAFKPlayerModel.curAnimation == 'wave' then
ElvUIAFKPlayerModel:SetAnimation(69)
ElvUIAFKPlayerModel.curAnimation = 'dance'
ElvUIAFKPlayerModel.startTime = GetTime()
ElvUIAFKPlayerModel.duration = 300
ElvUIAFKPlayerModel.isIdle = false
ElvUIAFKPlayerModel.idleDuration = 120
end
end
function AFK:Initialize()
AFK.Initialized = true
AFK.AFKMode = CreateFrame('Frame', 'ElvUIAFKFrame')
AFK.AFKMode:SetFrameLevel(1)
AFK.AFKMode:SetScale(_G.UIParent:GetScale())
AFK.AFKMode:SetAllPoints(_G.UIParent)
AFK.AFKMode:Hide()
AFK.AFKMode:EnableKeyboard(true)
AFK.AFKMode:SetScript('OnKeyDown', OnKeyDown)
AFK.AFKMode.chat = CreateFrame('ScrollingMessageFrame', nil, AFK.AFKMode)
AFK.AFKMode.chat:Size(500, 200)
AFK.AFKMode.chat:Point('TOPLEFT', AFK.AFKMode, 'TOPLEFT', 4, -4)
AFK.AFKMode.chat:FontTemplate()
AFK.AFKMode.chat:SetJustifyH('LEFT')
AFK.AFKMode.chat:SetMaxLines(500)
AFK.AFKMode.chat:EnableMouseWheel(true)
AFK.AFKMode.chat:SetFading(false)
AFK.AFKMode.chat:SetMovable(true)
AFK.AFKMode.chat:EnableMouse(true)
AFK.AFKMode.chat:RegisterForDrag('LeftButton')
AFK.AFKMode.chat:SetScript('OnDragStart', AFK.AFKMode.chat.StartMoving)
AFK.AFKMode.chat:SetScript('OnDragStop', AFK.AFKMode.chat.StopMovingOrSizing)
AFK.AFKMode.chat:SetScript('OnMouseWheel', Chat_OnMouseWheel)
AFK.AFKMode.chat:SetScript('OnEvent', Chat_OnEvent)
AFK.AFKMode.bottom = CreateFrame('Frame', nil, AFK.AFKMode, 'BackdropTemplate')
AFK.AFKMode.bottom:SetFrameLevel(0)
AFK.AFKMode.bottom:SetTemplate('Transparent')
AFK.AFKMode.bottom:Point('BOTTOM', AFK.AFKMode, 'BOTTOM', 0, -E.Border)
AFK.AFKMode.bottom:Width(GetScreenWidth() + (E.Border*2))
AFK.AFKMode.bottom:Height(GetScreenHeight() * (1 / 10))
AFK.AFKMode.bottom.LogoTop = AFK.AFKMode:CreateTexture(nil, 'OVERLAY')
AFK.AFKMode.bottom.LogoTop:Size(320, 150)
AFK.AFKMode.bottom.LogoTop:Point('CENTER', AFK.AFKMode.bottom, 'CENTER', 0, 50)
AFK.AFKMode.bottom.LogoTop:SetTexture(E.Media.Textures.LogoTop)
AFK.AFKMode.bottom.LogoBottom = AFK.AFKMode:CreateTexture(nil, 'OVERLAY')
AFK.AFKMode.bottom.LogoBottom:Size(320, 150)
AFK.AFKMode.bottom.LogoBottom:Point('CENTER', AFK.AFKMode.bottom, 'CENTER', 0, 50)
AFK.AFKMode.bottom.LogoBottom:SetTexture(E.Media.Textures.LogoBottom)
local factionGroup, size, offsetX, offsetY, nameOffsetX, nameOffsetY = E.myfaction, 140, -20, -16, -10, -28
if factionGroup == 'Neutral' then
factionGroup, size, offsetX, offsetY, nameOffsetX, nameOffsetY = 'Panda', 90, 15, 10, 20, -5
end
AFK.AFKMode.bottom.faction = AFK.AFKMode.bottom:CreateTexture(nil, 'OVERLAY')
AFK.AFKMode.bottom.faction:Point('BOTTOMLEFT', AFK.AFKMode.bottom, 'BOTTOMLEFT', offsetX, offsetY)
AFK.AFKMode.bottom.faction:SetTexture(format([[Interface\Timer\%s-Logo]], factionGroup))
AFK.AFKMode.bottom.faction:Size(size, size)
local classColor = E:ClassColor(E.myclass)
AFK.AFKMode.bottom.name = AFK.AFKMode.bottom:CreateFontString(nil, 'OVERLAY')
AFK.AFKMode.bottom.name:FontTemplate(nil, 20)
AFK.AFKMode.bottom.name:SetFormattedText('%s-%s', E.myname, E.myrealm)
AFK.AFKMode.bottom.name:Point('TOPLEFT', AFK.AFKMode.bottom.faction, 'TOPRIGHT', nameOffsetX, nameOffsetY)
AFK.AFKMode.bottom.name:SetTextColor(classColor.r, classColor.g, classColor.b)
AFK.AFKMode.bottom.guild = AFK.AFKMode.bottom:CreateFontString(nil, 'OVERLAY')
AFK.AFKMode.bottom.guild:FontTemplate(nil, 20)
AFK.AFKMode.bottom.guild:SetText(L["No Guild"])
AFK.AFKMode.bottom.guild:Point('TOPLEFT', AFK.AFKMode.bottom.name, 'BOTTOMLEFT', 0, -6)
AFK.AFKMode.bottom.guild:SetTextColor(0.7, 0.7, 0.7)
AFK.AFKMode.bottom.time = AFK.AFKMode.bottom:CreateFontString(nil, 'OVERLAY')
AFK.AFKMode.bottom.time:FontTemplate(nil, 20)
AFK.AFKMode.bottom.time:SetText('00:00')
AFK.AFKMode.bottom.time:Point('TOPLEFT', AFK.AFKMode.bottom.guild, 'BOTTOMLEFT', 0, -6)
AFK.AFKMode.bottom.time:SetTextColor(0.7, 0.7, 0.7)
--Use this frame to control position of the model
AFK.AFKMode.bottom.modelHolder = CreateFrame('Frame', nil, AFK.AFKMode.bottom)
AFK.AFKMode.bottom.modelHolder:Size(150, 150)
AFK.AFKMode.bottom.modelHolder:Point('BOTTOMRIGHT', AFK.AFKMode.bottom, 'BOTTOMRIGHT', -200, 220)
AFK.AFKMode.bottom.model = CreateFrame('PlayerModel', 'ElvUIAFKPlayerModel', AFK.AFKMode.bottom.modelHolder)
AFK.AFKMode.bottom.model:Point('CENTER', AFK.AFKMode.bottom.modelHolder, 'CENTER')
AFK.AFKMode.bottom.model:Size(GetScreenWidth() * 2, GetScreenHeight() * 2) --YES, double screen size. This prevents clipping of models. Position is controlled with the helper frame.
AFK.AFKMode.bottom.model:SetCamDistanceScale(4.5) --Since the model frame is huge, we need to zoom out quite a bit.
AFK.AFKMode.bottom.model:SetFacing(6)
AFK.AFKMode.bottom.model:SetScript('OnUpdate', function(model)
if not model.isIdle then
local timePassed = GetTime() - model.startTime
if timePassed > model.duration then
model:SetAnimation(0)
model.isIdle = true
AFK.animTimer = AFK:ScheduleTimer('LoopAnimations', model.idleDuration)
end
end
end)
AFK:Toggle()
AFK.isActive = false
end
E:RegisterModule(AFK:GetName())

View File

@@ -0,0 +1,173 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule('Misc')
local CH = E:GetModule('Chat')
local LSM = E.Libs.LSM
local format, wipe, unpack, pairs = format, wipe, unpack, pairs
local strmatch, strlower, gmatch, gsub = strmatch, strlower, gmatch, gsub
local Ambiguate = Ambiguate
local CreateFrame = CreateFrame
local GetInstanceInfo = GetInstanceInfo
local RemoveExtraSpaces = RemoveExtraSpaces
local PRIEST_COLOR = RAID_CLASS_COLORS.PRIEST
local C_ChatBubbles_GetAllChatBubbles = C_ChatBubbles.GetAllChatBubbles
--Message caches
local messageToGUID = {}
local messageToSender = {}
function M:UpdateBubbleBorder()
local backdrop = self.backdrop
local str = backdrop and backdrop.String
if not str then return end
if E.private.general.chatBubbles == 'backdrop' then
backdrop:SetBackdropBorderColor(str:GetTextColor())
end
local name = self.Name and self.Name:GetText()
if name then self.Name:SetText() end
local text = str:GetText()
if not text then return end
if E.private.general.chatBubbleName then
M:AddChatBubbleName(self, messageToGUID[text], messageToSender[text])
end
if E.private.chat.enable and E.private.general.classColorMentionsSpeech then
local isFirstWord, rebuiltString
if text and strmatch(text, '%s-%S+%s*') then
for word in gmatch(text, '%s-%S+%s*') do
local tempWord = gsub(word, '^[%s%p]-([^%s%p]+)([%-]?[^%s%p]-)[%s%p]*$', '%1%2')
local lowerCaseWord = strlower(tempWord)
local classMatch = CH.ClassNames[lowerCaseWord]
local wordMatch = classMatch and lowerCaseWord
if wordMatch and not E.global.chat.classColorMentionExcludedNames[wordMatch] then
local classColorTable = E:ClassColor(classMatch)
if classColorTable then
word = gsub(word, gsub(tempWord, '%-','%%-'), format('\124cff%.2x%.2x%.2x%s\124r', classColorTable.r*255, classColorTable.g*255, classColorTable.b*255, tempWord))
end
end
if not isFirstWord then
rebuiltString = word
isFirstWord = true
else
rebuiltString = format('%s%s', rebuiltString, word)
end
end
if rebuiltString then
str:SetText(RemoveExtraSpaces(rebuiltString))
end
end
end
end
function M:AddChatBubbleName(chatBubble, guid, name)
if not name then return end
local color = PRIEST_COLOR
local data = guid and guid ~= '' and CH:GetPlayerInfoByGUID(guid)
if data and data.classColor then
color = data.classColor
end
chatBubble.Name:SetFormattedText('|c%s%s|r', color.colorStr, name)
chatBubble.Name:Width(chatBubble:GetWidth()-10)
end
local yOffset --Value set in M:LoadChatBubbles()
function M:SkinBubble(frame, backdrop)
local bubbleFont = LSM:Fetch('font', E.private.general.chatBubbleFont)
if backdrop.String then
backdrop.String:FontTemplate(bubbleFont, E.private.general.chatBubbleFontSize, E.private.general.chatBubbleFontOutline)
end
if E.private.general.chatBubbles == 'backdrop' then
if not backdrop.template then
backdrop:SetBackdrop()
backdrop:SetTemplate('Transparent', nil, true)
end
elseif E.private.general.chatBubbles == 'backdrop_noborder' then
if not backdrop.noBorder then
backdrop:SetBackdrop()
backdrop.noBorder = backdrop:CreateTexture(nil, 'ARTWORK')
end
backdrop.noBorder:SetInside(frame, 4, 4)
backdrop.noBorder:SetColorTexture(unpack(E.media.backdropfadecolor))
elseif E.private.general.chatBubbles == 'nobackdrop' then
backdrop:SetBackdrop()
end
if not frame.Name then
local name = frame:CreateFontString(nil, 'BORDER')
name:Height(10) --Width set in M:AddChatBubbleName()
name:Point('BOTTOM', frame, 'TOP', 0, yOffset)
name:FontTemplate(bubbleFont, E.private.general.chatBubbleFontSize * 0.85, E.private.general.chatBubbleFontOutline)
name:SetJustifyH('LEFT')
frame.Name = name
end
if not frame.backdrop then
frame.backdrop = backdrop
backdrop.Tail:Hide()
frame:HookScript('OnShow', M.UpdateBubbleBorder)
frame:SetFrameStrata('DIALOG') --Doesn't work currently in Legion due to a bug on Blizzards end
frame:SetClampedToScreen(false)
M.UpdateBubbleBorder(frame)
end
frame.isSkinnedElvUI = true
end
local function ChatBubble_OnEvent(_, event, msg, sender, _, _, _, _, _, _, _, _, _, guid)
if event == 'PLAYER_ENTERING_WORLD' then --Clear caches
wipe(messageToGUID)
wipe(messageToSender)
elseif E.private.general.chatBubbleName then
messageToGUID[msg] = guid
messageToSender[msg] = Ambiguate(sender, 'none')
end
end
local function ChatBubble_OnUpdate(eventFrame, elapsed)
eventFrame.lastupdate = (eventFrame.lastupdate or -2) + elapsed
if eventFrame.lastupdate < 0.1 then return end
eventFrame.lastupdate = 0
for _, frame in pairs(C_ChatBubbles_GetAllChatBubbles()) do
local backdrop = frame:GetChildren(1)
if backdrop and not backdrop:IsForbidden() and not frame.isSkinnedElvUI then
M:SkinBubble(frame, backdrop)
end
end
end
function M:ToggleChatBubbleScript()
local _, instanceType = GetInstanceInfo()
if instanceType == 'none' and E.private.general.chatBubbles ~= 'disabled' then
M.BubbleFrame:SetScript('OnEvent', ChatBubble_OnEvent)
M.BubbleFrame:SetScript('OnUpdate', ChatBubble_OnUpdate)
else
M.BubbleFrame:SetScript('OnEvent', nil)
M.BubbleFrame:SetScript('OnUpdate', nil)
end
end
function M:LoadChatBubbles()
yOffset = (E.private.general.chatBubbles == 'backdrop' and 2) or (E.private.general.chatBubbles == 'backdrop_noborder' and -2) or 0
self.BubbleFrame = CreateFrame('Frame')
self.BubbleFrame:RegisterEvent('CHAT_MSG_SAY')
self.BubbleFrame:RegisterEvent('CHAT_MSG_YELL')
self.BubbleFrame:RegisterEvent('CHAT_MSG_MONSTER_SAY')
self.BubbleFrame:RegisterEvent('CHAT_MSG_MONSTER_YELL')
self.BubbleFrame:RegisterEvent('PLAYER_ENTERING_WORLD')
end

128
Modules/Misc/DebugTools.lua Normal file
View File

@@ -0,0 +1,128 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local D = E:GetModule('DebugTools')
local _G = _G
local hooksecurefunc = hooksecurefunc
local CreateFrame = CreateFrame
local InCombatLockdown = InCombatLockdown
local GetCVarBool = GetCVarBool
local StaticPopup_Hide = StaticPopup_Hide
D.HideFrame = CreateFrame('Frame')
local function UnHighlightText(self)
self:HighlightText(0, 0)
end
local function ScriptErrors_UnHighlightText()
_G.ScriptErrorsFrame.ScrollFrame.Text:HighlightText(0, 0)
end
function D:ModifyErrorFrame()
local ScriptErrorsFrame = _G.ScriptErrorsFrame
ScriptErrorsFrame.ScrollFrame.Text.cursorOffset = 0
ScriptErrorsFrame.ScrollFrame.Text.cursorHeight = 0
ScriptErrorsFrame.ScrollFrame.Text:SetScript('OnEditFocusGained', nil)
hooksecurefunc(ScriptErrorsFrame, 'Update', ScriptErrors_UnHighlightText)
-- Unhighlight text when focus is hit
ScriptErrorsFrame.ScrollFrame.Text:HookScript('OnEscapePressed', UnHighlightText)
ScriptErrorsFrame:Size(500, 300)
ScriptErrorsFrame.ScrollFrame:Size(ScriptErrorsFrame:GetWidth() - 45, ScriptErrorsFrame:GetHeight() - 71)
local BUTTON_WIDTH = 75
local BUTTON_HEIGHT = 23
local BUTTON_SPACING = 2
-- Add a first button
local firstButton = CreateFrame('Button', nil, ScriptErrorsFrame, 'UIPanelButtonTemplate, BackdropTemplate')
firstButton:Point('BOTTOMLEFT', ScriptErrorsFrame.Reload, 'BOTTOMRIGHT', BUTTON_SPACING, 0)
firstButton:SetText('First')
firstButton:Size(BUTTON_WIDTH, BUTTON_HEIGHT)
firstButton:SetScript('OnClick', function()
ScriptErrorsFrame.index = 1
ScriptErrorsFrame:Update()
end)
ScriptErrorsFrame.firstButton = firstButton
-- Also add a Last button for errors
local lastButton = CreateFrame('Button', nil, ScriptErrorsFrame, 'UIPanelButtonTemplate, BackdropTemplate')
lastButton:Point('BOTTOMRIGHT', ScriptErrorsFrame.Close, 'BOTTOMLEFT', -BUTTON_SPACING, 0)
lastButton:Size(BUTTON_WIDTH, BUTTON_HEIGHT)
lastButton:SetText('Last')
lastButton:SetScript('OnClick', function()
ScriptErrorsFrame.index = #(ScriptErrorsFrame.order)
ScriptErrorsFrame:Update()
end)
ScriptErrorsFrame.lastButton = lastButton
D:ScriptErrorsFrame_UpdateButtons()
D:Unhook(ScriptErrorsFrame, 'OnShow')
end
function D:ScriptErrorsFrame_UpdateButtons()
local ScriptErrorsFrame = _G.ScriptErrorsFrame
if not ScriptErrorsFrame.firstButton then return end
local numErrors = #ScriptErrorsFrame.order;
local index = ScriptErrorsFrame.index;
if index == 0 then
ScriptErrorsFrame.lastButton:Disable()
ScriptErrorsFrame.firstButton:Disable()
else
if numErrors == 1 then
ScriptErrorsFrame.lastButton:Disable()
ScriptErrorsFrame.firstButton:Disable()
else
ScriptErrorsFrame.lastButton:Enable()
ScriptErrorsFrame.firstButton:Enable()
end
end
end
function D:ScriptErrorsFrame_OnError(_, _, keepHidden)
if keepHidden or D.MessagePrinted or not InCombatLockdown() or GetCVarBool('scriptErrors') ~= true then return; end
E:Print(L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."])
D.MessagePrinted = true;
end
function D:PLAYER_REGEN_ENABLED()
_G.ScriptErrorsFrame:SetParent(_G.UIParent)
D.MessagePrinted = nil;
end
function D:PLAYER_REGEN_DISABLED()
_G.ScriptErrorsFrame:SetParent(self.HideFrame)
end
function D:TaintError(event, addonName, addonFunc)
if GetCVarBool('scriptErrors') ~= true or E.db.general.taintLog ~= true then return end
_G.ScriptErrorsFrame:OnError(L["%s: %s tried to call the protected function '%s'."]:format(event, addonName or '<name>', addonFunc or '<func>'), false, false)
end
function D:StaticPopup_Show(name)
if name == 'ADDON_ACTION_FORBIDDEN' then
StaticPopup_Hide(name);
end
end
function D:Initialize()
self.Initialized = true
self.HideFrame:Hide()
local ScriptErrorsFrame = _G.ScriptErrorsFrame
self:SecureHookScript(ScriptErrorsFrame, 'OnShow', D.ModifyErrorFrame)
self:SecureHook(ScriptErrorsFrame, 'UpdateButtons', D.ScriptErrorsFrame_UpdateButtons)
self:SecureHook(ScriptErrorsFrame, 'OnError', D.ScriptErrorsFrame_OnError)
self:SecureHook('StaticPopup_Show')
self:RegisterEvent('PLAYER_REGEN_DISABLED')
self:RegisterEvent('PLAYER_REGEN_ENABLED')
self:RegisterEvent('ADDON_ACTION_BLOCKED', 'TaintError')
self:RegisterEvent('ADDON_ACTION_FORBIDDEN', 'TaintError')
end
E:RegisterModule(D:GetName())

View File

@@ -0,0 +1,334 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule('Misc')
local LSM = E.Libs.LSM
local _G = _G
local rad = rad
local gsub = gsub
local wipe = wipe
local next = next
local pairs = pairs
local unpack = unpack
local UnitGUID = UnitGUID
local CreateFrame = CreateFrame
local InspectItems = {
'HeadSlot',
'NeckSlot',
'ShoulderSlot',
'',
'ChestSlot',
'WaistSlot',
'LegsSlot',
'FeetSlot',
'WristSlot',
'HandsSlot',
'Finger0Slot',
'Finger1Slot',
'Trinket0Slot',
'Trinket1Slot',
'BackSlot',
'MainHandSlot',
'SecondaryHandSlot',
}
local whileOpenEvents = {
UPDATE_INVENTORY_DURABILITY = true,
AZERITE_ESSENCE_UPDATE = true
}
function M:CreateInspectTexture(slot, x, y)
local texture = slot:CreateTexture()
texture:Point('BOTTOM', x, y)
texture:SetTexCoord(unpack(E.TexCoords))
texture:Size(14)
local backdrop = CreateFrame('Frame', nil, slot, 'BackdropTemplate')
backdrop:SetTemplate(nil, nil, true)
backdrop:SetBackdropColor(0,0,0,0)
backdrop:SetOutside(texture)
backdrop:Hide()
return texture, backdrop
end
function M:GetInspectPoints(id)
if not id then return end
if id <= 5 or (id == 9 or id == 15) then
return 40, 3, 18, 'BOTTOMLEFT' -- Left side
elseif (id >= 6 and id <= 8) or (id >= 10 and id <= 14) then
return -40, 3, 18, 'BOTTOMRIGHT' -- Right side
else
return 0, 45, 60, 'BOTTOM'
end
end
function M:UpdateInspectInfo(_, arg1)
M:UpdatePageInfo(_G.InspectFrame, 'Inspect', arg1)
end
function M:UpdateCharacterInfo(event)
if (not E.db.general.itemLevel.displayCharacterInfo)
or (whileOpenEvents[event] and not _G.CharacterFrame:IsShown()) then return end
M:UpdatePageInfo(_G.CharacterFrame, 'Character', nil, event)
end
function M:UpdateCharacterItemLevel()
M:UpdateAverageString(_G.CharacterFrame, 'Character')
end
function M:ClearPageInfo(frame, which)
if not (frame and frame.ItemLevelText) then return end
frame.ItemLevelText:SetText('')
for i = 1, 17 do
if i ~= 4 then
local inspectItem = _G[which..InspectItems[i]]
inspectItem.enchantText:SetText('')
inspectItem.iLvlText:SetText('')
for y=1, 10 do
inspectItem['textureSlot'..y]:SetTexture()
inspectItem['textureSlotBackdrop'..y]:Hide()
end
end
end
end
function M:ToggleItemLevelInfo(setupCharacterPage)
if setupCharacterPage then
M:CreateSlotStrings(_G.CharacterFrame, 'Character')
end
if E.db.general.itemLevel.displayCharacterInfo then
M:RegisterEvent('AZERITE_ESSENCE_UPDATE', 'UpdateCharacterInfo')
M:RegisterEvent('PLAYER_EQUIPMENT_CHANGED', 'UpdateCharacterInfo')
M:RegisterEvent('UPDATE_INVENTORY_DURABILITY', 'UpdateCharacterInfo')
M:RegisterEvent('PLAYER_AVG_ITEM_LEVEL_UPDATE', 'UpdateCharacterItemLevel')
_G.CharacterStatsPane.ItemLevelFrame.Value:Hide()
if not _G.CharacterFrame.CharacterInfoHooked then
_G.CharacterFrame:HookScript('OnShow', M.UpdateCharacterInfo)
_G.CharacterFrame.CharacterInfoHooked = true
end
if not setupCharacterPage then
M:UpdateCharacterInfo()
end
else
M:UnregisterEvent('AZERITE_ESSENCE_UPDATE')
M:UnregisterEvent('PLAYER_EQUIPMENT_CHANGED')
M:UnregisterEvent('UPDATE_INVENTORY_DURABILITY')
M:UnregisterEvent('PLAYER_AVG_ITEM_LEVEL_UPDATE')
_G.CharacterStatsPane.ItemLevelFrame.Value:Show()
M:ClearPageInfo(_G.CharacterFrame, 'Character')
end
if E.db.general.itemLevel.displayInspectInfo then
M:RegisterEvent('INSPECT_READY', 'UpdateInspectInfo')
else
M:UnregisterEvent('INSPECT_READY')
M:ClearPageInfo(_G.InspectFrame, 'Inspect')
end
end
function M:UpdatePageStrings(i, iLevelDB, inspectItem, slotInfo, which) -- `which` is used by plugins
iLevelDB[i] = slotInfo.iLvl
inspectItem.enchantText:SetText(slotInfo.enchantTextShort)
if slotInfo.enchantColors and next(slotInfo.enchantColors) then
inspectItem.enchantText:SetTextColor(unpack(slotInfo.enchantColors))
end
inspectItem.iLvlText:SetText(slotInfo.iLvl)
if slotInfo.itemLevelColors and next(slotInfo.itemLevelColors) then
inspectItem.iLvlText:SetTextColor(unpack(slotInfo.itemLevelColors))
end
local gemStep, essenceStep = 1, 1
for x = 1, 10 do
local texture = inspectItem['textureSlot'..x]
local backdrop = inspectItem['textureSlotBackdrop'..x]
local essenceType = inspectItem['textureSlotEssenceType'..x]
if essenceType then essenceType:Hide() end
local gem = slotInfo.gems and slotInfo.gems[gemStep]
local essence = not gem and (slotInfo.essences and slotInfo.essences[essenceStep])
if gem then
texture:SetTexture(gem)
backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
backdrop:Show()
gemStep = gemStep + 1
elseif essence and next(essence) then
local hexColor = essence[4]
if hexColor then
local r, g, b = E:HexToRGB(hexColor)
backdrop:SetBackdropBorderColor(r/255, g/255, b/255)
else
backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
end
if not essenceType then
essenceType = inspectItem:CreateTexture()
essenceType:SetTexture(2907423)
essenceType:SetRotation(rad(90))
essenceType:SetParent(backdrop)
inspectItem['textureSlotEssenceType'..x] = essenceType
end
essenceType:Point('BOTTOM', texture, 'TOP', 0, -9)
essenceType:SetAtlas(gsub(essence[2], '^tooltip%-(heartofazeroth)essence', '%1-list-selected'))
essenceType:Size(13, 17)
essenceType:Show()
local selected = essence[1]
texture:SetTexture(selected)
backdrop:Show()
if selected then
backdrop:SetBackdropColor(0,0,0,0)
else
local r, g, b = unpack(E.media.backdropcolor)
backdrop:SetBackdropColor(r, g, b, 1)
end
essenceStep = essenceStep + 1
else
texture:SetTexture()
backdrop:Hide()
end
end
end
function M:UpdateAverageString(frame, which, iLevelDB)
local isCharPage = which == 'Character'
local AvgItemLevel = (isCharPage and E:GetPlayerItemLevel()) or E:CalculateAverageItemLevel(iLevelDB, frame.unit)
if AvgItemLevel then
if isCharPage then
frame.ItemLevelText:SetText(AvgItemLevel)
frame.ItemLevelText:SetTextColor(_G.CharacterStatsPane.ItemLevelFrame.Value:GetTextColor())
else
frame.ItemLevelText:SetFormattedText(L["Item level: %.2f"], AvgItemLevel)
end
else
frame.ItemLevelText:SetText('')
end
end
function M:TryGearAgain(frame, which, i, deepScan, iLevelDB, inspectItem)
E:Delay(0.05, function()
if which == 'Inspect' and (not frame or not frame.unit) then return end
local unit = (which == 'Character' and 'player') or frame.unit
local slotInfo = E:GetGearSlotInfo(unit, i, deepScan)
if slotInfo == 'tooSoon' then return end
M:UpdatePageStrings(i, iLevelDB, inspectItem, slotInfo, which)
end)
end
do
local iLevelDB = {}
function M:UpdatePageInfo(frame, which, guid, event)
if not (which and frame and frame.ItemLevelText) then return end
if which == 'Inspect' and (not frame or not frame.unit or (guid and frame:IsShown() and UnitGUID(frame.unit) ~= guid)) then return end
wipe(iLevelDB)
local waitForItems
for i = 1, 17 do
if i ~= 4 then
local inspectItem = _G[which..InspectItems[i]]
inspectItem.enchantText:SetText('')
inspectItem.iLvlText:SetText('')
local unit = (which == 'Character' and 'player') or frame.unit
local slotInfo = E:GetGearSlotInfo(unit, i, true)
if slotInfo == 'tooSoon' then
if not waitForItems then waitForItems = true end
M:TryGearAgain(frame, which, i, true, iLevelDB, inspectItem)
else
M:UpdatePageStrings(i, iLevelDB, inspectItem, slotInfo, which)
end
end
end
if event and event == 'PLAYER_EQUIPMENT_CHANGED' then
return
end
if waitForItems then
E:Delay(0.10, M.UpdateAverageString, M, frame, which, iLevelDB)
else
M:UpdateAverageString(frame, which, iLevelDB)
end
end
end
function M:CreateSlotStrings(frame, which)
if not (frame and which) then return end
local itemLevelFont = E.db.general.itemLevel.itemLevelFont
local itemLevelFontSize = E.db.general.itemLevel.itemLevelFontSize or 12
local itemLevelFontOutline = E.db.general.itemLevel.itemLevelFontOutline or 'OUTLINE'
if which == 'Inspect' then
frame.ItemLevelText = _G.InspectPaperDollItemsFrame:CreateFontString(nil, 'ARTWORK')
frame.ItemLevelText:Point('BOTTOMRIGHT', -6, 6)
else
frame.ItemLevelText = _G.CharacterStatsPane.ItemLevelFrame:CreateFontString(nil, 'ARTWORK')
frame.ItemLevelText:Point('BOTTOM', _G.CharacterStatsPane.ItemLevelFrame.Value, 'BOTTOM', 0, 0)
end
frame.ItemLevelText:FontTemplate(nil, which == 'Inspect' and 12 or 20)
for i, s in pairs(InspectItems) do
if i ~= 4 then
local slot = _G[which..s]
local x, y, z, justify = M:GetInspectPoints(i)
slot.iLvlText = slot:CreateFontString(nil, 'OVERLAY')
slot.iLvlText:FontTemplate(LSM:Fetch('font', itemLevelFont), itemLevelFontSize, itemLevelFontOutline)
slot.iLvlText:Point('BOTTOM', slot, x, y)
slot.enchantText = slot:CreateFontString(nil, 'OVERLAY')
slot.enchantText:FontTemplate(LSM:Fetch('font', itemLevelFont), itemLevelFontSize, itemLevelFontOutline)
if i == 16 or i == 17 then
slot.enchantText:Point(i==16 and 'BOTTOMRIGHT' or 'BOTTOMLEFT', slot, i==16 and -40 or 40, 3)
else
slot.enchantText:Point(justify, slot, x + (justify == 'BOTTOMLEFT' and 5 or -5), z)
end
for u=1, 10 do
local offset = 8+(u*16)
local newX = ((justify == 'BOTTOMLEFT' or i == 17) and x+offset) or x-offset
slot['textureSlot'..u], slot['textureSlotBackdrop'..u] = M:CreateInspectTexture(slot, newX, --[[newY or]] y)
end
end
end
end
function M:SetupInspectPageInfo()
M:CreateSlotStrings(_G.InspectFrame, 'Inspect')
end
function M:UpdateInspectPageFonts(which)
local itemLevelFont = E.db.general.itemLevel.itemLevelFont
local itemLevelFontSize = E.db.general.itemLevel.itemLevelFontSize or 12
local itemLevelFontOutline = E.db.general.itemLevel.itemLevelFontOutline or 'OUTLINE'
for i, s in pairs(InspectItems) do
if i ~= 4 then
local slot = _G[which..s]
if slot then
slot.iLvlText:FontTemplate(LSM:Fetch('font', itemLevelFont), itemLevelFontSize, itemLevelFontOutline)
slot.enchantText:FontTemplate(LSM:Fetch('font', itemLevelFont), itemLevelFontSize, itemLevelFontOutline)
end
end
end
end

View File

@@ -0,0 +1,12 @@
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Script file='Misc.lua'/>
<Script file='DebugTools.lua'/>
<Script file='ChatBubbles.lua'/>
<Script file='RaidMarker.lua'/>
<Script file='Loot.lua'/>
<Script file='LootRoll.lua'/>
<Script file='InfoItemLevel.lua'/>
<Script file='RaidUtility.lua'/>
<Script file='TotemBar.lua'/>
<Script file='AFK.lua'/>
</Ui>

338
Modules/Misc/Loot.lua Normal file
View File

@@ -0,0 +1,338 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule('Misc')
local LBG = E.Libs.ButtonGlow
local _G = _G
local unpack, pairs = unpack, pairs
local tinsert = tinsert
local max = max
local CloseLoot = CloseLoot
local CreateFrame = CreateFrame
local CursorOnUpdate = CursorOnUpdate
local CursorUpdate = CursorUpdate
local GetCursorPosition = GetCursorPosition
local GetCVarBool = GetCVarBool
local GetLootSlotInfo = GetLootSlotInfo
local GetLootSlotLink = GetLootSlotLink
local GetNumLootItems = GetNumLootItems
local HandleModifiedItemClick = HandleModifiedItemClick
local IsFishingLoot = IsFishingLoot
local IsModifiedClick = IsModifiedClick
local LootSlot = LootSlot
local LootSlotHasItem = LootSlotHasItem
local ResetCursor = ResetCursor
local StaticPopup_Hide = StaticPopup_Hide
local UnitIsDead = UnitIsDead
local UnitIsFriend = UnitIsFriend
local UnitName = UnitName
local LOOT = LOOT
local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS
local TEXTURE_ITEM_QUEST_BANG = TEXTURE_ITEM_QUEST_BANG
local coinTextureIDs = {
[133784] = true,
[133785] = true,
[133786] = true,
[133787] = true,
[133788] = true,
[133789] = true,
}
--Credit Haste
local iconSize, lootFrame, lootFrameHolder = 30
local OnEnter = function(self)
local slot = self:GetID()
if LootSlotHasItem(slot) then
_G.GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
_G.GameTooltip:SetLootItem(slot)
CursorUpdate(self)
end
self.drop:Show()
self.drop:SetVertexColor(1, 1, 0)
end
local OnLeave = function(self)
if self.quality and (self.quality > 1) then
local color = ITEM_QUALITY_COLORS[self.quality]
self.drop:SetVertexColor(color.r, color.g, color.b)
else
self.drop:Hide()
end
_G.GameTooltip:Hide()
ResetCursor()
end
local OnClick = function(self)
local LootFrame = _G.LootFrame
LootFrame.selectedQuality = self.quality
LootFrame.selectedItemName = self.name:GetText()
LootFrame.selectedSlot = self:GetID()
LootFrame.selectedLootButton = self:GetName()
LootFrame.selectedTexture = self.icon:GetTexture()
if IsModifiedClick() then
HandleModifiedItemClick(GetLootSlotLink(self:GetID()))
else
StaticPopup_Hide('CONFIRM_LOOT_DISTRIBUTION')
LootSlot(self:GetID())
end
end
local OnShow = function(self)
local GameTooltip = _G.GameTooltip
if GameTooltip:IsOwned(self) then
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
GameTooltip:SetLootItem(self:GetID())
CursorOnUpdate(self)
end
end
local function anchorSlots(self)
local shownSlots = 0
for i=1, #self.slots do
local frame = self.slots[i]
if frame:IsShown() then
shownSlots = shownSlots + 1
frame:Point('TOP', lootFrame, 4, (-8 + iconSize) - (shownSlots * iconSize))
end
end
self:Height(max(shownSlots * iconSize + 16, 20))
end
local function createSlot(id)
local iconsize = (iconSize - 2)
local frame = CreateFrame('Button', 'ElvLootSlot'..id, lootFrame)
frame:Point('LEFT', 8, 0)
frame:Point('RIGHT', -8, 0)
frame:Height(iconsize)
frame:SetID(id)
frame:RegisterForClicks('LeftButtonUp', 'RightButtonUp')
frame:SetScript('OnEnter', OnEnter)
frame:SetScript('OnLeave', OnLeave)
frame:SetScript('OnClick', OnClick)
frame:SetScript('OnShow', OnShow)
local iconFrame = CreateFrame('Frame', nil, frame, 'BackdropTemplate')
iconFrame:Height(iconsize)
iconFrame:Width(iconsize)
iconFrame:Point('RIGHT', frame)
iconFrame:SetTemplate()
frame.iconFrame = iconFrame
E.frames[iconFrame] = nil
local icon = iconFrame:CreateTexture(nil, 'ARTWORK')
icon:SetTexCoord(unpack(E.TexCoords))
icon:SetInside()
frame.icon = icon
local count = iconFrame:CreateFontString(nil, 'OVERLAY')
count:SetJustifyH'RIGHT'
count:Point('BOTTOMRIGHT', iconFrame, -2, 2)
count:FontTemplate(nil, nil, 'OUTLINE')
count:SetText(1)
frame.count = count
local name = frame:CreateFontString(nil, 'OVERLAY')
name:SetJustifyH('LEFT')
name:Point('LEFT', frame)
name:Point('RIGHT', icon, 'LEFT')
name:SetNonSpaceWrap(true)
name:FontTemplate(nil, nil, 'OUTLINE')
frame.name = name
local drop = frame:CreateTexture(nil, 'ARTWORK')
drop:SetTexture([[Interface\QuestFrame\UI-QuestLogTitleHighlight]])
drop:Point('LEFT', icon, 'RIGHT', 0, 0)
drop:Point('RIGHT', frame)
drop:SetAllPoints(frame)
drop:SetAlpha(.3)
frame.drop = drop
local questTexture = iconFrame:CreateTexture(nil, 'OVERLAY')
questTexture:SetInside()
questTexture:SetTexture(TEXTURE_ITEM_QUEST_BANG)
questTexture:SetTexCoord(unpack(E.TexCoords))
frame.questTexture = questTexture
lootFrame.slots[id] = frame
return frame
end
function M:LOOT_SLOT_CLEARED(_, slot)
if not lootFrame:IsShown() then return end
if lootFrame.slots[slot] then
lootFrame.slots[slot]:Hide()
end
anchorSlots(lootFrame)
end
function M:LOOT_CLOSED()
StaticPopup_Hide('LOOT_BIND')
lootFrame:Hide()
for _, v in pairs(lootFrame.slots) do
v:Hide()
end
end
function M:LOOT_OPENED(_, autoloot)
lootFrame:Show()
if not lootFrame:IsShown() then
CloseLoot(not autoloot)
end
if IsFishingLoot() then
lootFrame.title:SetText(L["Fishy Loot"])
elseif not UnitIsFriend('player', 'target') and UnitIsDead('target') then
lootFrame.title:SetText(UnitName('target'))
else
lootFrame.title:SetText(LOOT)
end
-- Blizzard uses strings here
if GetCVarBool('lootUnderMouse') then
local x, y = GetCursorPosition()
x = x / lootFrame:GetEffectiveScale()
y = y / lootFrame:GetEffectiveScale()
lootFrame:ClearAllPoints()
lootFrame:Point('TOPLEFT', _G.UIParent, 'BOTTOMLEFT', x - 40, y + 20)
lootFrame:GetCenter()
lootFrame:Raise()
E:DisableMover('LootFrameMover')
else
lootFrame:ClearAllPoints()
lootFrame:Point('TOPLEFT', lootFrameHolder, 'TOPLEFT')
E:EnableMover('LootFrameMover')
end
local m, w, t = 0, 0, lootFrame.title:GetStringWidth()
local items = GetNumLootItems()
if items > 0 then
for i=1, items do
local slot = lootFrame.slots[i] or createSlot(i)
local textureID, item, quantity, _, quality, _, isQuestItem, questId, isActive = GetLootSlotInfo(i)
local color = ITEM_QUALITY_COLORS[quality]
if coinTextureIDs[textureID] then
item = item:gsub('\n', ', ')
end
if quantity and (quantity > 1) then
slot.count:SetText(quantity)
slot.count:Show()
else
slot.count:Hide()
end
if quality and (quality > 1) then
slot.drop:SetVertexColor(color.r, color.g, color.b)
slot.drop:Show()
else
slot.drop:Hide()
end
slot.quality = quality
slot.name:SetText(item)
if color then
slot.name:SetTextColor(color.r, color.g, color.b)
end
slot.icon:SetTexture(textureID)
if quality then
m = max(m, quality)
end
w = max(w, slot.name:GetStringWidth())
local questTexture = slot.questTexture
if questId and not isActive then
questTexture:Show()
LBG.ShowOverlayGlow(slot.iconFrame)
elseif questId or isQuestItem then
questTexture:Hide()
LBG.ShowOverlayGlow(slot.iconFrame)
else
questTexture:Hide()
LBG.HideOverlayGlow(slot.iconFrame)
end
-- Check for FasterLooting scripts or w/e (if bag is full)
if textureID then
slot:Enable()
slot:Show()
end
end
else
local slot = lootFrame.slots[1] or createSlot(1)
local color = ITEM_QUALITY_COLORS[0]
slot.name:SetText(L["Empty Slot"])
if color then
slot.name:SetTextColor(color.r, color.g, color.b)
end
slot.icon:SetTexture[[Interface\Icons\INV_Misc_Herb_AncientLichen]]
w = max(w, slot.name:GetStringWidth())
slot.count:Hide()
slot.drop:Hide()
slot:Disable()
slot:Show()
end
anchorSlots(lootFrame)
w = w + 60
t = t + 5
local color = ITEM_QUALITY_COLORS[m]
lootFrame:SetBackdropBorderColor(color.r, color.g, color.b, .8)
lootFrame:Width(max(w, t))
end
function M:LoadLoot()
if not E.private.general.loot then return end
lootFrameHolder = CreateFrame('Frame', 'ElvLootFrameHolder', E.UIParent)
lootFrameHolder:Point('TOPLEFT', E.UIParent, 'TOPLEFT', 418, -186)
lootFrameHolder:Size(150, 22)
lootFrame = CreateFrame('Button', 'ElvLootFrame', lootFrameHolder, 'BackdropTemplate')
lootFrame:SetClampedToScreen(true)
lootFrame:Point('TOPLEFT')
lootFrame:Size(256, 64)
lootFrame:SetTemplate('Transparent')
lootFrame:SetFrameStrata(_G.LootFrame:GetFrameStrata())
lootFrame:SetToplevel(true)
lootFrame.title = lootFrame:CreateFontString(nil, 'OVERLAY')
lootFrame.title:FontTemplate(nil, nil, 'OUTLINE')
lootFrame.title:Point('BOTTOMLEFT', lootFrame, 'TOPLEFT', 0, 1)
lootFrame.slots = {}
lootFrame:SetScript('OnHide', function()
StaticPopup_Hide('CONFIRM_LOOT_DISTRIBUTION')
CloseLoot()
end)
E.frames[lootFrame] = nil
self:RegisterEvent('LOOT_OPENED')
self:RegisterEvent('LOOT_SLOT_CLEARED')
self:RegisterEvent('LOOT_CLOSED')
E:CreateMover(lootFrameHolder, 'LootFrameMover', L["Loot Frame"], nil, nil, nil, nil, nil, 'general,blizzUIImprovements')
-- Fuzz
_G.LootFrame:UnregisterAllEvents()
tinsert(_G.UISpecialFrames, 'ElvLootFrame')
end

321
Modules/Misc/LootRoll.lua Normal file
View File

@@ -0,0 +1,321 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule('Misc')
local _G = _G
local pairs, unpack, ipairs, next, tonumber, tinsert = pairs, unpack, ipairs, next, tonumber, tinsert
local ChatEdit_InsertLink = ChatEdit_InsertLink
local CreateFrame = CreateFrame
local CursorOnUpdate = CursorOnUpdate
local DressUpItemLink = DressUpItemLink
local GameTooltip_ShowCompareItem = GameTooltip_ShowCompareItem
local IsPlayerAtEffectiveMaxLevel = IsPlayerAtEffectiveMaxLevel
local GetLootRollItemInfo = GetLootRollItemInfo
local GetLootRollItemLink = GetLootRollItemLink
local GetLootRollTimeLeft = GetLootRollTimeLeft
local ShowInspectCursor = ShowInspectCursor
local IsControlKeyDown = IsControlKeyDown
local IsModifiedClick = IsModifiedClick
local IsShiftKeyDown = IsShiftKeyDown
local ResetCursor = ResetCursor
local RollOnLoot = RollOnLoot
local C_LootHistoryGetItem = C_LootHistory.GetItem
local C_LootHistoryGetPlayerInfo = C_LootHistory.GetPlayerInfo
local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS
local GREED, NEED, PASS = GREED, NEED, PASS
local ROLL_DISENCHANT = ROLL_DISENCHANT
local pos = 'TOP';
local cancelled_rolls = {}
local cachedRolls = {}
local completedRolls = {}
local FRAME_WIDTH, FRAME_HEIGHT = 328, 28
M.RollBars = {}
local function ClickRoll(frame)
RollOnLoot(frame.parent.rollID, frame.rolltype)
end
local function HideTip() _G.GameTooltip:Hide() end
local function HideTip2() _G.GameTooltip:Hide(); ResetCursor() end
local rolltypes = {[1] = 'need', [2] = 'greed', [3] = 'disenchant', [0] = 'pass'}
local function SetTip(frame)
local GameTooltip = _G.GameTooltip
GameTooltip:SetOwner(frame, 'ANCHOR_RIGHT')
GameTooltip:SetText(frame.tiptext)
if frame:IsEnabled() == 0 then GameTooltip:AddLine('|cffff3333'..L["Can't Roll"]) end
for name, tbl in pairs(frame.parent.rolls) do
if rolltypes[tbl[1]] == rolltypes[frame.rolltype] then
local classColor = E:ClassColor(tbl[2])
GameTooltip:AddLine(name, classColor.r, classColor.g, classColor.b)
end
end
GameTooltip:Show()
end
local function SetItemTip(frame)
if not frame.link then return end
_G.GameTooltip:SetOwner(frame, 'ANCHOR_TOPLEFT')
_G.GameTooltip:SetHyperlink(frame.link)
if IsShiftKeyDown() then GameTooltip_ShowCompareItem() end
if IsModifiedClick('DRESSUP') then ShowInspectCursor() else ResetCursor() end
end
local function ItemOnUpdate(self)
if IsShiftKeyDown() then GameTooltip_ShowCompareItem() end
CursorOnUpdate(self)
end
local function LootClick(frame)
if IsControlKeyDown() then DressUpItemLink(frame.link)
elseif IsShiftKeyDown() then ChatEdit_InsertLink(frame.link) end
end
local function OnEvent(frame, _, rollID)
cancelled_rolls[rollID] = true
if frame.rollID ~= rollID then return end
frame.rollID = nil
frame.time = nil
frame:Hide()
end
local function StatusUpdate(frame)
if not frame.parent.rollID then return end
local t = GetLootRollTimeLeft(frame.parent.rollID)
local perc = t / frame.parent.time
frame.spark:Point('CENTER', frame, 'LEFT', perc * frame:GetWidth(), 0)
frame:SetValue(t)
if t > 1000000000 then
frame:GetParent():Hide()
end
end
local function CreateRollButton(parent, ntex, ptex, htex, rolltype, tiptext, ...)
local f = CreateFrame('Button', nil, parent)
f:Point(...)
f:Size(FRAME_HEIGHT - 4)
f:SetNormalTexture(ntex)
if ptex then f:SetPushedTexture(ptex) end
f:SetHighlightTexture(htex)
f.rolltype = rolltype
f.parent = parent
f.tiptext = tiptext
f:SetScript('OnEnter', SetTip)
f:SetScript('OnLeave', HideTip)
f:SetScript('OnClick', ClickRoll)
f:SetMotionScriptsWhileDisabled(true)
local txt = f:CreateFontString(nil, 'ARTWORK')
txt:FontTemplate(nil, nil, 'OUTLINE')
txt:Point('CENTER', 0, rolltype == 2 and 1 or rolltype == 0 and -1.2 or 0)
return f, txt
end
function M:CreateRollFrame()
local frame = CreateFrame('Frame', nil, E.UIParent, 'BackdropTemplate')
frame:Size(FRAME_WIDTH, FRAME_HEIGHT)
frame:SetTemplate()
frame:SetScript('OnEvent', OnEvent)
frame:SetFrameStrata('MEDIUM')
frame:SetFrameLevel(10)
frame:RegisterEvent('CANCEL_LOOT_ROLL')
frame:Hide()
local button = CreateFrame('Button', nil, frame)
button:Point('RIGHT', frame, 'LEFT', -(E.Spacing*3), 0)
button:Size(FRAME_HEIGHT - (E.Border * 2), FRAME_HEIGHT - (E.Border * 2))
button:CreateBackdrop()
button:SetScript('OnEnter', SetItemTip)
button:SetScript('OnLeave', HideTip2)
button:SetScript('OnUpdate', ItemOnUpdate)
button:SetScript('OnClick', LootClick)
frame.button = button
button.icon = button:CreateTexture(nil, 'OVERLAY')
button.icon:SetAllPoints()
button.icon:SetTexCoord(unpack(E.TexCoords))
local tfade = frame:CreateTexture(nil, 'BORDER')
tfade:Point('TOPLEFT', frame, 'TOPLEFT', 4, 0)
tfade:Point('BOTTOMRIGHT', frame, 'BOTTOMRIGHT', -4, 0)
tfade:SetTexture([[Interface\ChatFrame\ChatFrameBackground]])
tfade:SetBlendMode('ADD')
tfade:SetGradientAlpha('VERTICAL', .1, .1, .1, 0, .1, .1, .1, 0)
local status = CreateFrame('StatusBar', nil, frame)
status:SetInside()
status:SetScript('OnUpdate', StatusUpdate)
status:SetFrameLevel(status:GetFrameLevel()-1)
status:SetStatusBarTexture(E.media.normTex)
E:RegisterStatusBar(status)
status:SetStatusBarColor(.8, .8, .8, .9)
status.parent = frame
frame.status = status
status.bg = status:CreateTexture(nil, 'BACKGROUND')
status.bg:SetAlpha(0.1)
status.bg:SetAllPoints()
status.bg:SetDrawLayer('BACKGROUND', 2)
local spark = frame:CreateTexture(nil, 'OVERLAY')
spark:Size(14, FRAME_HEIGHT)
spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
spark:SetBlendMode('ADD')
status.spark = spark
local need, needtext = CreateRollButton(frame, [[Interface\Buttons\UI-GroupLoot-Dice-Up]], [[Interface\Buttons\UI-GroupLoot-Dice-Highlight]], [[Interface\Buttons\UI-GroupLoot-Dice-Down]], 1, NEED, 'LEFT', frame.button, 'RIGHT', 5, -1)
local greed, greedtext = CreateRollButton(frame, [[Interface\Buttons\UI-GroupLoot-Coin-Up]], [[Interface\Buttons\UI-GroupLoot-Coin-Highlight]], [[Interface\Buttons\UI-GroupLoot-Coin-Down]], 2, GREED, 'LEFT', need, 'RIGHT', 0, -1)
local de, detext
de, detext = CreateRollButton(frame, [[Interface\Buttons\UI-GroupLoot-DE-Up]], [[Interface\Buttons\UI-GroupLoot-DE-Highlight]], [[Interface\Buttons\UI-GroupLoot-DE-Down]], 3, ROLL_DISENCHANT, 'LEFT', greed, 'RIGHT', 0, -1)
local pass, passtext = CreateRollButton(frame, [[Interface\Buttons\UI-GroupLoot-Pass-Up]], nil, [[Interface\Buttons\UI-GroupLoot-Pass-Down]], 0, PASS, 'LEFT', de or greed, 'RIGHT', 0, 2)
frame.needbutt, frame.greedbutt, frame.disenchantbutt = need, greed, de
frame.need, frame.greed, frame.pass, frame.disenchant = needtext, greedtext, passtext, detext
local bind = frame:CreateFontString(nil, 'ARTWORK')
bind:Point('LEFT', pass, 'RIGHT', 3, 1)
bind:FontTemplate(nil, nil, 'OUTLINE')
frame.fsbind = bind
local loot = frame:CreateFontString(nil, 'ARTWORK')
loot:FontTemplate(nil, nil, 'OUTLINE')
loot:Point('LEFT', bind, 'RIGHT', 0, 0)
loot:Point('RIGHT', frame, 'RIGHT', -5, 0)
loot:Size(200, 10)
loot:SetJustifyH('LEFT')
frame.fsloot = loot
frame.rolls = {}
return frame
end
local function GetFrame()
for _,f in ipairs(M.RollBars) do
if not f.rollID then return f end
end
local f = M:CreateRollFrame()
if pos == 'TOP' then
f:Point('TOP', next(M.RollBars) and M.RollBars[#M.RollBars] or _G.AlertFrameHolder, 'BOTTOM', 0, -4)
else
f:Point('BOTTOM', next(M.RollBars) and M.RollBars[#M.RollBars] or _G.AlertFrameHolder, 'TOP', 0, 4)
end
tinsert(M.RollBars, f)
return f
end
function M:START_LOOT_ROLL(_, rollID, time)
if cancelled_rolls[rollID] then return end
local f = GetFrame()
f.rollID = rollID
f.time = time
for i in pairs(f.rolls) do f.rolls[i] = nil end
f.need:SetText(0)
f.greed:SetText(0)
f.pass:SetText(0)
f.disenchant:SetText(0)
local texture, name, _, quality, bop, canNeed, canGreed, canDisenchant = GetLootRollItemInfo(rollID)
f.button.icon:SetTexture(texture)
f.button.link = GetLootRollItemLink(rollID)
if canNeed then f.needbutt:Enable() else f.needbutt:Disable() end
if canGreed then f.greedbutt:Enable() else f.greedbutt:Disable() end
if canDisenchant then f.disenchantbutt:Enable() else f.disenchantbutt:Disable() end
local needTexture = f.needbutt:GetNormalTexture()
local greenTexture = f.greedbutt:GetNormalTexture()
local disenchantTexture = f.disenchantbutt:GetNormalTexture()
needTexture:SetDesaturation(not canNeed)
greenTexture:SetDesaturation(not canGreed)
disenchantTexture:SetDesaturation(not canDisenchant)
if canNeed then f.needbutt:SetAlpha(1) else f.needbutt:SetAlpha(0.2) end
if canGreed then f.greedbutt:SetAlpha(1) else f.greedbutt:SetAlpha(0.2) end
if canDisenchant then f.disenchantbutt:SetAlpha(1) else f.disenchantbutt:SetAlpha(0.2) end
f.fsbind:SetText(bop and L["BoP"] or L["BoE"])
f.fsbind:SetVertexColor(bop and 1 or .3, bop and .3 or 1, bop and .1 or .3)
local color = ITEM_QUALITY_COLORS[quality]
f.fsloot:SetText(name)
f.status:SetStatusBarColor(color.r, color.g, color.b, .7)
f.status.bg:SetColorTexture(color.r, color.g, color.b)
f.status:SetMinMaxValues(0, time)
f.status:SetValue(time)
f:Point('CENTER', _G.WorldFrame, 'CENTER')
f:Show()
_G.AlertFrame:UpdateAnchors()
--Add cached roll info, if any
for rollid, rollTable in pairs(cachedRolls) do
if f.rollID == rollid then --rollid matches cached rollid
for rollerName, rollerInfo in pairs(rollTable) do
local rollType, class = rollerInfo[1], rollerInfo[2]
f.rolls[rollerName] = {rollType, class}
f[rolltypes[rollType]]:SetText(tonumber(f[rolltypes[rollType]]:GetText()) + 1)
end
completedRolls[rollid] = true
break
end
end
if E.db.general.autoRoll and IsPlayerAtEffectiveMaxLevel() and quality == 2 and not bop then
if canDisenchant then
RollOnLoot(rollID, 3)
else
RollOnLoot(rollID, 2)
end
end
end
function M:LOOT_HISTORY_ROLL_CHANGED(_, itemIdx, playerIdx)
local rollID = C_LootHistoryGetItem(itemIdx);
local name, class, rollType = C_LootHistoryGetPlayerInfo(itemIdx, playerIdx);
local rollIsHidden = true
if name and rollType then
for _,f in ipairs(M.RollBars) do
if f.rollID == rollID then
f.rolls[name] = {rollType, class}
f[rolltypes[rollType]]:SetText(tonumber(f[rolltypes[rollType]]:GetText()) + 1)
rollIsHidden = false
break
end
end
--History changed for a loot roll that hasn't popped up for the player yet, so cache it for later
if rollIsHidden then
cachedRolls[rollID] = cachedRolls[rollID] or {}
if not cachedRolls[rollID][name] then
cachedRolls[rollID][name] = {rollType, class}
end
end
end
end
function M:LOOT_HISTORY_ROLL_COMPLETE()
--Remove completed rolls from cache
for rollID in pairs(completedRolls) do
cachedRolls[rollID] = nil
completedRolls[rollID] = nil
end
end
M.LOOT_ROLLS_COMPLETE = M.LOOT_HISTORY_ROLL_COMPLETE
function M:LoadLootRoll()
if not E.private.general.lootRoll then return end
self:RegisterEvent('LOOT_HISTORY_ROLL_CHANGED')
self:RegisterEvent('LOOT_HISTORY_ROLL_COMPLETE')
self:RegisterEvent('START_LOOT_ROLL')
self:RegisterEvent('LOOT_ROLLS_COMPLETE')
_G.UIParent:UnregisterEvent('START_LOOT_ROLL')
_G.UIParent:UnregisterEvent('CANCEL_LOOT_ROLL')
end

382
Modules/Misc/Misc.lua Normal file
View File

@@ -0,0 +1,382 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule('Misc')
local Bags = E:GetModule('Bags')
local _G = _G
local select = select
local format = format
local CreateFrame = CreateFrame
local AcceptGroup = AcceptGroup
local C_FriendList_IsFriend = C_FriendList.IsFriend
local CanGuildBankRepair = CanGuildBankRepair
local CanMerchantRepair = CanMerchantRepair
local GetCVarBool, SetCVar = GetCVarBool, SetCVar
local GetGuildBankWithdrawMoney = GetGuildBankWithdrawMoney
local GetInstanceInfo = GetInstanceInfo
local GetItemInfo = GetItemInfo
local GetNumGroupMembers = GetNumGroupMembers
local GetQuestItemInfo = GetQuestItemInfo
local GetQuestItemLink = GetQuestItemLink
local GetNumQuestChoices = GetNumQuestChoices
local GetRaidRosterInfo = GetRaidRosterInfo
local GetRepairAllCost = GetRepairAllCost
local InCombatLockdown = InCombatLockdown
local IsActiveBattlefieldArena = IsActiveBattlefieldArena
local IsAddOnLoaded = IsAddOnLoaded
local IsArenaSkirmish = IsArenaSkirmish
local IsGuildMember = IsGuildMember
local IsInGroup = IsInGroup
local IsInRaid = IsInRaid
local IsPartyLFG = IsPartyLFG
local IsShiftKeyDown = IsShiftKeyDown
local RaidNotice_AddMessage = RaidNotice_AddMessage
local RepairAllItems = RepairAllItems
local SendChatMessage = SendChatMessage
local StaticPopup_Hide = StaticPopup_Hide
local StaticPopupSpecial_Hide = StaticPopupSpecial_Hide
local UninviteUnit = UninviteUnit
local UnitExists = UnitExists
local UnitGUID = UnitGUID
local UnitInRaid = UnitInRaid
local UnitName = UnitName
local IsInGuild = IsInGuild
local PlaySound = PlaySound
local GetNumFactions = GetNumFactions
local GetFactionInfo = GetFactionInfo
local GetWatchedFactionInfo = GetWatchedFactionInfo
local ExpandAllFactionHeaders = ExpandAllFactionHeaders
local SetWatchedFactionIndex = SetWatchedFactionIndex
local GetCurrentCombatTextEventInfo = GetCurrentCombatTextEventInfo
local hooksecurefunc = hooksecurefunc
local C_PartyInfo_LeaveParty = C_PartyInfo.LeaveParty
local C_BattleNet_GetGameAccountInfoByGUID = C_BattleNet.GetGameAccountInfoByGUID
local CombatLogGetCurrentEventInfo = CombatLogGetCurrentEventInfo
local LE_GAME_ERR_GUILD_NOT_ENOUGH_MONEY = LE_GAME_ERR_GUILD_NOT_ENOUGH_MONEY
local LE_GAME_ERR_NOT_ENOUGH_MONEY = LE_GAME_ERR_NOT_ENOUGH_MONEY
local MAX_PARTY_MEMBERS = MAX_PARTY_MEMBERS
local BOOST_THANKSFORPLAYING_SMALLER = SOUNDKIT.UI_70_BOOST_THANKSFORPLAYING_SMALLER
local INTERRUPT_MSG = L["Interrupted %s's \124cff71d5ff\124Hspell:%d:0\124h[%s]\124h\124r!"]
function M:ErrorFrameToggle(event)
if not E.db.general.hideErrorFrame then return end
if event == 'PLAYER_REGEN_DISABLED' then
_G.UIErrorsFrame:UnregisterEvent('UI_ERROR_MESSAGE')
else
_G.UIErrorsFrame:RegisterEvent('UI_ERROR_MESSAGE')
end
end
function M:COMBAT_LOG_EVENT_UNFILTERED()
local inGroup = IsInGroup()
if not inGroup then return end
local _, event, _, sourceGUID, _, _, _, destGUID, destName, _, _, _, _, _, spellID, spellName = CombatLogGetCurrentEventInfo()
local announce = event == 'SPELL_INTERRUPT' and (sourceGUID == E.myguid or sourceGUID == UnitGUID('pet')) and destGUID ~= E.myguid
if not announce then return end -- No announce-able interrupt from player or pet, exit.
local inRaid, inPartyLFG = IsInRaid(), IsPartyLFG()
--Skirmish/non-rated arenas need to use INSTANCE_CHAT but IsPartyLFG() returns 'false'
local _, instanceType = GetInstanceInfo()
if instanceType == 'arena' then
local skirmish = IsArenaSkirmish()
local _, isRegistered = IsActiveBattlefieldArena()
if skirmish or not isRegistered then
inPartyLFG = true
end
inRaid = false --IsInRaid() returns true for arenas and they should not be considered a raid
end
local channel, msg = E.db.general.interruptAnnounce, format(INTERRUPT_MSG, destName, spellID, spellName)
if channel == 'PARTY' then
SendChatMessage(msg, inPartyLFG and 'INSTANCE_CHAT' or 'PARTY')
elseif channel == 'RAID' then
SendChatMessage(msg, inPartyLFG and 'INSTANCE_CHAT' or (inRaid and 'RAID' or 'PARTY'))
elseif channel == 'RAID_ONLY' and inRaid then
SendChatMessage(msg, inPartyLFG and 'INSTANCE_CHAT' or 'RAID')
elseif channel == 'SAY' and instanceType ~= 'none' then
SendChatMessage(msg, 'SAY')
elseif channel == 'YELL' and instanceType ~= 'none' then
SendChatMessage(msg, 'YELL')
elseif channel == 'EMOTE' then
SendChatMessage(msg, 'EMOTE')
end
end
function M:COMBAT_TEXT_UPDATE(_, messagetype)
if not E.db.general.autoTrackReputation then return end
if messagetype == 'FACTION' then
local faction = GetCurrentCombatTextEventInfo()
if faction ~= 'Guild' and faction ~= GetWatchedFactionInfo() then
ExpandAllFactionHeaders()
for i = 1, GetNumFactions() do
if faction == GetFactionInfo(i) then
SetWatchedFactionIndex(i)
break
end
end
end
end
end
do -- Auto Repair Functions
local STATUS, TYPE, COST, POSS
function M:AttemptAutoRepair(playerOverride)
STATUS, TYPE, COST, POSS = '', E.db.general.autoRepair, GetRepairAllCost()
if POSS and COST > 0 then
--This check evaluates to true even if the guild bank has 0 gold, so we add an override
if IsInGuild() and TYPE == 'GUILD' and (playerOverride or (not CanGuildBankRepair() or COST > GetGuildBankWithdrawMoney())) then
TYPE = 'PLAYER'
end
RepairAllItems(TYPE == 'GUILD')
--Delay this a bit so we have time to catch the outcome of first repair attempt
E:Delay(0.5, M.AutoRepairOutput)
end
end
function M:AutoRepairOutput()
if TYPE == 'GUILD' then
if STATUS == 'GUILD_REPAIR_FAILED' then
M:AttemptAutoRepair(true) --Try using player money instead
else
E:Print(L["Your items have been repaired using guild bank funds for: "]..E:FormatMoney(COST, 'SMART', true)) --Amount, style, textOnly
end
elseif TYPE == 'PLAYER' then
if STATUS == 'PLAYER_REPAIR_FAILED' then
E:Print(L["You don't have enough money to repair."])
else
E:Print(L["Your items have been repaired for: "]..E:FormatMoney(COST, 'SMART', true)) --Amount, style, textOnly
end
end
end
function M:UI_ERROR_MESSAGE(_, messageType)
if messageType == LE_GAME_ERR_GUILD_NOT_ENOUGH_MONEY then
STATUS = 'GUILD_REPAIR_FAILED'
elseif messageType == LE_GAME_ERR_NOT_ENOUGH_MONEY then
STATUS = 'PLAYER_REPAIR_FAILED'
end
end
end
function M:MERCHANT_CLOSED()
self:UnregisterEvent('UI_ERROR_MESSAGE')
self:UnregisterEvent('UPDATE_INVENTORY_DURABILITY')
self:UnregisterEvent('MERCHANT_CLOSED')
end
function M:MERCHANT_SHOW()
if E.db.bags.vendorGrays.enable then E:Delay(0.5, Bags.VendorGrays, Bags) end
if E.db.general.autoRepair == 'NONE' or IsShiftKeyDown() or not CanMerchantRepair() then return end
--Prepare to catch 'not enough money' messages
self:RegisterEvent('UI_ERROR_MESSAGE')
--Use this to unregister events afterwards
self:RegisterEvent('MERCHANT_CLOSED')
M:AttemptAutoRepair()
end
function M:DisbandRaidGroup()
if InCombatLockdown() then return end -- Prevent user error in combat
if UnitInRaid('player') then
for i = 1, GetNumGroupMembers() do
local name, _, _, _, _, _, _, online = GetRaidRosterInfo(i)
if online and name ~= E.myname then
UninviteUnit(name)
end
end
else
for i = MAX_PARTY_MEMBERS, 1, -1 do
if UnitExists('party'..i) then
UninviteUnit(UnitName('party'..i))
end
end
end
C_PartyInfo_LeaveParty()
end
function M:PVPMessageEnhancement(_, msg)
if not E.db.general.enhancedPvpMessages then return end
local _, instanceType = GetInstanceInfo()
if instanceType == 'pvp' or instanceType == 'arena' then
RaidNotice_AddMessage(_G.RaidBossEmoteFrame, msg, _G.ChatTypeInfo.RAID_BOSS_EMOTE);
end
end
local hideStatic
function M:AutoInvite(event, _, _, _, _, _, _, inviterGUID)
if not E.db.general.autoAcceptInvite then return end
if event == 'PARTY_INVITE_REQUEST' then
-- Prevent losing que inside LFD if someone invites you to group
if _G.QueueStatusMinimapButton:IsShown() or IsInGroup() or (not inviterGUID or inviterGUID == '') then return end
if C_BattleNet_GetGameAccountInfoByGUID(inviterGUID) or C_FriendList_IsFriend(inviterGUID) or IsGuildMember(inviterGUID) then
hideStatic = true
AcceptGroup()
end
elseif event == 'GROUP_ROSTER_UPDATE' and hideStatic then
StaticPopupSpecial_Hide(_G.LFGInvitePopup) --New LFD popup when invited in custom created group
StaticPopup_Hide('PARTY_INVITE')
hideStatic = nil
end
end
function M:ForceCVars()
if not GetCVarBool('lockActionBars') and E.private.actionbar.enable then
SetCVar('lockActionBars', 1)
end
end
function M:PLAYER_ENTERING_WORLD()
self:ForceCVars()
self:ToggleChatBubbleScript()
end
--[[local function OnValueChanged(self, value)
local bar = _G.ElvUI_ChallengeModeTimer
bar.text:SetText(self:GetParent().TimeLeft:GetText())
bar:SetValue(value)
local r, g, b = E:ColorGradient(value / self:GetParent().timeLimit, 1, 0, 0, 1, 1, 0, 0, 1, 0)
bar:SetStatusBarColor(r, g, b)
end
local function ChallengeModeTimer_Update(timerID, elapsedTime, timeLimit)
local block = _G.ScenarioChallengeModeBlock;
_G.ElvUI_ChallengeModeTimer:SetMinMaxValues(0, block.timeLimit)
_G.ElvUI_ChallengeModeTimer:Show()
OnValueChanged(_G.ScenarioChallengeModeBlock.StatusBar, _G.ScenarioChallengeModeBlock.StatusBar:GetValue())
end
function M:SetupChallengeTimer()
local bar = CreateFrame('StatusBar', 'ElvUI_ChallengeModeTimer', E.UIParent)
bar:Size(250, 20)
bar:Point('TOPLEFT', E.UIParent, 'TOPLEFT', 10, -10)
bar:CreateBackdrop('Transparent')
bar:SetStatusBarTexture(E.media.normTex)
bar.text = bar:CreateFontString(nil, 'OVERLAY')
bar.text:Point('CENTER')
bar.text:FontTemplate()
_G.ScenarioChallengeModeBlock.StatusBar:HookScript('OnValueChanged', OnValueChanged)
hooksecurefunc('Scenario_ChallengeMode_ShowBlock', ChallengeModeTimer_Update)
end]]
function M:RESURRECT_REQUEST()
if E.db.general.resurrectSound then
PlaySound(BOOST_THANKSFORPLAYING_SMALLER, 'Master')
end
end
function M:ADDON_LOADED(_, addon)
if addon == 'Blizzard_InspectUI' then
M:SetupInspectPageInfo()
--[[elseif addon == 'Blizzard_ObjectiveTracker' then
M:SetupChallengeTimer()]]
end
end
function M:QUEST_COMPLETE()
if not E.db.general.questRewardMostValueIcon then return end
local firstItem = _G.QuestInfoRewardsFrameQuestInfoItem1
if not firstItem then return end
local numQuests = GetNumQuestChoices()
if numQuests < 2 then return end
local bestValue, bestItem = 0
for i = 1, numQuests do
local questLink = GetQuestItemLink('choice', i)
local _, _, amount = GetQuestItemInfo('choice', i)
local itemSellPrice = questLink and select(11, GetItemInfo(questLink))
local totalValue = (itemSellPrice and itemSellPrice * amount) or 0
if totalValue > bestValue then
bestValue = totalValue
bestItem = i
end
end
if bestItem then
local btn = _G['QuestInfoRewardsFrameQuestInfoItem'..bestItem]
if btn and btn.type == 'choice' then
M.QuestRewardGoldIconFrame:ClearAllPoints()
M.QuestRewardGoldIconFrame:Point('TOPRIGHT', btn, 'TOPRIGHT', -2, -2)
M.QuestRewardGoldIconFrame:Show()
end
end
end
function M:Initialize()
self.Initialized = true
self:LoadRaidMarker()
self:LoadLootRoll()
self:LoadChatBubbles()
self:LoadLoot()
self:ToggleItemLevelInfo(true)
self:RegisterEvent('MERCHANT_SHOW')
self:RegisterEvent('RESURRECT_REQUEST')
self:RegisterEvent('PLAYER_REGEN_DISABLED', 'ErrorFrameToggle')
self:RegisterEvent('PLAYER_REGEN_ENABLED', 'ErrorFrameToggle')
self:RegisterEvent('CHAT_MSG_BG_SYSTEM_HORDE', 'PVPMessageEnhancement')
self:RegisterEvent('CHAT_MSG_BG_SYSTEM_ALLIANCE', 'PVPMessageEnhancement')
self:RegisterEvent('CHAT_MSG_BG_SYSTEM_NEUTRAL', 'PVPMessageEnhancement')
self:RegisterEvent('PARTY_INVITE_REQUEST', 'AutoInvite')
self:RegisterEvent('GROUP_ROSTER_UPDATE', 'AutoInvite')
self:RegisterEvent('CVAR_UPDATE', 'ForceCVars')
self:RegisterEvent('COMBAT_TEXT_UPDATE')
self:RegisterEvent('PLAYER_ENTERING_WORLD')
self:RegisterEvent('QUEST_COMPLETE')
do -- questRewardMostValueIcon
local MostValue = CreateFrame('Frame', 'ElvUI_QuestRewardGoldIconFrame', _G.UIParent)
MostValue:SetFrameStrata('HIGH')
MostValue:Size(19)
MostValue:Hide()
MostValue.Icon = MostValue:CreateTexture(nil, 'OVERLAY')
MostValue.Icon:SetAllPoints(MostValue)
MostValue.Icon:SetTexture([[Interface\MONEYFRAME\UI-GoldIcon]])
M.QuestRewardGoldIconFrame = MostValue
hooksecurefunc(_G.QuestFrameRewardPanel, 'Hide', function()
if M.QuestRewardGoldIconFrame then
M.QuestRewardGoldIconFrame:Hide()
end
end)
end
if E.db.general.interruptAnnounce ~= 'NONE' then
self:RegisterEvent('COMBAT_LOG_EVENT_UNFILTERED')
end
if IsAddOnLoaded('Blizzard_InspectUI') then
M:SetupInspectPageInfo()
else
self:RegisterEvent('ADDON_LOADED')
end
--[[if IsAddOnLoaded('Blizzard_ObjectiveTracker') then
M:SetupChallengeTimer()
else
self:RegisterEvent('ADDON_LOADED')
end]]
end
E:RegisterModule(M:GetName())

109
Modules/Misc/RaidMarker.lua Normal file
View File

@@ -0,0 +1,109 @@
--Credit Baudzilla
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule('Misc')
local sin, cos, rad = math.sin, math.cos, rad -- sin~=math.sin, cos~=math.cos, rad==math.rad; why? who knows? :P
local CreateFrame = CreateFrame
local GetNumGroupMembers = GetNumGroupMembers
local UnitIsGroupLeader = UnitIsGroupLeader
local UnitIsGroupAssistant = UnitIsGroupAssistant
local IsInGroup, IsInRaid = IsInGroup, IsInRaid
local UnitExists, UnitIsDead = UnitExists, UnitIsDead
local GetCursorPosition = GetCursorPosition
local PlaySound = PlaySound
local SetRaidTarget = SetRaidTarget
local SetRaidTargetIconTexture = SetRaidTargetIconTexture
local UIErrorsFrame = UIErrorsFrame
-- GLOBALS: RaidMark_HotkeyPressed
local ButtonIsDown
function M:RaidMarkCanMark()
if not self.RaidMarkFrame then return false; end
if GetNumGroupMembers() > 0 then
if UnitIsGroupLeader('player') or UnitIsGroupAssistant('player') then
return true;
elseif IsInGroup() and not IsInRaid() then
return true;
else
UIErrorsFrame:AddMessage(L["You don't have permission to mark targets."], 1.0, 0.1, 0.1, 1.0);
return false;
end
else
return true
end
end
function M:RaidMarkShowIcons()
if not UnitExists('target') or UnitIsDead('target')then
return;
end
local x, y = GetCursorPosition();
local scale = E.UIParent:GetEffectiveScale();
self.RaidMarkFrame:Point('CENTER', E.UIParent, 'BOTTOMLEFT', x / scale, y / scale);
self.RaidMarkFrame:Show();
end
function RaidMark_HotkeyPressed(keystate)
ButtonIsDown = (keystate=='down') and M:RaidMarkCanMark();
if ButtonIsDown and M.RaidMarkFrame then
M:RaidMarkShowIcons();
elseif M.RaidMarkFrame then
M.RaidMarkFrame:Hide();
end
end
function M:RaidMark_OnEvent()
if ButtonIsDown and self.RaidMarkFrame then
self:RaidMarkShowIcons();
end
end
M:RegisterEvent('PLAYER_TARGET_CHANGED', 'RaidMark_OnEvent');
function M:RaidMarkButton_OnEnter()
self.Texture:ClearAllPoints();
self.Texture:Point('TOPLEFT', -10, 10);
self.Texture:Point('BOTTOMRIGHT', 10, -10);
end
function M:RaidMarkButton_OnLeave()
self.Texture:SetAllPoints();
end
function M:RaidMarkButton_OnClick(arg1)
PlaySound(1115) --U_CHAT_SCROLL_BUTTON
SetRaidTarget('target', (arg1~='RightButton') and self:GetID() or 0);
self:GetParent():Hide();
end
local ANG_RAD = rad(360) / 7
function M:LoadRaidMarker()
local marker = CreateFrame('Frame', nil, E.UIParent);
marker:EnableMouse(true);
marker:SetFrameStrata('DIALOG');
marker:Size(100);
for i = 1, 8 do
local button = CreateFrame('Button', 'RaidMarkIconButton'..i, marker);
button:Size(40);
button:SetID(i);
button.Texture = button:CreateTexture(button:GetName()..'NormalTexture', 'ARTWORK');
button.Texture:SetTexture([[Interface\TargetingFrame\UI-RaidTargetingIcons]]);
button.Texture:SetAllPoints();
SetRaidTargetIconTexture(button.Texture, i);
button:RegisterForClicks('LeftbuttonUp','RightbuttonUp');
button:SetScript('OnClick', M.RaidMarkButton_OnClick);
button:SetScript('OnEnter', M.RaidMarkButton_OnEnter);
button:SetScript('OnLeave', M.RaidMarkButton_OnLeave);
if i == 8 then
button:Point('CENTER');
else
local angle = ANG_RAD * (i - 1)
button:Point('CENTER', sin(angle) * 60, cos(angle) * 60);
end
end
M.RaidMarkFrame = marker;
end

View File

@@ -0,0 +1,408 @@
local E, L, V, P, G = unpack(select(2, ...)) -- Import Functions/Constants, Config, Locales
local RU = E:GetModule('RaidUtility')
local _G = _G
local unpack, ipairs, pairs, next = unpack, ipairs, pairs, next
local strfind, tinsert, wipe, sort = strfind, tinsert, wipe, sort
local IsInRaid = IsInRaid
local CreateFrame = CreateFrame
local DoReadyCheck = DoReadyCheck
local GameTooltip_Hide = GameTooltip_Hide
local GetInstanceInfo = GetInstanceInfo
local GetNumGroupMembers = GetNumGroupMembers
local GetRaidRosterInfo = GetRaidRosterInfo
local GetTexCoordsForRole = GetTexCoordsForRole
local InCombatLockdown = InCombatLockdown
local InitiateRolePoll = InitiateRolePoll
local SecureHandlerSetFrameRef = SecureHandlerSetFrameRef
local SecureHandler_OnClick = SecureHandler_OnClick
local ToggleFriendsFrame = ToggleFriendsFrame
local UnitGroupRolesAssigned = UnitGroupRolesAssigned
local UnitIsGroupAssistant = UnitIsGroupAssistant
local UnitIsGroupLeader = UnitIsGroupLeader
local C_PartyInfo_DoCountdown = C_PartyInfo.DoCountdown
local PRIEST_COLOR = RAID_CLASS_COLORS.PRIEST
local NUM_RAID_GROUPS = NUM_RAID_GROUPS
local PANEL_HEIGHT = 110
local PANEL_WIDTH = 230
local BUTTON_HEIGHT = 20
--Check if We are Raid Leader or Raid Officer
function RU:CheckRaidStatus()
if UnitIsGroupLeader('player') or UnitIsGroupAssistant('player') then
local _, instanceType = GetInstanceInfo()
return instanceType ~= 'pvp' and instanceType ~= 'arena'
end
end
--Change border when mouse is inside the button
function RU:ButtonEnter()
if self.backdrop then self = self.backdrop end
self:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
end
--Change border back to normal when mouse leaves button
function RU:ButtonLeave()
if self.backdrop then self = self.backdrop end
self:SetBackdropBorderColor(unpack(E.media.bordercolor))
end
-- Function to create buttons in this module
function RU:CreateUtilButton(name, parent, template, width, height, point, relativeto, point2, xOfs, yOfs, text, texture)
local b = CreateFrame('Button', name, parent, template)
b:Size(width, height)
b:Point(point, relativeto, point2, xOfs, yOfs)
b:HookScript('OnEnter', RU.ButtonEnter)
b:HookScript('OnLeave', RU.ButtonLeave)
b:SetTemplate(nil, true)
if text then
local t = b:CreateFontString(nil, 'OVERLAY')
t:FontTemplate()
t:Point('CENTER', b, 'CENTER', 0, -1)
t:SetJustifyH('CENTER')
t:SetText(text)
b:SetFontString(t)
b.text = t
elseif texture then
local t = b:CreateTexture(nil, 'OVERLAY')
t:SetTexture(texture)
t:Point('TOPLEFT', b, 'TOPLEFT', 1, -1)
t:Point('BOTTOMRIGHT', b, 'BOTTOMRIGHT', -1, 1)
t.tex = texture
b.texture = t
end
RU.Buttons[name] = b
return b
end
function RU:UpdateMedia()
for _, btn in pairs(RU.Buttons) do
if btn.text then btn.text:FontTemplate() end
if btn.texture then btn.texture:SetTexture(btn.texture.tex) end
btn:SetTemplate(nil, true)
end
if RU.MarkerButton then
RU.MarkerButton:CreateBackdrop(nil, true)
RU.MarkerButton.backdrop:SetAllPoints()
end
end
function RU:ToggleRaidUtil(event)
if InCombatLockdown() then
self:RegisterEvent('PLAYER_REGEN_ENABLED', 'ToggleRaidUtil')
return
end
local RaidUtilityPanel = _G.RaidUtilityPanel
local RaidUtility_ShowButton = _G.RaidUtility_ShowButton
if RU:CheckRaidStatus() then
if RaidUtilityPanel.toggled == true then
RaidUtility_ShowButton:Hide()
RaidUtilityPanel:Show()
else
RaidUtility_ShowButton:Show()
RaidUtilityPanel:Hide()
end
else
RaidUtility_ShowButton:Hide()
RaidUtilityPanel:Hide()
end
if event == 'PLAYER_REGEN_ENABLED' then
self:UnregisterEvent('PLAYER_REGEN_ENABLED', 'ToggleRaidUtil')
elseif self.updateMedia and event == 'PLAYER_ENTERING_WORLD' then
self:UpdateMedia()
self.updateMedia = nil
end
end
-- Credits oRA3 for the RoleIcons
local function sortColoredNames(a, b)
return a:sub(11) < b:sub(11)
end
local roleIconRoster = {}
function RU:RoleOnEnter()
wipe(roleIconRoster)
for i = 1, NUM_RAID_GROUPS do
roleIconRoster[i] = {}
end
local role = self.role
local point = E:GetScreenQuadrant(_G.RaidUtility_ShowButton)
local bottom = point and strfind(point, 'BOTTOM')
local left = point and strfind(point, 'LEFT')
local anchor1 = (bottom and left and 'BOTTOMLEFT') or (bottom and 'BOTTOMRIGHT') or (left and 'TOPLEFT') or 'TOPRIGHT'
local anchor2 = (bottom and left and 'BOTTOMRIGHT') or (bottom and 'BOTTOMLEFT') or (left and 'TOPRIGHT') or 'TOPLEFT'
local anchorX = left and 2 or -2
local GameTooltip = _G.GameTooltip
GameTooltip:SetOwner(E.UIParent, 'ANCHOR_NONE')
GameTooltip:Point(anchor1, self, anchor2, anchorX, 0)
GameTooltip:SetText(_G['INLINE_' .. role .. '_ICON'] .. _G[role])
local name, group, class, groupRole, color, coloredName, _
for i = 1, GetNumGroupMembers() do
name, _, group, _, _, class, _, _, _, _, _, groupRole = GetRaidRosterInfo(i)
if name and groupRole == role then
color = E:ClassColor(class, true) or PRIEST_COLOR
coloredName = ('|cff%02x%02x%02x%s'):format(color.r * 255, color.g * 255, color.b * 255, name:gsub('%-.+', '*'))
tinsert(roleIconRoster[group], coloredName)
end
end
for Group, list in ipairs(roleIconRoster) do
sort(list, sortColoredNames)
for _, Name in ipairs(list) do
GameTooltip:AddLine(('[%d] %s'):format(Group, Name), 1, 1, 1)
end
roleIconRoster[Group] = nil
end
GameTooltip:Show()
end
function RU:PositionRoleIcons()
local point = E:GetScreenQuadrant(_G.RaidUtility_ShowButton)
local left = point and strfind(point, 'LEFT')
_G.RaidUtilityRoleIcons:ClearAllPoints()
if left then
_G.RaidUtilityRoleIcons:Point('LEFT', _G.RaidUtilityPanel, 'RIGHT', -1, 0)
else
_G.RaidUtilityRoleIcons:Point('RIGHT', _G.RaidUtilityPanel, 'LEFT', 1, 0)
end
end
local count = {}
local function UpdateIcons(self)
if not IsInRaid() then
self:Hide()
return
else
self:Show()
RU:PositionRoleIcons()
end
wipe(count)
for i = 1, GetNumGroupMembers() do
local role = UnitGroupRolesAssigned('raid'..i)
if role and role ~= 'NONE' then
count[role] = (count[role] or 0) + 1
end
end
for Role, icon in next, _G.RaidUtilityRoleIcons.icons do
icon.count:SetText(count[Role] or 0)
end
end
function RU:Initialize()
if E.private.general.raidUtility == false then return end
self.Initialized = true
self.updateMedia = true -- update fonts and textures on entering world once, used to set the custom media from a plugin
self.Buttons = {}
local RaidUtilityPanel = CreateFrame('Frame', 'RaidUtilityPanel', E.UIParent, 'SecureHandlerBaseTemplate, BackdropTemplate')
RaidUtilityPanel:SetScript('OnMouseUp', function(panel, ...) SecureHandler_OnClick(panel, '_onclick', ...) end)
RaidUtilityPanel:SetTemplate('Transparent')
RaidUtilityPanel:Size(PANEL_WIDTH, PANEL_HEIGHT)
RaidUtilityPanel:Point('TOP', E.UIParent, 'TOP', -400, 1)
RaidUtilityPanel:SetFrameLevel(3)
RaidUtilityPanel.toggled = false
RaidUtilityPanel:SetFrameStrata('HIGH')
E.FrameLocks.RaidUtilityPanel = true
local ShowButton = self:CreateUtilButton('RaidUtility_ShowButton', E.UIParent, 'UIMenuButtonStretchTemplate, SecureHandlerClickTemplate, BackdropTemplate', 136, 18, 'TOP', E.UIParent, 'TOP', -400, E.Border, _G.RAID_CONTROL)
SecureHandlerSetFrameRef(ShowButton, 'RaidUtilityPanel', RaidUtilityPanel)
ShowButton:SetAttribute('_onclick', ([=[
local raidUtil = self:GetFrameRef('RaidUtilityPanel')
local closeButton = raidUtil:GetFrameRef('RaidUtility_CloseButton')
self:Hide()
raidUtil:Show()
local point = self:GetPoint()
local raidUtilPoint, closeButtonPoint, yOffset
if strfind(point, 'BOTTOM') then
raidUtilPoint = 'BOTTOM'
closeButtonPoint = 'TOP'
yOffset = 1
else
raidUtilPoint = 'TOP'
closeButtonPoint = 'BOTTOM'
yOffset = -1
end
yOffset = yOffset * (tonumber(%d))
raidUtil:ClearAllPoints()
closeButton:ClearAllPoints()
raidUtil:SetPoint(raidUtilPoint, self, raidUtilPoint)
closeButton:SetPoint(raidUtilPoint, raidUtil, closeButtonPoint, 0, yOffset)
]=]):format(-E.Border + E.Spacing*3))
ShowButton:SetScript('OnMouseUp', function()
RaidUtilityPanel.toggled = true
RU:PositionRoleIcons()
end)
ShowButton:SetMovable(true)
ShowButton:SetClampedToScreen(true)
ShowButton:SetClampRectInsets(0, 0, -1, 1)
ShowButton:RegisterForDrag('RightButton')
ShowButton:SetFrameStrata('HIGH')
ShowButton:SetScript('OnDragStart', function(sb)
sb:StartMoving()
end)
ShowButton:SetScript('OnDragStop', function(sb)
sb:StopMovingOrSizing()
local point = sb:GetPoint()
local xOffset = sb:GetCenter()
local screenWidth = E.UIParent:GetWidth() / 2
xOffset = xOffset - screenWidth
sb:ClearAllPoints()
if strfind(point, 'BOTTOM') then
sb:Point('BOTTOM', E.UIParent, 'BOTTOM', xOffset, -1)
else
sb:Point('TOP', E.UIParent, 'TOP', xOffset, 1)
end
end)
E.FrameLocks.RaidUtility_ShowButton = true
local CloseButton = self:CreateUtilButton('RaidUtility_CloseButton', RaidUtilityPanel, 'UIMenuButtonStretchTemplate, SecureHandlerClickTemplate, BackdropTemplate', 136, 18, 'TOP', RaidUtilityPanel, 'BOTTOM', 0, -1, _G.CLOSE)
SecureHandlerSetFrameRef(CloseButton, 'RaidUtility_ShowButton', ShowButton)
CloseButton:SetAttribute('_onclick', [=[self:GetParent():Hide(); self:GetFrameRef('RaidUtility_ShowButton'):Show();]=])
CloseButton:SetScript('OnMouseUp', function() RaidUtilityPanel.toggled = false end)
SecureHandlerSetFrameRef(RaidUtilityPanel, 'RaidUtility_CloseButton', CloseButton)
local RoleIcons = CreateFrame('Frame', 'RaidUtilityRoleIcons', RaidUtilityPanel, 'BackdropTemplate')
RoleIcons:Point('LEFT', RaidUtilityPanel, 'RIGHT', -1, 0)
RoleIcons:Size(36, PANEL_HEIGHT)
RoleIcons:SetTemplate('Transparent')
RoleIcons:RegisterEvent('PLAYER_ENTERING_WORLD')
RoleIcons:RegisterEvent('GROUP_ROSTER_UPDATE')
RoleIcons:SetScript('OnEvent', UpdateIcons)
RoleIcons.icons = {}
local roles = {'TANK', 'HEALER', 'DAMAGER'}
for i, role in ipairs(roles) do
local frame = CreateFrame('Frame', '$parent_'..role, RoleIcons)
if i == 1 then
frame:Point('TOP', 0, -5)
else
frame:Point('TOP', _G['RaidUtilityRoleIcons_'..roles[i-1]], 'BOTTOM', 0, -8)
end
local texture = frame:CreateTexture(nil, 'OVERLAY')
texture:SetTexture(E.Media.Textures.RoleIcons) --(337499)
local texA, texB, texC, texD = GetTexCoordsForRole(role)
texture:SetTexCoord(texA, texB, texC, texD)
texture:Point('TOPLEFT', frame, 'TOPLEFT', -2, 2)
texture:Point('BOTTOMRIGHT', frame, 'BOTTOMRIGHT', 2, -2)
frame.texture = texture
local Count = frame:CreateFontString(nil, 'OVERLAY', 'GameFontHighlight')
Count:Point('BOTTOMRIGHT', -2, 2)
Count:SetText(0)
frame.count = Count
frame.role = role
frame:SetScript('OnEnter', RU.RoleOnEnter)
frame:SetScript('OnLeave', GameTooltip_Hide)
frame:Size(28)
RoleIcons.icons[role] = frame
end
local BUTTON_WIDTH = PANEL_WIDTH - 20
self:CreateUtilButton('DisbandRaidButton', RaidUtilityPanel, 'UIMenuButtonStretchTemplate, BackdropTemplate', BUTTON_WIDTH, BUTTON_HEIGHT, 'TOP', RaidUtilityPanel, 'TOP', 0, -5, L["Disband Group"])
_G.DisbandRaidButton:SetScript('OnMouseUp', function()
if RU:CheckRaidStatus() then
E:StaticPopup_Show('DISBAND_RAID')
end
end)
self:CreateUtilButton('RoleCheckButton', RaidUtilityPanel, 'UIMenuButtonStretchTemplate, BackdropTemplate', BUTTON_WIDTH, BUTTON_HEIGHT, 'TOP', _G.DisbandRaidButton, 'BOTTOM', 0, -5, _G.ROLE_POLL)
_G.RoleCheckButton:SetScript('OnMouseUp', function() if RU:CheckRaidStatus() then InitiateRolePoll() end end)
--[[self:CreateUtilButton('MainTankButton', RaidUtilityPanel, 'SecureActionButtonTemplate, UIMenuButtonStretchTemplate, BackdropTemplate', (DisbandRaidButton:GetWidth() / 2) - 2, BUTTON_HEIGHT, 'TOPLEFT', RoleCheckButton, 'BOTTOMLEFT', 0, -5, MAINTANK)
MainTankButton:SetAttribute('type', 'maintank')
MainTankButton:SetAttribute('unit', 'target')
MainTankButton:SetAttribute('action', 'toggle')
self:CreateUtilButton('MainAssistButton', RaidUtilityPanel, 'SecureActionButtonTemplate, UIMenuButtonStretchTemplate, BackdropTemplate', (DisbandRaidButton:GetWidth() / 2) - 2, BUTTON_HEIGHT, 'TOPRIGHT', RoleCheckButton, 'BOTTOMRIGHT', 0, -5, MAINASSIST)
MainAssistButton:SetAttribute('type', 'mainassist')
MainAssistButton:SetAttribute('unit', 'target')
MainAssistButton:SetAttribute('action', 'toggle')]]
self:CreateUtilButton('ReadyCheckButton', RaidUtilityPanel, 'UIMenuButtonStretchTemplate, BackdropTemplate', BUTTON_WIDTH * 0.79, BUTTON_HEIGHT, 'TOPLEFT', _G.RoleCheckButton, 'BOTTOMLEFT', 0, -5, _G.READY_CHECK)
_G.ReadyCheckButton:SetScript('OnMouseUp', function() if RU:CheckRaidStatus() then DoReadyCheck() end end)
self:CreateUtilButton('RaidControlButton', RaidUtilityPanel, 'UIMenuButtonStretchTemplate, BackdropTemplate', BUTTON_WIDTH * 0.5, BUTTON_HEIGHT, 'TOPLEFT', _G.ReadyCheckButton, 'BOTTOMLEFT', 0, -5, L["Raid Menu"])
_G.RaidControlButton:SetScript('OnMouseUp', function() ToggleFriendsFrame(3) end)
self:CreateUtilButton('RaidCountdownButton', RaidUtilityPanel, 'UIMenuButtonStretchTemplate, BackdropTemplate', BUTTON_WIDTH * 0.49, BUTTON_HEIGHT, 'TOPLEFT', _G.RaidControlButton, 'TOPRIGHT', 2, 0, _G.PLAYER_COUNTDOWN_BUTTON)
_G.RaidCountdownButton:SetScript('OnMouseUp', function() C_PartyInfo_DoCountdown(10) end)
local buttons = {
'DisbandRaidButton',
'RoleCheckButton',
'ReadyCheckButton',
'RaidControlButton',
'RaidCountdownButton',
'RaidUtility_ShowButton',
'RaidUtility_CloseButton'
}
if _G.CompactRaidFrameManager then
--Reposition/Resize and Reuse the World Marker Button
tinsert(buttons, 'CompactRaidFrameManagerDisplayFrameLeaderOptionsRaidWorldMarkerButton')
local marker = _G.CompactRaidFrameManagerDisplayFrameLeaderOptionsRaidWorldMarkerButton
marker:SetParent('RaidUtilityPanel')
marker:ClearAllPoints()
marker:Point('TOPRIGHT', _G.RoleCheckButton, 'BOTTOMRIGHT', 0, -5)
marker:Size(BUTTON_WIDTH * 0.2, BUTTON_HEIGHT)
marker:HookScript('OnEnter', RU.ButtonEnter)
marker:HookScript('OnLeave', RU.ButtonLeave)
self.MarkerButton = marker
-- Since we steal the Marker Button for our utility panel, move the Ready Check button over a bit
local readyCheck = _G.CompactRaidFrameManagerDisplayFrameLeaderOptionsInitiateReadyCheck
readyCheck:ClearAllPoints()
readyCheck:Point('BOTTOMLEFT', _G.CompactRaidFrameManagerDisplayFrameLockedModeToggle, 'TOPLEFT', 0, 1)
readyCheck:Point('BOTTOMRIGHT', _G.CompactRaidFrameManagerDisplayFrameHiddenModeToggle, 'TOPRIGHT', 0, 1)
self.ReadyCheck = readyCheck
else
E:StaticPopup_Show('WARNING_BLIZZARD_ADDONS')
end
--Reskin Stuff
for _, button in pairs(buttons) do
local f = _G[button]
f.BottomLeft:SetAlpha(0)
f.BottomRight:SetAlpha(0)
f.BottomMiddle:SetAlpha(0)
f.TopMiddle:SetAlpha(0)
f.TopLeft:SetAlpha(0)
f.TopRight:SetAlpha(0)
f.MiddleLeft:SetAlpha(0)
f.MiddleRight:SetAlpha(0)
f.MiddleMiddle:SetAlpha(0)
f:SetHighlightTexture('')
f:SetDisabledTexture('')
end
--Automatically show/hide the frame if we have RaidLeader or RaidOfficer
self:RegisterEvent('GROUP_ROSTER_UPDATE', 'ToggleRaidUtil')
self:RegisterEvent('PLAYER_ENTERING_WORLD', 'ToggleRaidUtil')
end
E:RegisterInitialModule(RU:GetName())

117
Modules/Misc/TotemBar.lua Normal file
View File

@@ -0,0 +1,117 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local TOTEMS = E:GetModule('Totems')
local _G = _G
local unpack = unpack
local CreateFrame = CreateFrame
local GetTotemInfo = GetTotemInfo
local CooldownFrame_Set = CooldownFrame_Set
local MAX_TOTEMS = MAX_TOTEMS
function TOTEMS:Update()
for i=1, MAX_TOTEMS do
local button = _G['TotemFrameTotem'..i];
local _, _, startTime, duration, icon = GetTotemInfo(button.slot);
if button:IsShown() then
self.bar[i]:Show()
self.bar[i].iconTexture:SetTexture(icon)
CooldownFrame_Set(self.bar[i].cooldown, startTime, duration, 1)
button:ClearAllPoints();
button:SetParent(self.bar[i].holder);
button:SetAllPoints(self.bar[i].holder);
else
self.bar[i]:Hide()
end
end
end
function TOTEMS:PositionAndSize()
if not E.private.general.totemBar then return end
for i=1, MAX_TOTEMS do
local button = self.bar[i]
local prevButton = self.bar[i-1]
button:Size(self.db.size)
button:ClearAllPoints()
if self.db.growthDirection == 'HORIZONTAL' and self.db.sortDirection == 'ASCENDING' then
if i == 1 then
button:Point('LEFT', self.bar, 'LEFT', self.db.spacing, 0)
elseif prevButton then
button:Point('LEFT', prevButton, 'RIGHT', self.db.spacing, 0)
end
elseif self.db.growthDirection == 'VERTICAL' and self.db.sortDirection == 'ASCENDING' then
if i == 1 then
button:Point('TOP', self.bar, 'TOP', 0, -self.db.spacing)
elseif prevButton then
button:Point('TOP', prevButton, 'BOTTOM', 0, -self.db.spacing)
end
elseif self.db.growthDirection == 'HORIZONTAL' and self.db.sortDirection == 'DESCENDING' then
if i == 1 then
button:Point('RIGHT', self.bar, 'RIGHT', -self.db.spacing, 0)
elseif prevButton then
button:Point('RIGHT', prevButton, 'LEFT', -self.db.spacing, 0)
end
else
if i == 1 then
button:Point('BOTTOM', self.bar, 'BOTTOM', 0, self.db.spacing)
elseif prevButton then
button:Point('BOTTOM', prevButton, 'TOP', 0, self.db.spacing)
end
end
end
if self.db.growthDirection == 'HORIZONTAL' then
self.bar:Width(self.db.size*(MAX_TOTEMS) + self.db.spacing*(MAX_TOTEMS) + self.db.spacing)
self.bar:Height(self.db.size + self.db.spacing*2)
else
self.bar:Height(self.db.size*(MAX_TOTEMS) + self.db.spacing*(MAX_TOTEMS) + self.db.spacing)
self.bar:Width(self.db.size + self.db.spacing*2)
end
self:Update()
end
function TOTEMS:Initialize()
self.Initialized = true
if not E.private.general.totemBar then return end
self.db = E.db.general.totems
local bar = CreateFrame('Frame', 'ElvUI_TotemBar', E.UIParent)
bar:Point('BOTTOMLEFT', E.UIParent, 'BOTTOMLEFT', 490, 4)
self.bar = bar
for i=1, MAX_TOTEMS do
local frame = CreateFrame('Button', bar:GetName()..'Totem'..i, bar, 'BackdropTemplate')
frame:SetID(i)
frame:SetTemplate()
frame:StyleButton()
frame:Hide()
frame.holder = CreateFrame('Frame', nil, frame)
frame.holder:SetAlpha(0)
frame.holder:SetAllPoints()
frame.iconTexture = frame:CreateTexture(nil, 'ARTWORK')
frame.iconTexture:SetTexCoord(unpack(E.TexCoords))
frame.iconTexture:SetInside()
frame.cooldown = CreateFrame('Cooldown', frame:GetName()..'Cooldown', frame, 'CooldownFrameTemplate')
frame.cooldown:SetReverse(true)
frame.cooldown:SetInside()
E:RegisterCooldown(frame.cooldown)
self.bar[i] = frame;
end
self:PositionAndSize()
self:RegisterEvent('PLAYER_TOTEM_UPDATE', 'Update')
self:RegisterEvent('PLAYER_ENTERING_WORLD', 'Update')
E:CreateMover(bar, 'TotemBarMover', L["Class Totems"], nil, nil, nil, nil, nil, 'general,totems');
end
E:RegisterModule(TOTEMS:GetName())

View File

@@ -0,0 +1,164 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local NP = E:GetModule('NamePlates')
local UF = E:GetModule('UnitFrames')
local LSM = E.Libs.LSM
local _G = _G
local floor = floor
local unpack = unpack
local CreateFrame = CreateFrame
function NP:Construct_Auras(nameplate)
local frameName = nameplate:GetName()
local Buffs = CreateFrame('Frame', frameName..'Buffs', nameplate)
Buffs:SetFrameStrata(nameplate:GetFrameStrata())
Buffs:SetFrameLevel(5)
Buffs:Size(300, 27)
Buffs.disableMouse = true
Buffs.size = 27
Buffs.num = 4
Buffs.spacing = E.Border * 2
Buffs.onlyShowPlayer = false
Buffs.initialAnchor = 'BOTTOMLEFT'
Buffs['growth-x'] = 'RIGHT'
Buffs['growth-y'] = 'UP'
Buffs.type = 'buffs'
Buffs.forceShow = nameplate == _G.ElvNP_Test
local Debuffs = CreateFrame('Frame', frameName..'Debuffs', nameplate)
Debuffs:SetFrameStrata(nameplate:GetFrameStrata())
Debuffs:SetFrameLevel(5)
Debuffs:Size(300, 27)
Debuffs.disableMouse = true
Debuffs.size = 27
Debuffs.num = 4
Debuffs.spacing = E.Border * 2
Debuffs.onlyShowPlayer = false
Debuffs.initialAnchor = 'BOTTOMLEFT'
Debuffs['growth-x'] = 'RIGHT'
Debuffs['growth-y'] = 'UP'
Debuffs.type = 'debuffs'
Debuffs.forceShow = nameplate == _G.ElvNP_Test
Buffs.PostCreateIcon = NP.Construct_AuraIcon
Buffs.PostUpdateIcon = UF.PostUpdateAura
Buffs.CustomFilter = UF.AuraFilter
Debuffs.PostCreateIcon = NP.Construct_AuraIcon
Debuffs.PostUpdateIcon = UF.PostUpdateAura
Debuffs.CustomFilter = UF.AuraFilter
nameplate.Buffs_, nameplate.Debuffs_ = Buffs, Debuffs
nameplate.Buffs, nameplate.Debuffs = Buffs, Debuffs
end
function NP:Construct_AuraIcon(button)
if not button then return end
button:SetTemplate(nil, nil, nil, nil, nil, true)
button.cd:SetReverse(true)
button.cd:SetInside(button)
button.icon:SetDrawLayer('ARTWORK')
button.icon:SetInside()
button.count:ClearAllPoints()
button.count:Point('BOTTOMRIGHT', 1, 1)
button.count:SetJustifyH('RIGHT')
button.overlay:SetTexture()
button.stealable:SetTexture()
button.cd.CooldownOverride = 'nameplates'
E:RegisterCooldown(button.cd)
local auras = button:GetParent()
button.db = auras and NP.db.units and NP.db.units[auras.__owner.frameType] and NP.db.units[auras.__owner.frameType][auras.type]
NP:UpdateAuraSettings(button)
end
function NP:Configure_Auras(nameplate, auras, db)
auras.size = db.size
auras.num = db.numAuras
auras.onlyShowPlayer = false
auras.spacing = db.spacing
auras['growth-y'] = db.growthY
auras['growth-x'] = db.growthX
auras.initialAnchor = E.InversePoints[db.anchorPoint]
local index = 1
while auras[index] do
local button = auras[index]
if button then
button.db = db
NP:UpdateAuraSettings(button)
end
index = index + 1
end
local mult = floor((nameplate.width or 150) / db.size) < db.numAuras
auras:Size((nameplate.width or 150), (mult and 1 or 2) * db.size)
auras:ClearAllPoints()
auras:Point(E.InversePoints[db.anchorPoint] or 'TOPRIGHT', db.attachTo == 'BUFFS' and nameplate.Buffs or nameplate, db.anchorPoint or 'TOPRIGHT', db.xOffset, db.yOffset)
end
function NP:Update_Auras(nameplate)
local db = NP:PlateDB(nameplate)
if db.debuffs.enable or db.buffs.enable then
nameplate:SetAuraUpdateMethod(E.global.nameplate.effectiveAura)
nameplate:SetAuraUpdateSpeed(E.global.nameplate.effectiveAuraSpeed)
if not nameplate:IsElementEnabled('Auras') then
nameplate:EnableElement('Auras')
end
if db.debuffs.enable then
nameplate.Debuffs = nameplate.Debuffs_
NP:Configure_Auras(nameplate, nameplate.Debuffs, db.debuffs)
nameplate.Debuffs:Show()
nameplate.Debuffs:ForceUpdate()
elseif nameplate.Debuffs then
nameplate.Debuffs:Hide()
nameplate.Debuffs = nil
end
if db.buffs.enable then
nameplate.Buffs = nameplate.Buffs_
NP:Configure_Auras(nameplate, nameplate.Buffs, db.buffs)
nameplate.Buffs:Show()
nameplate.Buffs:ForceUpdate()
elseif nameplate.Buffs then
nameplate.Buffs:Hide()
nameplate.Buffs = nil
end
elseif nameplate:IsElementEnabled('Auras') then
nameplate:DisableElement('Auras')
end
end
function NP:UpdateAuraSettings(button)
if button.db then
button.count:FontTemplate(LSM:Fetch('font', button.db.countFont), button.db.countFontSize, button.db.countFontOutline)
button.count:ClearAllPoints()
local point = (button.db and button.db.countPosition) or 'CENTER'
if point == 'CENTER' then
button.count:Point(point, 1, 0)
else
local bottom, right = point:find('BOTTOM'), point:find('RIGHT')
button.count:SetJustifyH(right and 'RIGHT' or 'LEFT')
button.count:Point(point, right and -1 or 1, bottom and 1 or -1)
end
end
if button.icon then
button.icon:SetTexCoord(unpack(E.TexCoords))
end
button:Size((button.db and button.db.size) or 26)
button.needsUpdateCooldownPosition = true
end

View File

@@ -0,0 +1,233 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local NP = E:GetModule('NamePlates')
local CH = E:GetModule('Chat')
local LSM = E.Libs.LSM
local _G = _G
local abs = abs
local unpack = unpack
local strjoin = strjoin
local strmatch = strmatch
local CreateFrame = CreateFrame
local UnitCanAttack = UnitCanAttack
local CombatLogGetCurrentEventInfo = CombatLogGetCurrentEventInfo
local INTERRUPTED = INTERRUPTED
function NP:Castbar_CheckInterrupt(unit)
if unit == 'vehicle' then
unit = 'player'
end
if self.notInterruptible and UnitCanAttack('player', unit) then
self:SetStatusBarColor(NP.db.colors.castNoInterruptColor.r, NP.db.colors.castNoInterruptColor.g, NP.db.colors.castNoInterruptColor.b)
if self.Icon and NP.db.colors.castbarDesaturate then
self.Icon:SetDesaturated(true)
end
else
self:SetStatusBarColor(NP.db.colors.castColor.r, NP.db.colors.castColor.g, NP.db.colors.castColor.b)
if self.Icon then
self.Icon:SetDesaturated(false)
end
end
end
function NP:Castbar_CustomDelayText(duration)
if self.channeling then
if self.channelTimeFormat == 'CURRENT' then
self.Time:SetFormattedText('%.1f |cffaf5050%.1f|r', abs(duration - self.max), self.delay)
elseif self.channelTimeFormat == 'CURRENTMAX' then
self.Time:SetFormattedText('%.1f / %.1f |cffaf5050%.1f|r', duration, self.max, self.delay)
elseif self.channelTimeFormat == 'REMAINING' then
self.Time:SetFormattedText('%.1f |cffaf5050%.1f|r', duration, self.delay)
elseif self.channelTimeFormat == 'REMAININGMAX' then
self.Time:SetFormattedText('%.1f / %.1f |cffaf5050%.1f|r', abs(duration - self.max), self.max, self.delay)
end
else
if self.castTimeFormat == 'CURRENT' then
self.Time:SetFormattedText('%.1f |cffaf5050%s %.1f|r', duration, '+', self.delay)
elseif self.castTimeFormat == 'CURRENTMAX' then
self.Time:SetFormattedText('%.1f / %.1f |cffaf5050%s %.1f|r', duration, self.max, '+', self.delay)
elseif self.castTimeFormat == 'REMAINING' then
self.Time:SetFormattedText('%.1f |cffaf5050%s %.1f|r', abs(duration - self.max), '+', self.delay)
elseif self.castTimeFormat == 'REMAININGMAX' then
self.Time:SetFormattedText('%.1f / %.1f |cffaf5050%s %.1f|r', abs(duration - self.max), self.max, '+', self.delay)
end
end
end
function NP:Castbar_CustomTimeText(duration)
if self.channeling then
if self.channelTimeFormat == 'CURRENT' then
self.Time:SetFormattedText('%.1f', abs(duration - self.max))
elseif self.channelTimeFormat == 'CURRENTMAX' then
self.Time:SetFormattedText('%.1f / %.1f', abs(duration - self.max), self.max)
elseif self.channelTimeFormat == 'REMAINING' then
self.Time:SetFormattedText('%.1f', duration)
elseif self.channelTimeFormat == 'REMAININGMAX' then
self.Time:SetFormattedText('%.1f / %.1f', duration, self.max)
end
else
if self.castTimeFormat == 'CURRENT' then
self.Time:SetFormattedText('%.1f', duration)
elseif self.castTimeFormat == 'CURRENTMAX' then
self.Time:SetFormattedText('%.1f / %.1f', duration, self.max)
elseif self.castTimeFormat == 'REMAINING' then
self.Time:SetFormattedText('%.1f', abs(duration - self.max))
elseif self.castTimeFormat == 'REMAININGMAX' then
self.Time:SetFormattedText('%.1f / %.1f', abs(duration - self.max), self.max)
end
end
end
function NP:Castbar_PostCastStart(unit)
self:CheckInterrupt(unit)
NP:StyleFilterUpdate(self.__owner, 'FAKE_Casting')
end
function NP:Castbar_PostCastFail()
self:SetStatusBarColor(NP.db.colors.castInterruptedColor.r, NP.db.colors.castInterruptedColor.g, NP.db.colors.castInterruptedColor.b)
NP:StyleFilterUpdate(self.__owner, 'FAKE_Casting')
end
function NP:Castbar_PostCastInterruptible(unit)
self:CheckInterrupt(unit)
end
function NP:Castbar_PostCastStop()
NP:StyleFilterUpdate(self.__owner, 'FAKE_Casting')
end
function NP:Construct_Castbar(nameplate)
local Castbar = CreateFrame('StatusBar', nameplate:GetName()..'Castbar', nameplate)
Castbar:SetFrameStrata(nameplate:GetFrameStrata())
Castbar:SetFrameLevel(5)
Castbar:CreateBackdrop('Transparent', nil, nil, nil, nil, true)
Castbar:SetStatusBarTexture(LSM:Fetch('statusbar', NP.db.statusbar))
NP.StatusBars[Castbar] = true
Castbar.Button = CreateFrame('Frame', nil, Castbar, 'BackdropTemplate')
Castbar.Button:SetTemplate()
Castbar.Icon = Castbar.Button:CreateTexture(nil, 'ARTWORK')
Castbar.Icon:SetTexCoord(unpack(E.TexCoords))
Castbar.Icon:SetInside()
Castbar.Time = Castbar:CreateFontString(nil, 'OVERLAY')
Castbar.Time:Point('RIGHT', Castbar, 'RIGHT', -4, 0)
Castbar.Time:SetJustifyH('RIGHT')
Castbar.Time:FontTemplate(LSM:Fetch('font', NP.db.font), NP.db.fontSize, NP.db.fontOutline)
Castbar.Text = Castbar:CreateFontString(nil, 'OVERLAY')
Castbar.Text:SetJustifyH('LEFT')
Castbar.Text:FontTemplate(LSM:Fetch('font', NP.db.font), NP.db.fontSize, NP.db.fontOutline)
Castbar.Text:SetWordWrap(false)
Castbar.CheckInterrupt = NP.Castbar_CheckInterrupt
Castbar.CustomDelayText = NP.Castbar_CustomDelayText
Castbar.CustomTimeText = NP.Castbar_CustomTimeText
Castbar.PostCastStart = NP.Castbar_PostCastStart
Castbar.PostCastFail = NP.Castbar_PostCastFail
Castbar.PostCastInterruptible = NP.Castbar_PostCastInterruptible
Castbar.PostCastStop = NP.Castbar_PostCastStop
if nameplate == _G.ElvNP_Test then
Castbar.Hide = Castbar.Show
Castbar:Show()
Castbar.Text:SetText('Casting')
Castbar.Time:SetText('3.1')
Castbar.Icon:SetTexture([[Interface\Icons\Achievement_Character_Pandaren_Female]])
Castbar:SetStatusBarColor(NP.db.colors.castColor.r, NP.db.colors.castColor.g, NP.db.colors.castColor.b)
end
return Castbar
end
function NP:COMBAT_LOG_EVENT_UNFILTERED()
local _, event, _, sourceGUID, sourceName, _, _, targetGUID = CombatLogGetCurrentEventInfo()
if (event == 'SPELL_INTERRUPT' or event == 'SPELL_PERIODIC_INTERRUPT') and targetGUID and (sourceName and sourceName ~= '') then
local plate, classColor = NP.PlateGUID[targetGUID]
if plate and plate.Castbar then
local db = plate.frameType and self.db and self.db.units and self.db.units[plate.frameType]
if db and db.castbar and db.castbar.enable and db.castbar.sourceInterrupt then
if db.castbar.timeToHold > 0 then
local name = strmatch(sourceName, '([^%-]+).*')
if db.castbar.sourceInterruptClassColor then
local data = CH:GetPlayerInfoByGUID(sourceGUID)
if data and data.classColor then
classColor = data.classColor.colorStr
end
plate.Castbar.Text:SetFormattedText('%s > %s', INTERRUPTED, classColor and strjoin('', '|c', classColor, name) or name)
else
plate.Castbar.Text:SetFormattedText('%s > %s', INTERRUPTED, name)
end
end
end
end
end
end
function NP:Update_Castbar(nameplate)
local db = NP:PlateDB(nameplate)
if nameplate == _G.ElvNP_Test then
nameplate.Castbar:SetAlpha((not db.nameOnly and db.castbar.enable) and 1 or 0)
end
if db.castbar.enable then
if not nameplate:IsElementEnabled('Castbar') then
nameplate:EnableElement('Castbar')
end
nameplate.Castbar.timeToHold = db.castbar.timeToHold
nameplate.Castbar.castTimeFormat = db.castbar.castTimeFormat
nameplate.Castbar.channelTimeFormat = db.castbar.channelTimeFormat
nameplate.Castbar:Size(db.castbar.width, db.castbar.height)
nameplate.Castbar:Point('CENTER', nameplate, 'CENTER', db.castbar.xOffset, db.castbar.yOffset)
if db.castbar.showIcon then
nameplate.Castbar.Button:ClearAllPoints()
nameplate.Castbar.Button:Point(db.castbar.iconPosition == 'RIGHT' and 'BOTTOMLEFT' or 'BOTTOMRIGHT', nameplate.Castbar, db.castbar.iconPosition == 'RIGHT' and 'BOTTOMRIGHT' or 'BOTTOMLEFT', db.castbar.iconOffsetX, db.castbar.iconOffsetY)
nameplate.Castbar.Button:Size(db.castbar.iconSize, db.castbar.iconSize)
nameplate.Castbar.Button:Show()
else
nameplate.Castbar.Button:Hide()
end
nameplate.Castbar.Time:ClearAllPoints()
nameplate.Castbar.Text:ClearAllPoints()
if db.castbar.textPosition == 'BELOW' then
nameplate.Castbar.Time:Point('TOPRIGHT', nameplate.Castbar, 'BOTTOMRIGHT')
nameplate.Castbar.Text:Point('TOPLEFT', nameplate.Castbar, 'BOTTOMLEFT')
elseif db.castbar.textPosition == 'ABOVE' then
nameplate.Castbar.Time:Point('BOTTOMRIGHT', nameplate.Castbar, 'TOPRIGHT')
nameplate.Castbar.Text:Point('BOTTOMLEFT', nameplate.Castbar, 'TOPLEFT')
else
nameplate.Castbar.Time:Point('RIGHT', nameplate.Castbar, 'RIGHT', -1, 0)
nameplate.Castbar.Text:Point('LEFT', nameplate.Castbar, 'LEFT', 1, 0)
end
nameplate.Castbar.Text:Point('RIGHT', nameplate.Castbar, 'RIGHT', -20, 0)
if db.castbar.hideTime then
nameplate.Castbar.Time:Hide()
else
nameplate.Castbar.Time:FontTemplate(LSM:Fetch('font', db.castbar.font), db.castbar.fontSize, db.castbar.fontOutline)
nameplate.Castbar.Time:Show()
end
if db.castbar.hideSpellName then
nameplate.Castbar.Text:Hide()
else
nameplate.Castbar.Text:FontTemplate(LSM:Fetch('font', db.castbar.font), db.castbar.fontSize, db.castbar.fontOutline)
nameplate.Castbar.Text:Show()
end
elseif nameplate:IsElementEnabled('Castbar') then
nameplate:DisableElement('Castbar')
end
end

View File

@@ -0,0 +1,269 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local NP = E:GetModule('NamePlates')
local LSM = E.Libs.LSM
local oUF = E.oUF
local _G = _G
local unpack, max = unpack, max
local CreateFrame = CreateFrame
local UnitHasVehicleUI = UnitHasVehicleUI
local MAX_POINTS = {
DRUID = 5,
DEATHKNIGHT = 6,
MAGE = 4,
MONK = 6,
PALADIN = 5,
ROGUE = 6,
WARLOCK = 5
}
function NP:ClassPower_UpdateColor(powerType)
local color, r, g, b = NP.db.colors.classResources[E.myclass] or NP.db.colors.power[powerType]
if color then
r, g, b = color.r, color.g, color.b
else
color = oUF.colors.power[powerType]
r, g, b = unpack(color)
end
local db = NP.db.units[self.__owner.frameType]
local ClassColor = db and db.classpower.classColor and E:ClassColor(E.myclass)
for i = 1, #self do
local classColor = ClassColor or (powerType == 'COMBO_POINTS' and NP.db.colors.classResources.comboPoints[i] or powerType == 'CHI' and NP.db.colors.classResources.MONK[i])
if classColor then r, g, b = classColor.r, classColor.g, classColor.b end
self[i]:SetStatusBarColor(r, g, b)
if self[i].bg then self[i].bg:SetVertexColor(r * NP.multiplier, g * NP.multiplier, b * NP.multiplier) end
end
end
function NP:ClassPower_PostUpdate(Cur, _, needUpdate)
if Cur and Cur > 0 then
self:Show()
else
self:Hide()
end
if needUpdate then
NP:Update_ClassPower(self.__owner)
end
end
function NP:Construct_ClassPower(nameplate)
local frameName = nameplate:GetName()
local ClassPower = CreateFrame('Frame', frameName..'ClassPower', nameplate)
ClassPower:CreateBackdrop('Transparent', nil, nil, nil, nil, true)
ClassPower:Hide()
ClassPower:SetFrameStrata(nameplate:GetFrameStrata())
ClassPower:SetFrameLevel(5)
local Max = max(MAX_POINTS[E.myclass] or 0, _G.MAX_COMBO_POINTS)
local texture = LSM:Fetch('statusbar', NP.db.statusbar)
for i = 1, Max do
ClassPower[i] = CreateFrame('StatusBar', frameName..'ClassPower'..i, ClassPower)
ClassPower[i]:SetStatusBarTexture(texture)
ClassPower[i]:SetFrameStrata(nameplate:GetFrameStrata())
ClassPower[i]:SetFrameLevel(6)
NP.StatusBars[ClassPower[i]] = true
ClassPower[i].bg = ClassPower:CreateTexture(frameName..'ClassPower'..i..'bg', 'BORDER')
ClassPower[i].bg:SetAllPoints(ClassPower[i])
ClassPower[i].bg:SetTexture(texture)
end
if nameplate == _G.ElvNP_Test then
ClassPower.Hide = ClassPower.Show
ClassPower:Show()
for i = 1, Max do
ClassPower[i]:SetStatusBarTexture(texture)
ClassPower[i].bg:SetTexture(texture)
ClassPower[i].bg:SetVertexColor(NP.db.colors.classResources.comboPoints[i].r, NP.db.colors.classResources.comboPoints[i].g, NP.db.colors.classResources.comboPoints[i].b)
end
end
ClassPower.UpdateColor = NP.ClassPower_UpdateColor
ClassPower.PostUpdate = NP.ClassPower_PostUpdate
return ClassPower
end
function NP:Update_ClassPower(nameplate)
local db = NP:PlateDB(nameplate)
if nameplate == _G.ElvNP_Test then
if not db.nameOnly and db.classpower and db.classpower.enable then
NP.ClassPower_UpdateColor(nameplate.ClassPower, 'COMBO_POINTS')
nameplate.ClassPower:SetAlpha(1)
else
nameplate.ClassPower:SetAlpha(0)
end
end
if (nameplate.frameType == 'PLAYER' or nameplate.frameType == 'TARGET') and db.classpower and db.classpower.enable then
if not nameplate:IsElementEnabled('ClassPower') then
nameplate:EnableElement('ClassPower')
end
nameplate.ClassPower:ClearAllPoints()
nameplate.ClassPower:Point('CENTER', nameplate, 'CENTER', db.classpower.xOffset, db.classpower.yOffset)
local maxClassBarButtons = nameplate.ClassPower.__max
local Width = db.classpower.width / maxClassBarButtons
nameplate.ClassPower:Size(db.classpower.width, db.classpower.height)
for i = 1, #nameplate.ClassPower do
nameplate.ClassPower[i]:Hide()
nameplate.ClassPower[i].bg:Hide()
end
for i = 1, maxClassBarButtons do
nameplate.ClassPower[i]:Show()
nameplate.ClassPower[i].bg:Show()
nameplate.ClassPower[i]:ClearAllPoints()
if i == 1 then
nameplate.ClassPower[i]:Size(Width - (maxClassBarButtons == 6 and 2 or 0), db.classpower.height)
nameplate.ClassPower[i].bg:Size(Width - (maxClassBarButtons == 6 and 2 or 0), db.classpower.height)
nameplate.ClassPower[i]:ClearAllPoints()
nameplate.ClassPower[i]:Point('LEFT', nameplate.ClassPower, 'LEFT', 0, 0)
else
nameplate.ClassPower[i]:Size(Width - 1, db.classpower.height)
nameplate.ClassPower[i].bg:Size(Width - 1, db.classpower.height)
nameplate.ClassPower[i]:ClearAllPoints()
nameplate.ClassPower[i]:Point('LEFT', nameplate.ClassPower[i - 1], 'RIGHT', 1, 0)
if i == maxClassBarButtons then
nameplate.ClassPower[i]:Point('RIGHT', nameplate.ClassPower)
end
end
end
else
if nameplate:IsElementEnabled('ClassPower') then
nameplate:DisableElement('ClassPower')
end
nameplate.ClassPower:Hide()
end
end
function NP:Runes_PostUpdate()
if UnitHasVehicleUI('player') then
self:Hide()
else
self:Show()
end
end
function NP:Construct_Runes(nameplate)
local frameName = nameplate:GetName()
local Runes = CreateFrame('Frame', frameName..'Runes', nameplate)
Runes:SetFrameStrata(nameplate:GetFrameStrata())
Runes:SetFrameLevel(5)
Runes:CreateBackdrop('Transparent', nil, nil, nil, nil, true)
Runes:Hide()
Runes.UpdateColor = E.noop
Runes.PostUpdate = NP.Runes_PostUpdate
local texture = LSM:Fetch('statusbar', NP.db.statusbar)
local color = NP.db.colors.classResources.DEATHKNIGHT
for i = 1, 6 do
Runes[i] = CreateFrame('StatusBar', frameName..'Runes'..i, Runes)
Runes[i]:SetStatusBarTexture(texture)
Runes[i]:SetStatusBarColor(color.r, color.g, color.b)
NP.StatusBars[Runes[i]] = true
Runes[i].bg = Runes[i]:CreateTexture(frameName..'Runes'..i..'bg', 'BORDER')
Runes[i].bg:SetVertexColor(color.r * NP.multiplier, color.g * NP.multiplier, color.b * NP.multiplier)
Runes[i].bg:SetTexture(texture)
Runes[i].bg:SetAllPoints()
end
return Runes
end
function NP:Update_Runes(nameplate)
local db = NP:PlateDB(nameplate)
if (nameplate.frameType == 'PLAYER' or nameplate.frameType == 'TARGET') and db.classpower and db.classpower.enable then
if not nameplate:IsElementEnabled('Runes') then
nameplate:EnableElement('Runes')
end
nameplate.Runes:Show()
nameplate.Runes:ClearAllPoints()
nameplate.Runes:Point('CENTER', nameplate, 'CENTER', db.classpower.xOffset, db.classpower.yOffset)
nameplate.Runes.sortOrder = db.classpower.sortDirection
local width = db.classpower.width / 6
nameplate.Runes:Size(db.classpower.width, db.classpower.height)
local runeColor = (db.classpower.classColor and E:ClassColor(E.myclass)) or NP.db.colors.classResources.DEATHKNIGHT
for i = 1, 6 do
nameplate.Runes[i]:SetStatusBarColor(runeColor.r, runeColor.g, runeColor.b)
if i == 1 then
nameplate.Runes[i]:Size(width, db.classpower.height)
nameplate.Runes[i].bg:Size(width, db.classpower.height)
nameplate.Runes[i]:ClearAllPoints()
nameplate.Runes[i]:Point('LEFT', nameplate.Runes, 'LEFT', 0, 0)
else
nameplate.Runes[i]:Size(width - 1, db.classpower.height)
nameplate.Runes[i].bg:Size(width - 1, db.classpower.height)
nameplate.Runes[i]:ClearAllPoints()
nameplate.Runes[i]:Point('LEFT', nameplate.Runes[i-1], 'RIGHT', 1, 0)
if i == 6 then
nameplate.Runes[6]:Point('RIGHT', nameplate.Runes)
end
end
end
else
if nameplate:IsElementEnabled('Runes') then
nameplate:DisableElement('Runes')
end
nameplate.Runes:Hide()
end
end
function NP:Construct_Stagger(nameplate)
local Stagger = CreateFrame('StatusBar', nameplate:GetName()..'Stagger', nameplate)
Stagger:SetFrameStrata(nameplate:GetFrameStrata())
Stagger:SetFrameLevel(5)
Stagger:SetStatusBarTexture(LSM:Fetch('statusbar', NP.db.statusbar))
Stagger:CreateBackdrop('Transparent', nil, nil, nil, nil, true)
Stagger:Hide()
NP.StatusBars[Stagger] = true
return Stagger
end
function NP:Update_Stagger(nameplate)
local db = NP:PlateDB(nameplate)
if (nameplate.frameType == 'PLAYER' or nameplate.frameType == 'TARGET') and db.classpower and db.classpower.enable then
if not nameplate:IsElementEnabled('Stagger') then
nameplate:EnableElement('Stagger')
end
nameplate.Stagger:ClearAllPoints()
nameplate.Stagger:Point('CENTER', nameplate, 'CENTER', db.classpower.xOffset, db.classpower.yOffset)
nameplate.Stagger:Size(db.classpower.width, db.classpower.height)
elseif nameplate:IsElementEnabled('Stagger') then
nameplate:DisableElement('Stagger')
end
end

View File

@@ -0,0 +1,185 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local NP = E:GetModule('NamePlates')
local LSM = E.Libs.LSM
local ipairs = ipairs
local unpack = unpack
local UnitPlayerControlled = UnitPlayerControlled
local UnitIsTapDenied = UnitIsTapDenied
local UnitClass = UnitClass
local UnitReaction = UnitReaction
local UnitIsConnected = UnitIsConnected
local CreateFrame = CreateFrame
function NP:Health_UpdateColor(_, unit)
if not unit or self.unit ~= unit then return end
local element = self.Health
local Selection = element.colorSelection and NP:UnitSelectionType(unit, element.considerSelectionInCombatHostile)
local r, g, b, t
if element.colorDisconnected and not UnitIsConnected(unit) then
t = self.colors.disconnected
elseif element.colorTapping and not UnitPlayerControlled(unit) and UnitIsTapDenied(unit) then
t = NP.db.colors.tapped
elseif (element.colorClass and self.isPlayer) or (element.colorClassNPC and not self.isPlayer) or (element.colorClassPet and UnitPlayerControlled(unit) and not self.isPlayer) then
local _, class = UnitClass(unit)
t = self.colors.class[class]
elseif Selection then
if Selection == 3 then Selection = UnitPlayerControlled(unit) and 5 or 3 end
t = NP.db.colors.selection[Selection]
elseif element.colorReaction and UnitReaction(unit, 'player') then
local reaction = UnitReaction(unit, 'player')
if reaction <= 3 then reaction = 'bad' elseif reaction == 4 then reaction = 'neutral' else reaction = 'good' end
t = NP.db.colors.reactions[reaction]
elseif element.colorSmooth then
r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
elseif element.colorHealth then
t = NP.db.colors.health
end
if t then
r, g, b = t[1] or t.r, t[2] or t.g, t[3] or t.b
element.r, element.g, element.b = r, g, b -- save these for the style filter to switch back
end
local sf = NP:StyleFilterChanges(self)
if sf.HealthColor then
r, g, b = sf.HealthColor.r, sf.HealthColor.g, sf.HealthColor.b
end
if b then
element:SetStatusBarColor(r, g, b)
if element.bg then
element.bg:SetVertexColor(r * NP.multiplier, g * NP.multiplier, b * NP.multiplier)
end
end
if element.PostUpdateColor then
element:PostUpdateColor(unit, r, g, b)
end
end
function NP:Construct_Health(nameplate)
local Health = CreateFrame('StatusBar', nameplate:GetName()..'Health', nameplate)
Health:SetFrameStrata(nameplate:GetFrameStrata())
Health:SetFrameLevel(5)
Health:CreateBackdrop('Transparent', nil, nil, nil, nil, true)
Health:SetStatusBarTexture(LSM:Fetch('statusbar', NP.db.statusbar))
local clipFrame = CreateFrame('Frame', nil, Health)
clipFrame:SetClipsChildren(true)
clipFrame:SetAllPoints()
clipFrame:EnableMouse(false)
Health.ClipFrame = clipFrame
--[[Health.bg = Health:CreateTexture(nil, 'BACKGROUND')
Health.bg:SetAllPoints()
Health.bg:SetTexture(E.media.blankTex)
Health.bg.multiplier = 0.2]]
NP.StatusBars[Health] = true
local statusBarTexture = Health:GetStatusBarTexture()
local healthFlashTexture = Health:CreateTexture(nameplate:GetName()..'FlashTexture', 'OVERLAY')
healthFlashTexture:SetTexture(LSM:Fetch('background', 'ElvUI Blank'))
healthFlashTexture:Point('BOTTOMLEFT', statusBarTexture, 'BOTTOMLEFT')
healthFlashTexture:Point('TOPRIGHT', statusBarTexture, 'TOPRIGHT')
healthFlashTexture:Hide()
nameplate.HealthFlashTexture = healthFlashTexture
Health.colorTapping = true
Health.colorSelection = true
Health.UpdateColor = NP.Health_UpdateColor
return Health
end
function NP:Update_Health(nameplate, skipUpdate)
local db = NP:PlateDB(nameplate)
nameplate.Health.colorTapping = true
nameplate.Health.colorSelection = true
nameplate.Health.colorClass = db.health.useClassColor
nameplate.Health.considerSelectionInCombatHostile = true
if skipUpdate then return end
if db.health.enable then
if not nameplate:IsElementEnabled('Health') then
nameplate:EnableElement('Health')
end
nameplate.Health:Point('CENTER')
nameplate.Health:Point('LEFT')
nameplate.Health:Point('RIGHT')
nameplate:SetHealthUpdateMethod(E.global.nameplate.effectiveHealth)
nameplate:SetHealthUpdateSpeed(E.global.nameplate.effectiveHealthSpeed)
E:SetSmoothing(nameplate.Health, NP.db.smoothbars)
elseif nameplate:IsElementEnabled('Health') then
nameplate:DisableElement('Health')
end
nameplate.Health.width = db.health.width
nameplate.Health.height = db.health.height
nameplate.Health:Height(db.health.height)
end
local bars = { 'myBar', 'otherBar', 'absorbBar', 'healAbsorbBar' }
function NP:Construct_HealthPrediction(nameplate)
local HealthPrediction = CreateFrame('Frame', nameplate:GetName()..'HealthPrediction', nameplate)
for _, name in ipairs(bars) do
local bar = CreateFrame('StatusBar', nil, nameplate.Health.ClipFrame)
bar:SetFrameStrata(nameplate:GetFrameStrata())
bar:SetStatusBarTexture(LSM:Fetch('statusbar', NP.db.statusbar))
bar:Point('TOP')
bar:Point('BOTTOM')
bar:Width(150)
HealthPrediction[name] = bar
NP.StatusBars[bar] = true
end
local healthTexture = nameplate.Health:GetStatusBarTexture()
local healthFrameLevel = nameplate.Health:GetFrameLevel()
HealthPrediction.myBar:Point('LEFT', healthTexture, 'RIGHT')
HealthPrediction.myBar:SetFrameLevel(healthFrameLevel + 2)
HealthPrediction.myBar:SetStatusBarColor(NP.db.colors.healPrediction.personal.r, NP.db.colors.healPrediction.personal.g, NP.db.colors.healPrediction.personal.b)
HealthPrediction.myBar:SetMinMaxValues(0, 1)
HealthPrediction.otherBar:Point('LEFT', HealthPrediction.myBar:GetStatusBarTexture(), 'RIGHT')
HealthPrediction.otherBar:SetFrameLevel(healthFrameLevel + 1)
HealthPrediction.otherBar:SetStatusBarColor(NP.db.colors.healPrediction.others.r, NP.db.colors.healPrediction.others.g, NP.db.colors.healPrediction.others.b)
HealthPrediction.absorbBar:Point('LEFT', HealthPrediction.otherBar:GetStatusBarTexture(), 'RIGHT')
HealthPrediction.absorbBar:SetFrameLevel(healthFrameLevel)
HealthPrediction.absorbBar:SetStatusBarColor(NP.db.colors.healPrediction.absorbs.r, NP.db.colors.healPrediction.absorbs.g, NP.db.colors.healPrediction.absorbs.b)
HealthPrediction.healAbsorbBar:Point('RIGHT', healthTexture)
HealthPrediction.healAbsorbBar:SetFrameLevel(healthFrameLevel + 3)
HealthPrediction.healAbsorbBar:SetStatusBarColor(NP.db.colors.healPrediction.healAbsorbs.r, NP.db.colors.healPrediction.healAbsorbs.g, NP.db.colors.healPrediction.healAbsorbs.b)
HealthPrediction.healAbsorbBar:SetReverseFill(true)
HealthPrediction.maxOverflow = 1
HealthPrediction.frequentUpdates = true
return HealthPrediction
end
function NP:Update_HealthPrediction(nameplate)
local db = NP:PlateDB(nameplate)
if db.health.enable and db.health.healPrediction then
if not nameplate:IsElementEnabled('HealthPrediction') then
nameplate:EnableElement('HealthPrediction')
end
nameplate.HealthPrediction.myBar:SetStatusBarColor(NP.db.colors.healPrediction.personal.r, NP.db.colors.healPrediction.personal.g, NP.db.colors.healPrediction.personal.b)
nameplate.HealthPrediction.otherBar:SetStatusBarColor(NP.db.colors.healPrediction.others.r, NP.db.colors.healPrediction.others.g, NP.db.colors.healPrediction.others.b)
nameplate.HealthPrediction.absorbBar:SetStatusBarColor(NP.db.colors.healPrediction.absorbs.r, NP.db.colors.healPrediction.absorbs.g, NP.db.colors.healPrediction.absorbs.b)
nameplate.HealthPrediction.healAbsorbBar:SetStatusBarColor(NP.db.colors.healPrediction.healAbsorbs.r, NP.db.colors.healPrediction.healAbsorbs.g, NP.db.colors.healPrediction.healAbsorbs.b)
elseif nameplate:IsElementEnabled('HealthPrediction') then
nameplate:DisableElement('HealthPrediction')
end
end

Some files were not shown because too many files have changed in this diff Show More