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

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