ShadowTheAge@0: CrossRealmAssist = LibStub("AceAddon-3.0"):NewAddon("CrossRealmAssist", "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0") ShadowTheAge@0: local addon = CrossRealmAssist; ShadowTheAge@0: local wholib = LibStub:GetLibrary('LibWho-2.0'):Library() ShadowTheAge@32: local realmInfo = LibStub:GetLibrary('LibRealmInfo') ShadowTheAge@12: local ScrollingTable = LibStub("ScrollingTable"); ShadowTheAge@13: local ldb = LibStub("LibDataBroker-1.1") ShadowTheAge@13: local minimapIcon = LibStub("LibDBIcon-1.0") ShadowTheAge@13: local db ShadowTheAge@0: ShadowTheAge@13: local homeRealm, realmSep, gui, btRefresh, btSettings, btQuick, btManual, lbRealm, lbStatus, playerName, lfgui, lfgTabSelected, lfgTable, lbThrottle, curLfgGroup, sheduledScan, wasInGroup, inInstance ShadowTheAge@13: local settingsMenu ShadowTheAge@13: local hintShown ShadowTheAge@32: local btFilterCount, cbHideNoAutoinv, edFilterText ShadowTheAge@0: ShadowTheAge@12: local tabs = {} ShadowTheAge@27: local curRealmStat ShadowTheAge@0: local scanstate=0 ShadowTheAge@0: local recentRealms={} ShadowTheAge@12: local recentgroups={} ShadowTheAge@13: local autoScanGroups={} ShadowTheAge@0: local active=false ShadowTheAge@21: local allLanguageTable={} ShadowTheAge@32: local extraColumns ShadowTheAge@32: local tableTemplate ShadowTheAge@32: local filterString ShadowTheAge@32: local filterByCountId=1 ShadowTheAge@0: ShadowTheAge@32: addon.lfgGroups={ ShadowTheAge@0: 6, -- Custom ShadowTheAge@0: 10, -- Ashran ShadowTheAge@0: 1, -- Quests ShadowTheAge@13: 3, -- Raids ShadowTheAge@13: 8 -- BGs ShadowTheAge@0: } ShadowTheAge@0: ShadowTheAge@12: local StatusTable = { ShadowTheAge@12: ["invited"]="Invited", ShadowTheAge@12: ["declined"]="Declined", ShadowTheAge@12: ["timedout"]="Timed out", ShadowTheAge@12: ["applied"]="Applied", ShadowTheAge@12: ["cancelled"]="Join cancelled", ShadowTheAge@12: ["inviteaccepted"]="Joined", ShadowTheAge@13: ["_init"]="Join request", ShadowTheAge@13: ["_skip"]="Skipped" ShadowTheAge@12: } ShadowTheAge@13: local DefaultWidgetPos = {x=0, y=200, to="CENTER"} ShadowTheAge@13: local SettingsDefaults={ ShadowTheAge@13: global={ ShadowTheAge@13: minimap = {}, ShadowTheAge@13: widgetPos=DefaultWidgetPos, ShadowTheAge@13: quickJoinHint = true, ShadowTheAge@27: quickJoin={[6]=1}, ShadowTheAge@27: allLanguages = true, ShadowTheAge@32: stoplist = {"no hop","nohop","no realm","kick"}, ShadowTheAge@32: priorityList = {"realm hop","realmhop","garrison"}, ShadowTheAge@32: lfgPanelScale = 1.0, uiScale = 1.0, listItemCount=15, ShadowTheAge@32: extraColumns = {} ShadowTheAge@13: } ShadowTheAge@13: } ShadowTheAge@32: local filterByCountList = { ShadowTheAge@32: {text="Any number of players",min=1,max=40}, ShadowTheAge@32: {text="Groups (1-5)",min=1,max=5}, ShadowTheAge@32: {text="Raids (6-40)",min=6,max=40}, ShadowTheAge@32: {text="Non-full groups (1-4)",min=1,max=4}, ShadowTheAge@32: {text="Non-full raids (6-35)",min=6,max=35} ShadowTheAge@32: } ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: -- Utils functions ShadowTheAge@12: ShadowTheAge@32: ShadowTheAge@32: local function searchInList(name, list) ShadowTheAge@32: if list and name then ShadowTheAge@32: local lname = string.lower(name); ShadowTheAge@32: for i=1, #list do ShadowTheAge@32: if string.find(lname, list[i], 1, true) then return true end ShadowTheAge@32: end ShadowTheAge@32: end ShadowTheAge@32: return false; ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@12: local function PlayerName(fullname) ShadowTheAge@12: fullname = fullname or "???-???" ShadowTheAge@12: local name, realm = strsplit(realmSep, fullname) ShadowTheAge@12: realm = realm or homeRealm; ShadowTheAge@12: return name, realm; ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: local function canJoinGroup() ShadowTheAge@12: return (not IsInGroup()) or (UnitIsGroupLeader('player') and not IsInRaid()) ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@32: local function sortByTypeAndName(a,b) ShadowTheAge@32: if a.type == b.type then ShadowTheAge@32: return a.name < b.name ShadowTheAge@32: else ShadowTheAge@32: return a.type < b.type; ShadowTheAge@32: end ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: -- UI functions ShadowTheAge@12: ShadowTheAge@12: local function createIcon(owner, icon, id) ShadowTheAge@12: local image = owner:CreateTexture(nil, "BACKGROUND") ShadowTheAge@12: image:SetWidth(16) ShadowTheAge@12: image:SetHeight(16) ShadowTheAge@12: image:SetTexture(icon) ShadowTheAge@12: image:SetPoint("TOPLEFT",owner,"TOPLEFT",id*16,0) ShadowTheAge@12: return image ShadowTheAge@12: end ShadowTheAge@0: ShadowTheAge@11: local function setupWidget(widget, parameters, x, y) ShadowTheAge@11: if parameters then ShadowTheAge@11: for key,value in pairs(parameters) do widget[key](widget,value) end ShadowTheAge@11: end ShadowTheAge@11: if y then ShadowTheAge@11: widget:SetPoint("TOPLEFT",widget:GetParent(),"TOPLEFT",x,-y) ShadowTheAge@11: end ShadowTheAge@11: return widget ShadowTheAge@11: end ShadowTheAge@11: ShadowTheAge@11: local function ShowTooltip(widget) ShadowTheAge@11: GameTooltip:SetOwner(widget, widget.TooltipAnchor) ShadowTheAge@11: GameTooltip:ClearLines() ShadowTheAge@11: widget:TooltipFactory() ShadowTheAge@11: GameTooltip:Show() ShadowTheAge@11: end ShadowTheAge@11: ShadowTheAge@11: local function HideTooltip(widget) ShadowTheAge@11: GameTooltip:Hide() ShadowTheAge@11: end ShadowTheAge@11: ShadowTheAge@11: local function setupTooltip(widget, anchor, factory) ShadowTheAge@11: widget.TooltipAnchor = anchor; ShadowTheAge@11: widget.TooltipFactory = factory; ShadowTheAge@11: widget:SetScript("OnEnter", ShowTooltip) ShadowTheAge@11: widget:SetScript("OnLeave", HideTooltip) ShadowTheAge@11: end ShadowTheAge@11: ShadowTheAge@13: local function TabClick(tab) ShadowTheAge@13: if tab == lfgTabSelected then return end ShadowTheAge@13: addon.LfgScan(tab.searchID) ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@13: local function changeTab(tab) ShadowTheAge@12: PanelTemplates_DeselectTab(lfgTabSelected) ShadowTheAge@12: lfgTabSelected = tab ShadowTheAge@12: PanelTemplates_SelectTab(lfgTabSelected) ShadowTheAge@12: end ShadowTheAge@0: ShadowTheAge@12: local function realmToolip() ShadowTheAge@12: if not curRealmStat then return end ShadowTheAge@12: local players = curRealmStat.players; ShadowTheAge@12: local threshold = curRealmStat.threshold ShadowTheAge@12: GameTooltip:AddLine("Players in zone: "..players) ShadowTheAge@12: if not curRealmStat.complete then ShadowTheAge@12: GameTooltip:AppendText("+") ShadowTheAge@12: end ShadowTheAge@12: for i=1,curRealmStat.realms do ShadowTheAge@12: local data = curRealmStat[i] ShadowTheAge@12: local percent = math.ceil(100 * data.count / players - 0.5) .. "%"; ShadowTheAge@12: if data.count >= threshold then ShadowTheAge@12: GameTooltip:AddDoubleLine(data.realm, percent, 0,1,0,0,1,0) ShadowTheAge@12: else ShadowTheAge@12: GameTooltip:AddDoubleLine(data.realm, percent, 0.5,0.5,0.5,0.5,0.5,0.5) ShadowTheAge@12: end ShadowTheAge@12: end ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@13: local function ClearRealmHistory() ShadowTheAge@13: recentRealms = {} ShadowTheAge@13: addon:updateCurrentRealm() ShadowTheAge@13: if lfgTable then lfgTable:Refresh() end ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: -- LFG list data providers, filters and tooltips ShadowTheAge@12: ShadowTheAge@12: local lfgScanInProgress=false ShadowTheAge@12: local hasLfgListChanges=false ShadowTheAge@12: ShadowTheAge@12: local function addTooltipLineIcon(predicat, text, icon, r, g, b, wrap) ShadowTheAge@12: if predicat then ShadowTheAge@12: GameTooltip:AddLine(text, r, g, b, wrap) ShadowTheAge@12: if icon then GameTooltip:AddTexture(icon) end ShadowTheAge@12: end ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@32: local function getJoinedAgo(name) ShadowTheAge@32: if recentgroups[name] then ShadowTheAge@32: return GetTime() - recentgroups[name].time ShadowTheAge@32: end ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@12: local function WeightLfgItem(id, forAutoJoin) ShadowTheAge@38: local _, action, caption, desc, voice, ilvl, unk1, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(id) ShadowTheAge@12: if delisted then return 0 end ShadowTheAge@12: local name,realm = PlayerName(fullname); ShadowTheAge@32: local ldesc = caption .. "|" .. desc; ShadowTheAge@32: if searchInList(ldesc, db.global.stoplist) then return 0 end ShadowTheAge@32: local isHopGroup = searchInList(ldesc, db.global.priorityList); ShadowTheAge@12: if forAutoJoin then ShadowTheAge@27: if not autoinv or recentgroups[fullname] or (not isHopGroup and (pcount >= 35 or pcount <= 5)) then return 0 end ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: local autoinvWeight = autoinv and 5 or 2 ShadowTheAge@29: local hopCoef = isHopGroup and 3 or 1 ShadowTheAge@12: ShadowTheAge@12: local visCoef = 1 ShadowTheAge@12: if recentgroups[fullname] then ShadowTheAge@32: local ago = getJoinedAgo(fullname) ShadowTheAge@12: visCoef = math.min(1,ago/600) ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: local leaderRealm = 3 -- recently visited realms ShadowTheAge@13: local realmVis = recentRealms[realm] ShadowTheAge@13: local leaderRealm = 3; ShadowTheAge@13: if realmVis then ShadowTheAge@13: local ago = GetTime() - realmVis ShadowTheAge@13: leaderRealm = 1 + 2*math.min(1,ago/600); ShadowTheAge@13: end ShadowTheAge@12: ShadowTheAge@12: local countWeight = 4 -- count weight ShadowTheAge@29: if not isHopGroup then ShadowTheAge@29: if pcount >= 39 or pcount <= 1 then countWeight = 1 ShadowTheAge@29: elseif pcount >= 35 or pcount <= 5 then countWeight = 2 ShadowTheAge@29: elseif pcount >= 30 or pcount <= 10 then countWeight = 3 end ShadowTheAge@27: end ShadowTheAge@12: ShadowTheAge@12: local ageWeight = 2 ShadowTheAge@12: if time > 1200 then ageWeight = 4 ShadowTheAge@12: elseif time > 300 then ageWeight = 3 end ShadowTheAge@12: ShadowTheAge@27: return leaderRealm * countWeight * visCoef * autoinvWeight * ageWeight * hopCoef; ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@13: local function AddLfgGroupInfo(id, short) ShadowTheAge@38: local _, action, caption, desc, voice, ilvl, unk1, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(id) ShadowTheAge@12: local friends = bnetfr+charfr+guild ShadowTheAge@12: GameTooltip:ClearLines() ShadowTheAge@12: GameTooltip:AddLine(caption,1,1,1) ShadowTheAge@12: addTooltipLineIcon(desc ~= "", desc, nil, 0.5, 0.5, 0.5, true) ShadowTheAge@12: local name, realm = PlayerName(fullname) ShadowTheAge@13: GameTooltip:AddDoubleLine("Players:",pcount) ShadowTheAge@12: GameTooltip:AddDoubleLine("Leader:",name) ShadowTheAge@12: GameTooltip:AddDoubleLine("Leader realm:",realm) ShadowTheAge@13: if recentRealms[realm] then ShadowTheAge@13: local ago = GetTime() - recentRealms[realm] ShadowTheAge@13: GameTooltip:AddDoubleLine("Realm visited",SecondsToTime(ago, false, false, 1, false).." ago",1,0.5,0,1,0.5,0) ShadowTheAge@13: else ShadowTheAge@13: GameTooltip:AddDoubleLine(" ","Realm not visited!",0,0,0,0,1,0) ShadowTheAge@13: end ShadowTheAge@13: if not short then ShadowTheAge@13: addTooltipLineIcon(ilvl > 0, "Min. ilvl: "..ilvl, READY_CHECK_WAITING_TEXTURE, 1, 1, 0) ShadowTheAge@13: addTooltipLineIcon(voice ~= "", "Voice: "..voice, READY_CHECK_WAITING_TEXTURE, 1, 1, 0) ShadowTheAge@13: addTooltipLineIcon(friends > 0, "Friends: "..friends, READY_CHECK_WAITING_TEXTURE, 1, 1, 0) ShadowTheAge@32: addTooltipLineIcon(autoinv, "Autoaccept!", READY_CHECK_READY_TEXTURE, 0, 1, 0) ShadowTheAge@13: local visitinfo = recentgroups[fullname] ShadowTheAge@13: if visitinfo then ShadowTheAge@13: local ago = GetTime() - visitinfo.time; ShadowTheAge@13: GameTooltip:AddDoubleLine(StatusTable[visitinfo.status] or visitinfo.status,SecondsToTime(ago, false, false, 1, false).." ago",1,0,0,1,0,0) ShadowTheAge@13: GameTooltip:AddTexture(READY_CHECK_NOT_READY_TEXTURE) ShadowTheAge@13: end ShadowTheAge@12: end ShadowTheAge@12: GameTooltip:Show() ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@13: local function ShowLfgInfo(rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...) ShadowTheAge@13: if not realrow then return end ShadowTheAge@13: local rowdata = scrollingTable:GetRow(realrow); ShadowTheAge@13: GameTooltip:SetOwner(rowFrame, "ANCHOR_BOTTOMLEFT",-10,25) ShadowTheAge@13: AddLfgGroupInfo(rowdata.id); ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@12: local function updateTableData(rowFrame, cellFrame, data, cols, row, realrow, column, fShow, table, ...) ShadowTheAge@12: if fShow then ShadowTheAge@12: local rowdata = table:GetRow(realrow); ShadowTheAge@12: local icons = cellFrame.icons ShadowTheAge@38: local _, action, caption, desc, voice, ilvl, unk1, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(rowdata.id) ShadowTheAge@12: if not icons then ShadowTheAge@12: local miscdata = createIcon(cellFrame,READY_CHECK_WAITING_TEXTURE,0) ShadowTheAge@12: local autoinv = createIcon(cellFrame,READY_CHECK_READY_TEXTURE, 1) ShadowTheAge@12: local visited = createIcon(cellFrame,READY_CHECK_NOT_READY_TEXTURE, 2) ShadowTheAge@12: icons = {misc=miscdata, autoinv=autoinv, visited=visited} ShadowTheAge@12: cellFrame.icons = icons ShadowTheAge@12: end ShadowTheAge@12: icons.misc:SetShown(voice ~= "" or bnetfr > 0 or charfr > 0 or guild > 0 or ilvl > 0) ShadowTheAge@12: icons.autoinv:SetShown(autoinv) ShadowTheAge@12: icons.visited:SetShown(recentgroups[fullname]) ShadowTheAge@12: if GameTooltip:GetOwner() == rowFrame then ShowLfgInfo(rowFrame, cellFrame, data, cols, row, realrow, column, table) end ShadowTheAge@12: end ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: local function updateGroupName(id) ShadowTheAge@12: return select(3, C_LFGList.GetSearchResultInfo(id)) ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@32: local function updateRealmType(id) ShadowTheAge@38: local name = select(13, C_LFGList.GetSearchResultInfo(id)) ShadowTheAge@32: local pname, realm = PlayerName(name); ShadowTheAge@32: return select(4, realmInfo:GetRealmInfo(realm)) or "???" ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@32: local function updateGroupAge(id) ShadowTheAge@38: local age = select(8, C_LFGList.GetSearchResultInfo(id)) ShadowTheAge@32: return SecondsToTime(age, false, false, 1, false) ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@32: local function sortBase(col, value) ShadowTheAge@32: local column = lfgTable.cols[col]; ShadowTheAge@32: local direction = column.sort or column.defaultsort or "asc" ShadowTheAge@32: if direction == "asc" then ShadowTheAge@32: return value ShadowTheAge@32: else ShadowTheAge@32: return not value; ShadowTheAge@32: end ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@32: ShadowTheAge@32: local function sortByAge(self, rowa, rowb, sortbycol) ShadowTheAge@32: if rowa == nil or rowb == nil then return false end; -- wtf ScrollingTable??? ShadowTheAge@32: local row1 = lfgTable:GetRow(rowa); ShadowTheAge@32: local row2 = lfgTable:GetRow(rowb); ShadowTheAge@38: local age1 = select(8, C_LFGList.GetSearchResultInfo(row1.id)); ShadowTheAge@38: local age2 = select(8, C_LFGList.GetSearchResultInfo(row2.id)); ShadowTheAge@32: return sortBase(sortbycol, age1 row2.weight; ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@12: local function updateGroupCount(id) ShadowTheAge@38: return select(14, C_LFGList.GetSearchResultInfo(id)) ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: local function updateGroupRealm(id) ShadowTheAge@38: local name = select(13, C_LFGList.GetSearchResultInfo(id)) ShadowTheAge@12: local pname, realm = PlayerName(name); ShadowTheAge@32: return realm; ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@13: local COLOR_YELLOW = {r=1,g=1,b=0,a=1} ShadowTheAge@32: local COLOR_WHITE = {r=1,g=1,b=1,a=1} ShadowTheAge@13: local COLOR_GREEN = {r=0,g=1,b=0,a=1} ShadowTheAge@32: local COLOR_RED = {r=1,g=0,b=0,a=1} ShadowTheAge@32: local COLOR_GREY = {r=0.5,g=0.5,b=0.5,a=1} ShadowTheAge@13: local function updateRealmColor(id) ShadowTheAge@38: local name = select(13, C_LFGList.GetSearchResultInfo(id)) ShadowTheAge@13: local pname, realm = PlayerName(name); ShadowTheAge@13: return recentRealms[realm] and COLOR_YELLOW or COLOR_GREEN; ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@32: local function updateNameColor(id) ShadowTheAge@32: local name = select(3, C_LFGList.GetSearchResultInfo(id)) ShadowTheAge@32: if searchInList(name, db.global.highlightList) then return COLOR_GREEN end; ShadowTheAge@32: if searchInList(name, db.global.stoplist) then return COLOR_GREY end; ShadowTheAge@32: if searchInList(name, db.global.priorityList) then return COLOR_YELLOW end; ShadowTheAge@32: return COLOR_WHITE; ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@12: local function filterTable(self, row) ShadowTheAge@38: local _, _, caption, desc, _, _, _, _, _, _, _, delisted, _, pcount, autoinv = C_LFGList.GetSearchResultInfo(row.id) ShadowTheAge@25: if delisted then return false end; ShadowTheAge@32: if filterByCountId > 1 then ShadowTheAge@32: local fobj = filterByCountList[filterByCountId]; ShadowTheAge@32: if pcount < fobj.min or pcount > fobj.max then return false end; ShadowTheAge@32: end ShadowTheAge@25: if not autoinv and cbHideNoAutoinv:GetChecked() then return false end; ShadowTheAge@32: if filterString then ShadowTheAge@32: caption = string.lower(caption); ShadowTheAge@32: desc = string.lower(desc); ShadowTheAge@32: if not (string.find(caption, filterString, 1, true) or string.find(desc, filterString, 1, true))then return false end ShadowTheAge@32: end ShadowTheAge@25: return true; ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: function addon:UpdateResponseData(event, result) ShadowTheAge@13: if not lfgTable then return end ShadowTheAge@38: if select(12, C_LFGList.GetSearchResultInfo(result)) then ShadowTheAge@12: lfgTable:SetFilter(filterTable) ShadowTheAge@12: end ShadowTheAge@12: hasLfgListChanges = true ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: local function refreshLFGList() ShadowTheAge@12: if lfgScanInProgress or not lfgTable then return end ShadowTheAge@12: local count, list = C_LFGList.GetSearchResults() ShadowTheAge@12: local tableData = {} ShadowTheAge@32: local extraColumnId = 4; ShadowTheAge@32: ShadowTheAge@12: for i = 1,count do ShadowTheAge@12: local rid = list[i]; ShadowTheAge@12: if not rid then break end ShadowTheAge@12: local data = list[i]; ShadowTheAge@12: local cols = {} ShadowTheAge@12: local row = {rid} ShadowTheAge@32: for i=1, #tableTemplate do ShadowTheAge@32: local item = tableTemplate[i]; ShadowTheAge@32: local cell = {value=item.value, args=row } ShadowTheAge@32: if item.color then ShadowTheAge@32: cell.color = item.color; ShadowTheAge@32: cell.colorargs = row; ShadowTheAge@32: end ShadowTheAge@32: cols[i] = cell ShadowTheAge@32: end ShadowTheAge@12: table.insert(tableData, {cols=cols,id=rid,weight=WeightLfgItem(rid)}) ShadowTheAge@12: end ShadowTheAge@12: lfgTable:SetData(tableData) ShadowTheAge@21: if #tableData == 0 then ShadowTheAge@21: lbThrottle:SetText("No groups found") ShadowTheAge@21: end ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@13: local function JoinGroup(rid) ShadowTheAge@13: local tank, heal, dd = C_LFGList.GetAvailableRoles() ShadowTheAge@25: local noHealTank = not db.global.applyAsDD; ShadowTheAge@13: addon:SetGroupJoinStatus(rid, "_init") ShadowTheAge@25: C_LFGList.ApplyToGroup(rid, "", tank and noHealTank, heal and noHealTank, dd) ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@13: local function TableCellClick(rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...) ShadowTheAge@32: if not realrow then return end ShadowTheAge@12: local rowdata = scrollingTable:GetRow(realrow); ShadowTheAge@32: if canJoinGroup() then ShadowTheAge@32: JoinGroup(rowdata.id) ShadowTheAge@32: else ShadowTheAge@32: LeaveParty() ShadowTheAge@32: end ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: -- Addon functions and gui constructors ShadowTheAge@12: ShadowTheAge@13: function addon.ShowMmTooltip(tooltip) ShadowTheAge@13: tooltip:AddLine("Cross Realm Assist",1,1,1) ShadowTheAge@13: tooltip:Show() ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@13: function addon:OnInitialize() ShadowTheAge@13: db = LibStub("AceDB-3.0"):New("CrossRealmAssistDB", SettingsDefaults) ShadowTheAge@32: addon.db = db; ShadowTheAge@13: local minimapData = ldb:NewDataObject("CrossRealmAssistMinimapIcon",{ ShadowTheAge@13: type = "data source", ShadowTheAge@13: text = "Cross Realm Assist", ShadowTheAge@13: icon = "Interface/Icons/INV_Misc_GroupNeedMore", ShadowTheAge@13: OnClick = addon.Activate, ShadowTheAge@13: OnTooltipShow = addon.ShowMmTooltip ShadowTheAge@13: }) ShadowTheAge@13: minimapIcon:Register("CrossRealmAssistMinimapIcon", minimapData, db.global.minimap) ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@0: function addon:OnEnable() ShadowTheAge@0: realmSep = _G.REALM_SEPARATORS ShadowTheAge@11: playerName = UnitName("player") ShadowTheAge@0: homeRealm = GetRealmName() ShadowTheAge@0: addon:RegisterChatCommand("cra", "Activate") ShadowTheAge@0: addon:RegisterChatCommand("crossrealmassist", "Activate") ShadowTheAge@29: if db.global.autoCreateHopGroup then ShadowTheAge@29: addon:RegisterEvent("PLAYER_FLAGS_CHANGED", "PlayerFlagsUpdate") ShadowTheAge@29: end ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:OnDisable() ShadowTheAge@0: addon:Deactivate() ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:Activate() ShadowTheAge@0: if active then return end ShadowTheAge@0: active=true ShadowTheAge@0: wasInGroup = IsInGroup() ShadowTheAge@11: if not gui then addon:CreateUI() end ShadowTheAge@11: addon:updateCurrentRealm(); ShadowTheAge@13: addon:RefreshZoneAndClearHistory(); ShadowTheAge@11: gui:Show() ShadowTheAge@13: addon:RegisterEvent("ZONE_CHANGED_NEW_AREA", "RefreshZoneAndClearHistory") ShadowTheAge@13: addon:RegisterEvent("SCENARIO_UPDATE", "RefreshZoneAndClearHistory") ShadowTheAge@12: addon:RegisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED", "LfgResponseData") ShadowTheAge@12: addon:RegisterEvent("LFG_LIST_SEARCH_RESULT_UPDATED", "UpdateResponseData") ShadowTheAge@12: addon:RegisterEvent("LFG_LIST_SEARCH_FAILED", "LfgScanFailed") ShadowTheAge@12: addon:RegisterEvent("GROUP_ROSTER_UPDATE", "updatePartyInfo") ShadowTheAge@12: addon:RegisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED", "updateAppStatus") ShadowTheAge@13: addon.LfgScan(addon.GetNextAutoScanCategory() or 1) ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:Deactivate() ShadowTheAge@0: if not active then return end ShadowTheAge@0: active = false ShadowTheAge@12: gui:Hide() ShadowTheAge@12: if lfgui then lfgui:Hide() end ShadowTheAge@0: scanstate = 0 ShadowTheAge@0: lfgScanInProgress = false ShadowTheAge@0: addon:UnregisterEvent("ZONE_CHANGED_NEW_AREA") ShadowTheAge@17: addon:UnregisterEvent("SCENARIO_UPDATE") ShadowTheAge@0: addon:UnregisterEvent("PLAYER_REGEN_ENABLED") ShadowTheAge@0: addon:UnregisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED") ShadowTheAge@12: addon:UnregisterEvent("LFG_LIST_SEARCH_RESULT_UPDATED") ShadowTheAge@0: addon:UnregisterEvent("LFG_LIST_SEARCH_FAILED") ShadowTheAge@0: addon:UnregisterEvent("GROUP_ROSTER_UPDATE") ShadowTheAge@0: addon:UnregisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED") ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@11: function addon:SetStatus(status) ShadowTheAge@11: if status then ShadowTheAge@11: lbStatus:SetText(status) ShadowTheAge@11: else ShadowTheAge@13: lbStatus:SetText("") ShadowTheAge@11: end ShadowTheAge@11: end ShadowTheAge@11: ShadowTheAge@13: local function stopMovingWidget() ShadowTheAge@13: gui:StopMovingOrSizing() ShadowTheAge@13: local point,_,_,x,y = gui:GetPoint(1); ShadowTheAge@13: db.global.widgetPos = {x=x,y=y,to=point} ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@0: function addon:CreateUI() ShadowTheAge@32: local scale = db.global.uiScale or 1.0; ShadowTheAge@32: gui = setupWidget(CreateFrame("Frame","CrossRealmAssistMainUI",nil,"InsetFrameTemplate3"), {SetFrameStrata="LOW",SetWidth=208,SetHeight=60,EnableMouse=true,SetMovable=true,SetClampedToScreen=true,SetScale=scale}) ShadowTheAge@11: local title = setupWidget(CreateFrame("Frame",nil,gui), {SetWidth=190,SetHeight=18,EnableMouse=true,RegisterForDrag="LeftButton"}, 0, 6); ShadowTheAge@11: title:SetScript("OnDragStart", function() gui:StartMoving() end) ShadowTheAge@13: title:SetScript("OnDragStop", stopMovingWidget) ShadowTheAge@11: gui:SetScript("OnHide", addon.Deactivate) ShadowTheAge@12: setupTooltip(title, "ANCHOR_TOP", realmToolip) ShadowTheAge@11: ShadowTheAge@11: lbRealm = setupWidget(gui:CreateFontString(nil,"BACKGROUND", "GameFontNormal"), {SetWidth=200,SetHeight=18}, 0, 6) ShadowTheAge@11: lbStatus = setupWidget(gui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmallLeft"), {SetWidth=200,SetHeight=10}, 6, 23) ShadowTheAge@11: ShadowTheAge@12: btQuick = setupWidget(CreateFrame("Button",nil,gui,"UIMenuButtonStretchTemplate"),{SetWidth=90,SetHeight=20,SetText="Quick join"},4,36) ShadowTheAge@13: btQuick:RegisterForClicks("RightButtonUp","LeftButtonUp") ShadowTheAge@12: btQuick:SetScript("OnClick",addon.DoAutoAction) ShadowTheAge@13: setupTooltip(btQuick, "ANCHOR_BOTTOM", addon.actionTooltip) ShadowTheAge@12: btManual = setupWidget(CreateFrame("Button",nil,gui,"UIMenuButtonStretchTemplate"),{SetWidth=90,SetHeight=20,SetText="Manual join"},94,36) ShadowTheAge@12: btManual:SetScript("OnClick",addon.ShowManualLfg) ShadowTheAge@11: setupWidget(CreateFrame("Button",nil,gui,"UIPanelCloseButton"),{EnableMouse=true,SetWidth=20,SetHeight=20},188,0) ShadowTheAge@11: ShadowTheAge@13: btRefresh = setupWidget(CreateFrame("Button",nil,gui,"UIPanelSquareButton"),{SetWidth=20,SetHeight=20},184,16) ShadowTheAge@11: btRefresh.icon:SetTexture("Interface/BUTTONS/UI-RefreshButton") ShadowTheAge@11: btRefresh.icon:SetTexCoord(0,1,0,1); ShadowTheAge@11: btRefresh:SetScript("OnClick",addon.RefreshZone) ShadowTheAge@11: ShadowTheAge@13: btSettings = setupWidget(CreateFrame("Button",nil,gui,"UIPanelSquareButton"),{SetWidth=20,SetHeight=20},184,36) ShadowTheAge@13: btSettings.icon:SetTexture("Interface/Worldmap/Gear_64Grey") ShadowTheAge@13: btSettings.icon:SetTexCoord(0.1,0.9,0.1,0.9); ShadowTheAge@13: btSettings:SetScript("OnClick",addon.ShowSettings) ShadowTheAge@13: ShadowTheAge@13: local savedPos = db.global.widgetPos ShadowTheAge@13: gui:SetPoint(savedPos.to,savedPos.x,savedPos.y) ShadowTheAge@12: addon:UpdateAutoButtonStatus() ShadowTheAge@21: ShadowTheAge@21: local languages = C_LFGList.GetAvailableLanguageSearchFilter() ShadowTheAge@21: for i=1,#languages do ShadowTheAge@21: allLanguageTable[languages[i]] = true; ShadowTheAge@21: end ShadowTheAge@12: end ShadowTheAge@11: ShadowTheAge@12: function addon:ShowManualLfg() ShadowTheAge@12: if not lfgui then addon:CreateLFGUI() end ShadowTheAge@12: lfgui:Show() ShadowTheAge@12: end ShadowTheAge@0: ShadowTheAge@12: function addon.lfgUpdate() ShadowTheAge@12: if hasLfgListChanges then ShadowTheAge@12: lfgTable:Refresh() ShadowTheAge@12: hasLfgListChanges = false ShadowTheAge@12: end ShadowTheAge@12: end ShadowTheAge@0: ShadowTheAge@25: function addon.refreshList() ShadowTheAge@25: lfgTable:SetFilter(filterTable) ShadowTheAge@25: end ShadowTheAge@25: ShadowTheAge@32: local function updateFilter(self) ShadowTheAge@32: SearchBoxTemplate_OnTextChanged(self) ShadowTheAge@32: filterString = string.lower(edFilterText:GetText()); ShadowTheAge@32: if filterString == "" then filterString = nil end; ShadowTheAge@32: addon.refreshList() ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@32: local function updateFilterByCount(btn, arg1, arg2, checked) ShadowTheAge@32: filterByCountId = arg1; ShadowTheAge@32: local filterObj = filterByCountList[arg1]; ShadowTheAge@32: UIDropDownMenu_SetText(btFilterCount, "Count: "..filterObj.min.."-"..filterObj.max); ShadowTheAge@32: addon.refreshList() ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@32: local function numberFilter(self, level, menuList) ShadowTheAge@32: for i=1,#filterByCountList do ShadowTheAge@32: UIDropDownMenu_AddButton({text=filterByCountList[i].text, arg1=i,checked=(i==filterByCountId), func=updateFilterByCount}, level) ShadowTheAge@32: end ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@40: local function setHighlightColorMy(self, frame, color) ShadowTheAge@40: if not frame.highlight then ShadowTheAge@40: frame.highlight = frame:CreateTexture(nil, "OVERLAY"); ShadowTheAge@40: frame.highlight:SetAllPoints(frame); ShadowTheAge@40: end ShadowTheAge@40: frame.highlight:SetColorTexture(color.r, color.g, color.b, color.a); ShadowTheAge@40: end ShadowTheAge@40: ShadowTheAge@12: function addon:CreateLFGUI() ShadowTheAge@32: local scale = db.global.lfgPanelScale or 1.0; ShadowTheAge@32: local itemCount = db.global.listItemCount; ShadowTheAge@32: local shift = itemCount * 16; ShadowTheAge@32: ShadowTheAge@32: tableTemplate = { ShadowTheAge@32: {name="Title",width=160, value = updateGroupName, color = updateNameColor}, ShadowTheAge@32: {name="#",width=30,align="CENTER",value = updateGroupCount}, ShadowTheAge@32: {name="Realm",width=120,align="RIGHT",value = updateGroupRealm, color = updateRealmColor} ShadowTheAge@32: } ShadowTheAge@32: ShadowTheAge@32: extraColumns = db.global.extraColumns; ShadowTheAge@32: if extraColumns.rtype then table.insert(tableTemplate, {name="Type",width=40,align="CENTER", value = updateRealmType}) end; ShadowTheAge@32: if extraColumns.groupAge then table.insert(tableTemplate, {name="Age",width=45,align="CENTER",comparesort=sortByAge, value = updateGroupAge}) end; ShadowTheAge@32: if extraColumns.joinTime then table.insert(tableTemplate, {name="Joined",width=45,align="CENTER",comparesort=sortByJoinAge, value = updateJoinAge}) end; ShadowTheAge@32: table.insert(tableTemplate, {name="Misc",width=50,DoCellUpdate=updateTableData,comparesort=sortByScore,align="RIGHT",sort="asc"}) ShadowTheAge@32: ShadowTheAge@32: local tableWidth = 0; ShadowTheAge@32: for i=1,#tableTemplate do ShadowTheAge@32: tableWidth = tableWidth + tableTemplate[i].width; ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@32: ShadowTheAge@33: lfgui = setupWidget(CreateFrame("Frame","CrossRealmAssistJoinUI",nil,"UIPanelDialogTemplate"), {SetFrameStrata="HIGH",SetWidth=tableWidth+45,SetHeight=shift+95,EnableMouse=true,SetMovable=true,SetScale=scale}) ShadowTheAge@45: lfgui.Title:SetText("Click to join group"); ShadowTheAge@42: local dragRect = setupWidget(CreateFrame("Frame",nil,lfgui), {EnableMouse=true,RegisterForDrag="LeftButton"}, 0, 6); ShadowTheAge@45: dragRect:SetAllPoints(lfgui.Title) ShadowTheAge@42: dragRect:SetScript("OnDragStart", function() lfgui:StartMoving() end) ShadowTheAge@42: dragRect:SetScript("OnDragStop", function() lfgui:StopMovingOrSizing() end) ShadowTheAge@12: lfgui:SetScript("OnUpdate",addon.lfgUpdate) ShadowTheAge@12: addon:CreateTabs() ShadowTheAge@0: ShadowTheAge@32: lfgTable = ScrollingTable:CreateST(tableTemplate,itemCount,16,nil,lfgui); ShadowTheAge@40: lfgTable.SetHighLightColor = setHighlightColorMy; -- work around API changes in 7.0 (SetTexture -> SetColorTexture) ShadowTheAge@0: ShadowTheAge@13: lfgTable:RegisterEvents({OnEnter=ShowLfgInfo,OnLeave=HideTooltip,OnClick=TableCellClick}) ShadowTheAge@0: ShadowTheAge@12: setupWidget(lfgTable.frame, nil, 10, 45); ShadowTheAge@12: lfgTable.frame:SetBackdrop(nil) ShadowTheAge@12: lfgui:SetPoint("CENTER",0,0) ShadowTheAge@12: refreshLFGList() ShadowTheAge@0: ShadowTheAge@32: lbThrottle = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetWidth=tableWidth}, 0, 100) ShadowTheAge@12: lbThrottle:Hide(); ShadowTheAge@0: ShadowTheAge@32: local btRefresh = setupWidget(CreateFrame("Button",nil,lfgui,"UIPanelSquareButton"),{SetWidth=22,SetHeight=22},tableWidth+19,27) ShadowTheAge@12: btRefresh.icon:SetTexture("Interface/BUTTONS/UI-RefreshButton") ShadowTheAge@12: btRefresh.icon:SetTexCoord(0,1,0,1); ShadowTheAge@12: btRefresh:SetScript("OnClick",addon.refreshLfgCurrent) ShadowTheAge@25: ShadowTheAge@32: setupWidget(CreateFrame("Frame",nil,lfgui,"HorizontalBarTemplate"),{SetWidth=tableWidth+32,SetHeight=2}, 8, shift+54) ShadowTheAge@32: local text = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetText="Filters:"}, 20, shift+68) ShadowTheAge@25: ShadowTheAge@32: btFilterCount = CreateFrame("FRAME", "CrossRealmAssistCountFilter", lfgui, "UIDropDownMenuTemplate") ShadowTheAge@32: UIDropDownMenu_SetWidth(btFilterCount, 90) ShadowTheAge@32: UIDropDownMenu_SetText(btFilterCount, "By count") ShadowTheAge@32: UIDropDownMenu_Initialize(btFilterCount, numberFilter) ShadowTheAge@32: btFilterCount:SetPoint("TOPLEFT",text,"TOPRIGHT",-10,10) ShadowTheAge@32: ShadowTheAge@32: cbHideNoAutoinv = setupWidget(CreateFrame("CheckButton",nil,lfgui,"UICheckButtonTemplate"),{SetWidth=22,SetHeight=22}) ShadowTheAge@32: cbHideNoAutoinv:SetPoint("TOPLEFT",btFilterCount,"TOPRIGHT",-10,-3) ShadowTheAge@32: cbHideNoAutoinv:SetScript("OnClick",addon.refreshList) ShadowTheAge@32: text = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetText="Autoaccept only"}) ShadowTheAge@32: text:SetPoint("TOPLEFT",cbHideNoAutoinv,"TOPRIGHT",0,-7) ShadowTheAge@32: ShadowTheAge@32: edFilterText = setupWidget(CreateFrame("EditBox",nil,lfgui,"SearchBoxTemplate"),{SetHeight=22}) ShadowTheAge@32: edFilterText:SetPoint("TOPLEFT",text,"TOPRIGHT",10,7) ShadowTheAge@32: edFilterText:SetPoint("TOPRIGHT",lfgui,"BOTTOMRIGHT",-10,0) ShadowTheAge@32: edFilterText:SetScript("OnTextChanged",updateFilter) ShadowTheAge@12: end ShadowTheAge@0: ShadowTheAge@12: function addon:CreateTabs() ShadowTheAge@12: local prevTab ShadowTheAge@32: for i=1,#addon.lfgGroups do ShadowTheAge@12: local tab = CreateFrame("Button","$parentTab"..i,lfgui,"CharacterFrameTabButtonTemplate") ShadowTheAge@32: tab:SetText((C_LFGList.GetCategoryInfo(addon.lfgGroups[i]))); ShadowTheAge@13: tab.searchID = i; ShadowTheAge@12: tab:SetID(i); ShadowTheAge@12: PanelTemplates_TabResize(tab, 0) ShadowTheAge@12: if i == 1 then ShadowTheAge@12: tab:SetPoint("TOPLEFT", lfgui, "BOTTOMLEFT", 10, 7) ShadowTheAge@12: lfgTabSelected = tab ShadowTheAge@13: else ShadowTheAge@13: tab:SetPoint("TOPLEFT", prevTab, "TOPRIGHT",-15,0) ShadowTheAge@13: end ShadowTheAge@13: if curLfgGroup == i then ShadowTheAge@12: PanelTemplates_SelectTab(tab) ShadowTheAge@12: else ShadowTheAge@12: PanelTemplates_DeselectTab(tab) ShadowTheAge@12: end ShadowTheAge@13: tab:SetScript("OnClick", TabClick) ShadowTheAge@12: tabs[i] = tab ShadowTheAge@12: prevTab = tab ShadowTheAge@12: end ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: -- LFG scanning routine ShadowTheAge@0: ShadowTheAge@12: function addon.refreshLfgCurrent() ShadowTheAge@12: addon.LfgScan(curLfgGroup) ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@13: function addon.GetNextAutoScanCategory() ShadowTheAge@32: for i=1,#addon.lfgGroups do ShadowTheAge@32: if not autoScanGroups[i] and db.global.quickJoin[addon.lfgGroups[i]] and i ~= curLfgGroup then return i end ShadowTheAge@13: end ShadowTheAge@13: return nil ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@12: function addon.LfgScan(group) ShadowTheAge@13: if lfgTable then ShadowTheAge@13: lfgTable:SetData({}) ShadowTheAge@13: changeTab(tabs[group]) ShadowTheAge@13: end ShadowTheAge@0: lfgScanInProgress = true ShadowTheAge@12: curLfgGroup = group ShadowTheAge@21: local languages = db.global.allLanguages and allLanguageTable or C_LFGList.GetLanguageSearchFilter(); ShadowTheAge@45: C_LFGList.Search(addon.lfgGroups[curLfgGroup],{},nil,nil,languages) ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:LfgScanFailed(event, reason) ShadowTheAge@21: reason = reason or "Unknown reason"; ShadowTheAge@0: if reason == "throttled" then ShadowTheAge@12: addon:ScheduleTimer(addon.LfgScan, 2, curLfgGroup) ShadowTheAge@0: end ShadowTheAge@13: if lbThrottle then ShadowTheAge@13: if reason == "throttled" then ShadowTheAge@13: lbThrottle:SetText("LFG scan is delayed (throttled).\nThis page will update automatically...") ShadowTheAge@13: else ShadowTheAge@13: lbThrottle:SetText("Scan failed ("..reason..")") ShadowTheAge@13: end ShadowTheAge@13: lbThrottle:Show() ShadowTheAge@13: end ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:LfgResponseData() ShadowTheAge@0: lfgScanInProgress = false; ShadowTheAge@13: addon:UpdateAutoButtonStatus() ShadowTheAge@12: if lbThrottle then lbThrottle:Hide() end ShadowTheAge@12: refreshLFGList() ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:updateAppStatus(event, id, status, oldstatus) ShadowTheAge@0: if status == "invited" then ShadowTheAge@0: LFGListInviteDialog_Accept(LFGListInviteDialog) ShadowTheAge@0: end ShadowTheAge@12: addon:UpdateAutoButtonStatus() ShadowTheAge@12: addon:SetGroupJoinStatus(id, status) ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: function addon:SetGroupJoinStatus(id, status) ShadowTheAge@38: local name = select(13, C_LFGList.GetSearchResultInfo(id)) ShadowTheAge@13: if name then ShadowTheAge@13: recentgroups[name] = {status=status, time=GetTime()} ShadowTheAge@13: end ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@13: function addon:RealmVisited(realm, head) ShadowTheAge@13: recentRealms[realm] = GetTime() ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: function addon:updatePartyInfo() ShadowTheAge@27: if IsInGroup() ~= wasInGroup then ShadowTheAge@13: addon:RefreshZone(true) ShadowTheAge@27: wasInGroup = IsInGroup() ShadowTheAge@12: addon:UpdateAutoButtonStatus() ShadowTheAge@12: end ShadowTheAge@12: end ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@0: ShadowTheAge@0: -- Zone scanning routine ShadowTheAge@0: ShadowTheAge@0: function addon:LeaveCombat() ShadowTheAge@0: addon:UnregisterEvent("PLAYER_REGEN_ENABLED") ShadowTheAge@0: scanstate = 0 ShadowTheAge@0: addon:ScanRealm(); ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@13: function addon:RefreshZoneAndClearHistory() ShadowTheAge@13: ClearRealmHistory() ShadowTheAge@11: addon:RefreshZone(true) ShadowTheAge@11: end ShadowTheAge@11: ShadowTheAge@11: function addon:RefreshZone(shedule) ShadowTheAge@11: local inst, instType = IsInInstance() ShadowTheAge@12: inInstance = (inst or instType ~= "none") ShadowTheAge@12: if inInstance then ShadowTheAge@11: lbRealm:SetText("Instanced zone") ShadowTheAge@11: curRealmStat = nil ShadowTheAge@12: inInstance = true ShadowTheAge@11: else ShadowTheAge@12: inInstance = false; ShadowTheAge@11: if scanstate == 0 then ShadowTheAge@11: addon:ScanRealm() ShadowTheAge@11: elseif shedule == true and scanstate == 2 then ShadowTheAge@27: addon:SetStatus("Rescan scheduled...") ShadowTheAge@11: scanstate = 3 ShadowTheAge@11: end ShadowTheAge@11: end ShadowTheAge@12: addon:UpdateAutoButtonStatus() ShadowTheAge@11: end ShadowTheAge@11: ShadowTheAge@0: function addon:ScanRealm() ShadowTheAge@0: if scanstate > 0 then return end ShadowTheAge@0: if InCombatLockdown() then ShadowTheAge@0: addon:RegisterEvent("PLAYER_REGEN_ENABLED","LeaveCombat") ShadowTheAge@0: scanstate = 1 ShadowTheAge@27: addon:SetStatus("Scan scheduled after combat..."); ShadowTheAge@0: return ShadowTheAge@0: end ShadowTheAge@0: scanstate = 2 ShadowTheAge@11: addon:SetStatus("Scanning current realm..."); ShadowTheAge@0: local searchString = _G.WHO_TAG_ZONE .. '"' .. GetZoneText() .. '"'; ShadowTheAge@0: wholib:Who(searchString, {callback = "ScanResult", handler=addon}) ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:ScanResult(query, results, complete) ShadowTheAge@0: local realms = {} ShadowTheAge@0: for _, player in ipairs(results) do ShadowTheAge@0: addon:AddRealmStat(player.Name, realms); ShadowTheAge@0: end ShadowTheAge@0: curRealmStat = addon:GetRealmStat(realms); ShadowTheAge@11: curRealmStat.complete = complete ShadowTheAge@0: addon:updateCurrentRealm(); ShadowTheAge@0: local rescan = scanstate == 3 ShadowTheAge@0: scanstate = 0; ShadowTheAge@0: if rescan then addon:ScanRealm() end ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:AddRealmStat(name, realms) ShadowTheAge@11: if (name == playerName) then return end ShadowTheAge@11: local _, realm = strsplit(realmSep, name) ShadowTheAge@0: realm = realm or homeRealm ShadowTheAge@0: realms[realm] = (realms[realm] or 0) + 1 ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:AddUnitIdStat(unitid, realms) ShadowTheAge@0: local name, realm = UnitName(unitid); ShadowTheAge@0: if not name then return end ShadowTheAge@0: if realm == "" then realm = homeRealm end ShadowTheAge@0: realm = realm or homeRealm ShadowTheAge@0: realms[realm] = (realms[realm] or 0) + 1 ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:GetRealmStat(realms) ShadowTheAge@0: local rcount = 0; ShadowTheAge@0: local stat = {}; ShadowTheAge@0: local pcount = 0; ShadowTheAge@19: if realms then ShadowTheAge@19: for realm,count in pairs(realms) do ShadowTheAge@19: table.insert(stat,{realm=realm,count=count}) ShadowTheAge@19: rcount = rcount + 1; ShadowTheAge@19: pcount = pcount + count; ShadowTheAge@19: end ShadowTheAge@0: end ShadowTheAge@0: if rcount > 1 then ShadowTheAge@0: table.sort(stat, function(a,b) return a.count > b.count end) ShadowTheAge@0: stat.max = stat[1].count ShadowTheAge@0: else stat.max = 0 end ShadowTheAge@0: stat.players = pcount; ShadowTheAge@0: stat.realms = rcount; ShadowTheAge@0: return stat; ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@0: function addon:updateCurrentRealm() ShadowTheAge@11: addon:SetStatus(); ShadowTheAge@11: if not curRealmStat or curRealmStat.realms < 1 then ShadowTheAge@11: lbRealm:SetText("Unknown realm (No players)") ShadowTheAge@11: return; ShadowTheAge@0: end ShadowTheAge@11: ShadowTheAge@11: local bestRealm = curRealmStat[1] ShadowTheAge@13: addon:RealmVisited(bestRealm.realm, true) ShadowTheAge@12: local prevThreshold = math.min(bestRealm.count/3,10) ShadowTheAge@11: local mixCount = 0 ShadowTheAge@11: for i=2,curRealmStat.realms do ShadowTheAge@0: local data = curRealmStat[i] ShadowTheAge@11: if data.count >= prevThreshold then ShadowTheAge@11: mixCount = mixCount + 1 ShadowTheAge@13: addon:RealmVisited(data.realm) ShadowTheAge@12: prevThreshold = math.min(data.count/3,10) ShadowTheAge@0: end ShadowTheAge@0: end ShadowTheAge@11: curRealmStat.threshold = prevThreshold ShadowTheAge@11: ShadowTheAge@11: if (mixCount > 0) then ShadowTheAge@11: lbRealm:SetText("Mixed "..bestRealm.realm.." +"..mixCount) ShadowTheAge@11: else ShadowTheAge@11: lbRealm:SetText(bestRealm.realm) ShadowTheAge@0: end ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: ShadowTheAge@12: -- Auto action button ShadowTheAge@12: ShadowTheAge@13: local action ShadowTheAge@12: ShadowTheAge@27: local function getPartyStat() ShadowTheAge@29: local curPartyStat = {} ShadowTheAge@27: if IsInGroup() then ShadowTheAge@27: if IsInRaid() then ShadowTheAge@27: for i=1, MAX_RAID_MEMBERS do ShadowTheAge@27: addon:AddUnitIdStat("raid"..i, curPartyStat) ShadowTheAge@27: end ShadowTheAge@27: else ShadowTheAge@27: for i=1, MAX_PARTY_MEMBERS do ShadowTheAge@27: addon:AddUnitIdStat("party"..i, curPartyStat) ShadowTheAge@27: end ShadowTheAge@27: end ShadowTheAge@27: end ShadowTheAge@29: return curPartyStat ShadowTheAge@27: end ShadowTheAge@27: ShadowTheAge@13: local LeaveGroup = { ShadowTheAge@13: func = LeaveParty; ShadowTheAge@17: tooltip = function(self) ShadowTheAge@27: local partyStat = addon:GetRealmStat(getPartyStat()) ShadowTheAge@17: GameTooltip:AddLine("Players in party "..partyStat.players) ShadowTheAge@17: local max = partyStat.max; ShadowTheAge@17: for i=1,#partyStat do ShadowTheAge@17: local data = partyStat[i] ShadowTheAge@17: local percent = math.ceil(100 * data.count / partyStat.players - 0.5) .. "%"; ShadowTheAge@17: local pmax = data.count/max; ShadowTheAge@17: local green = 0.5 + pmax * 0.5; ShadowTheAge@17: local gray = 0.5 * (1-pmax) ShadowTheAge@17: GameTooltip:AddDoubleLine(data.realm, percent, gray,green,gray,gray,green,gray) ShadowTheAge@17: end ShadowTheAge@17: GameTooltip:AddLine("Click to leave party",1,0.5,0) ShadowTheAge@17: end, ShadowTheAge@13: text = "Leave group" ShadowTheAge@13: } ShadowTheAge@13: ShadowTheAge@13: local CancelJoin = { ShadowTheAge@13: func = function() ShadowTheAge@13: local apps = C_LFGList.GetApplications(); ShadowTheAge@13: if apps[1] then ShadowTheAge@13: C_LFGList.CancelApplication(apps[1]) ShadowTheAge@13: end ShadowTheAge@13: end, ShadowTheAge@13: tooltip = "Cancel your current join application", ShadowTheAge@13: text = "Cancel join" ShadowTheAge@13: } ShadowTheAge@13: ShadowTheAge@13: local QuickJoin = { ShadowTheAge@13: func = function(self, button) ShadowTheAge@13: if button == "RightButton" then ShadowTheAge@13: addon:SetGroupJoinStatus(self.groupToJoin, "_skip") ShadowTheAge@13: else ShadowTheAge@38: local delisted = select(12, C_LFGList.GetSearchResultInfo(self.groupToJoin)) ShadowTheAge@13: if delisted == false then ShadowTheAge@13: JoinGroup(self.groupToJoin) ShadowTheAge@13: else ShadowTheAge@13: addon:SetStatus("Group just delisted") ShadowTheAge@13: end ShadowTheAge@13: end ShadowTheAge@13: end, ShadowTheAge@13: findGroup = function() ShadowTheAge@13: local count, list = C_LFGList.GetSearchResults() ShadowTheAge@13: local best ShadowTheAge@13: local bestvalue = 0 ShadowTheAge@13: for i = 1,count do ShadowTheAge@13: local rid = list[i]; ShadowTheAge@13: if not rid then break end ShadowTheAge@13: local value = WeightLfgItem(rid, true); ShadowTheAge@13: if value > bestvalue then ShadowTheAge@13: best = rid ShadowTheAge@13: bestvalue = value ShadowTheAge@13: end ShadowTheAge@13: end ShadowTheAge@13: return best ShadowTheAge@13: end, ShadowTheAge@13: tooltip = function(self) ShadowTheAge@13: AddLfgGroupInfo(self.groupToJoin, true) ShadowTheAge@13: GameTooltip:AddLine(" ") ShadowTheAge@13: GameTooltip:AddDoubleLine("Click to join","Right click to skip",0,1,0,1,0.5,0) ShadowTheAge@13: end, ShadowTheAge@13: text = "Quick join" ShadowTheAge@13: } ShadowTheAge@13: ShadowTheAge@13: local ScanNext = { ShadowTheAge@13: func = function(self) ShadowTheAge@13: autoScanGroups[curLfgGroup] = 1 ShadowTheAge@13: addon.LfgScan(self.category) ShadowTheAge@13: end, ShadowTheAge@13: tooltip = function(self) ShadowTheAge@32: GameTooltip:AddLine("Scan "..(C_LFGList.GetCategoryInfo(addon.lfgGroups[self.category]))) ShadowTheAge@13: end, ShadowTheAge@13: text = "Scan more" ShadowTheAge@13: } ShadowTheAge@13: ShadowTheAge@13: local NeedReset = { ShadowTheAge@13: func = function() ShadowTheAge@13: wipe(autoScanGroups); ShadowTheAge@38: curLfgGroup = 0; ShadowTheAge@13: local categoryToScan = addon.GetNextAutoScanCategory() ShadowTheAge@13: if categoryToScan then ShadowTheAge@13: addon.LfgScan(categoryToScan) ShadowTheAge@13: end ShadowTheAge@13: end, ShadowTheAge@13: tooltip = "Scan again", ShadowTheAge@13: text = "Restart scan" ShadowTheAge@13: } ShadowTheAge@13: ShadowTheAge@13: local Wait = { ShadowTheAge@13: tooltip = "Scan in progress", ShadowTheAge@13: text = "Wait..." ShadowTheAge@13: } ShadowTheAge@13: ShadowTheAge@13: local ShowQuickHint = { ShadowTheAge@13: tooltip = "Quick Join", ShadowTheAge@13: text = "Quick Join", ShadowTheAge@13: func = function() ShadowTheAge@13: StaticPopupDialogs["CROSS_REALM_ASSIST"] = { ShadowTheAge@32: text = "Quick Join button will automatically join you to a random group with autoaccept and medium number of players. You never join same group twice, you need to clear join history to do so. This message can be disabled in options.", ShadowTheAge@13: button1 = OKAY, ShadowTheAge@13: hideOnEscape = true, ShadowTheAge@13: preferredIndex = 3, ShadowTheAge@13: } ShadowTheAge@13: StaticPopup_Show("CROSS_REALM_ASSIST") ShadowTheAge@13: hintShown = true; ShadowTheAge@13: end ShadowTheAge@13: } ShadowTheAge@13: ShadowTheAge@13: function addon.DoAutoAction(widget, button) ShadowTheAge@13: addon:SetStatus() ShadowTheAge@13: if action and action.func then ShadowTheAge@13: action:func(button) ShadowTheAge@13: end ShadowTheAge@13: addon:UpdateAutoButtonStatus() ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@13: function addon.actionTooltip() ShadowTheAge@13: local tooltip = action.tooltip ShadowTheAge@13: if type(tooltip) == 'function' then ShadowTheAge@13: tooltip(action) ShadowTheAge@13: else ShadowTheAge@13: GameTooltip:AddLine(tooltip) ShadowTheAge@11: end ShadowTheAge@11: end ShadowTheAge@11: ShadowTheAge@13: function addon:UpdateAutoButtonStatus() ShadowTheAge@13: if not btQuick then return end ShadowTheAge@13: btQuick:Enable() ShadowTheAge@19: if IsInGroup() then ShadowTheAge@13: action = LeaveGroup; ShadowTheAge@13: elseif C_LFGList.GetNumApplications() > 0 then ShadowTheAge@13: action = CancelJoin; ShadowTheAge@13: elseif lfgScanInProgress then ShadowTheAge@13: action = Wait ShadowTheAge@19: elseif not hintShown and db.global.quickJoinHint then ShadowTheAge@19: action = ShowQuickHint; ShadowTheAge@13: else ShadowTheAge@13: local group = QuickJoin.findGroup(); ShadowTheAge@13: if group then ShadowTheAge@13: action = QuickJoin; ShadowTheAge@13: QuickJoin.groupToJoin = group ShadowTheAge@13: else ShadowTheAge@13: local categoryToScan = addon.GetNextAutoScanCategory() ShadowTheAge@13: if (categoryToScan) then ShadowTheAge@13: action = ScanNext; ShadowTheAge@13: ScanNext.category = categoryToScan ShadowTheAge@13: else ShadowTheAge@13: action = NeedReset; ShadowTheAge@13: end ShadowTheAge@13: end ShadowTheAge@13: end ShadowTheAge@13: btQuick:SetText(action.text) ShadowTheAge@13: if GameTooltip:GetOwner() == btQuick then ShadowTheAge@13: ShowTooltip(btQuick) ShadowTheAge@0: end ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@12: ShadowTheAge@13: ShadowTheAge@13: ShadowTheAge@27: -- Realm hop group ShadowTheAge@13: ShadowTheAge@27: local function CreateHopGroup() ShadowTheAge@29: if canJoinGroup() then ShadowTheAge@29: C_LFGList.CreateListing(16,"Realm hopping - "..homeRealm,0,"","",true) ShadowTheAge@29: addon:ScheduleTimer(ConvertToRaid, 5) ShadowTheAge@29: end ShadowTheAge@27: end ShadowTheAge@27: ShadowTheAge@27: function addon:PlayerFlagsUpdate(event, target) ShadowTheAge@29: if target == "player" and UnitIsAFK("player") and C_Garrison.IsOnGarrisonMap() and db.global.autoCreateHopGroup then ShadowTheAge@29: CreateHopGroup() ShadowTheAge@29: end ShadowTheAge@27: end ShadowTheAge@13: ShadowTheAge@13: -- Settings ShadowTheAge@13: ShadowTheAge@32: function addon.toggleMinimapIcon(hidden) ShadowTheAge@13: if hidden then ShadowTheAge@13: DEFAULT_CHAT_FRAME:AddMessage("|cffff0000Type |cffffffff/cra |cffff0000in chat to open Cross Realm Assist without minimap button"); ShadowTheAge@13: minimapIcon:Hide("CrossRealmAssistMinimapIcon") ShadowTheAge@13: else ShadowTheAge@13: minimapIcon:Show("CrossRealmAssistMinimapIcon") ShadowTheAge@13: end ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@32: function addon.updateLfgScale(scale) ShadowTheAge@32: if lfgui then lfgui:SetScale(scale) end; ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@32: function addon.updateUIScale(scale) ShadowTheAge@32: if gui then gui:SetScale(scale) end; ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@13: local function toggleQuickJoinHint(btn, arg1, arg2, checked) ShadowTheAge@13: db.global.quickJoinHint = checked ShadowTheAge@0: end ShadowTheAge@0: ShadowTheAge@13: local function toggleQuickJoin(btn, arg1, arg2, checked) ShadowTheAge@13: db.global.quickJoin[arg1] = checked ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@21: local function toggleAllLanguages(btn, arg1, arg2, checked) ShadowTheAge@21: db.global.allLanguages = checked ShadowTheAge@21: end ShadowTheAge@21: ShadowTheAge@25: local function toggleApplyAsDD(btn, arg1, arg2, checked) ShadowTheAge@25: db.global.applyAsDD = checked ShadowTheAge@25: end ShadowTheAge@25: ShadowTheAge@27: local function toggleCreateHopGroup(btn, arg1, arg2, checked) ShadowTheAge@27: db.global.autoCreateHopGroup = checked ShadowTheAge@29: if checked then addon:RegisterEvent("PLAYER_FLAGS_CHANGED", "PlayerFlagsUpdate") end ShadowTheAge@27: end ShadowTheAge@27: ShadowTheAge@32: local function joinFriendGroup(btn, rid) ShadowTheAge@32: JoinGroup(rid); ShadowTheAge@32: end ShadowTheAge@32: ShadowTheAge@13: local function ClearJoinHistory() ShadowTheAge@13: recentgroups = {} ShadowTheAge@13: addon:UpdateAutoButtonStatus() ShadowTheAge@13: if lfgTable then lfgTable:Refresh() end ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@27: local function QuickJoinStoplist() ShadowTheAge@27: StaticPopupDialogs["CROSS_REALM_ASSIST_STOPLIST"] = { ShadowTheAge@29: OnShow = function (self, data) ShadowTheAge@29: self.editBox:SetText(table.concat(db.global.stoplist or {}, ",")) ShadowTheAge@29: end, ShadowTheAge@29: OnAccept=function(self) ShadowTheAge@29: local text = self.editBox:GetText(); ShadowTheAge@29: local stoplist = {} ShadowTheAge@29: for item in string.gmatch(text, "[^, ][^,]*") do ShadowTheAge@29: table.insert(stoplist,string.lower(item)) ShadowTheAge@29: end ShadowTheAge@29: db.global.stoplist = stoplist ShadowTheAge@29: end, ShadowTheAge@29: button1 = OKAY, ShadowTheAge@29: button2 = CANCEL, ShadowTheAge@29: editBoxWidth = 350, ShadowTheAge@29: hasEditBox=true, ShadowTheAge@29: text = "Ignore groups containing following words:\nSeparated by comma", ShadowTheAge@29: preferredIndex = 3 ShadowTheAge@29: } ShadowTheAge@29: StaticPopup_Show("CROSS_REALM_ASSIST_STOPLIST") ShadowTheAge@27: end ShadowTheAge@13: ShadowTheAge@13: local function initMenu(self, level) ShadowTheAge@13: if not level then return end ShadowTheAge@13: if level == 1 then ShadowTheAge@32: UIDropDownMenu_AddButton({text="Clear join history",notCheckable=1,func=ClearJoinHistory}, level) ShadowTheAge@13: UIDropDownMenu_AddButton({text="Clear realm history",notCheckable=1,func=ClearRealmHistory}, level) ShadowTheAge@32: UIDropDownMenu_AddButton({disabled=1,notCheckable=1}, level) ShadowTheAge@29: ShadowTheAge@32: UIDropDownMenu_AddButton({text="Cross Realm Assist Toolbox",notCheckable=1,func=CreateHopGroup,isTitle=1}, level) ShadowTheAge@32: UIDropDownMenu_AddButton({text="Show Quick Join Hint",checked=db.global.quickJoinHint, func=toggleQuickJoinHint,keepShownOnClick=true,isNotRadio=true}, level) ShadowTheAge@32: if canJoinGroup() then ShadowTheAge@29: UIDropDownMenu_AddButton({text="Create a group for realm hoppers",notCheckable=1,func=CreateHopGroup}, level) ShadowTheAge@32: UIDropDownMenu_AddButton({text="Join to a friend",notCheckable=1,hasArrow=1,value="jtf",keepShownOnClick=true}, level) ShadowTheAge@29: end ShadowTheAge@29: ShadowTheAge@29: UIDropDownMenu_AddButton({disabled=1,notCheckable=1}, level) ShadowTheAge@32: UIDropDownMenu_AddButton({text="Settings...",notCheckable=1,func=addon.showSettings}, level) ShadowTheAge@13: elseif level == 2 then ShadowTheAge@32: if UIDROPDOWNMENU_MENU_VALUE == "jtf" then ShadowTheAge@32: local count, list = C_LFGList.GetSearchResults() ShadowTheAge@32: local friends = {} ShadowTheAge@32: for i = 1,count do ShadowTheAge@32: local rid = list[i]; ShadowTheAge@32: if not rid then break end ShadowTheAge@32: local bnf, chf, gf = C_LFGList.GetSearchResultFriends(rid) ShadowTheAge@32: for j=1,#bnf do table.insert(friends,{name="|cFF00B1F0"..bnf[j],type=0,id=rid}) end ShadowTheAge@32: for j=1,#chf do table.insert(friends,{name="|cFFFF80FF"..chf[j],type=1,id=rid}) end ShadowTheAge@32: for j=1,#gf do table.insert(friends,{name="|cFF40FF40"..gf[j],type=2,id=rid}) end ShadowTheAge@32: end ShadowTheAge@32: if #friends==0 then ShadowTheAge@32: UIDropDownMenu_AddButton({text="No friends found (click to refresh)",notCheckable=1,func=addon.refreshLfgCurrent}, level) ShadowTheAge@32: else ShadowTheAge@32: UIDropDownMenu_AddButton({text="Refresh",notCheckable=1,func=addon.refreshLfgCurrent}, level) ShadowTheAge@32: table.sort(friends, sortByTypeAndName); ShadowTheAge@32: for i=1,#friends do ShadowTheAge@32: UIDropDownMenu_AddButton({text=friends[i].name,notCheckable=1,func=joinFriendGroup,arg1=friends[i].id}, level) ShadowTheAge@32: end ShadowTheAge@32: end ShadowTheAge@32: end ShadowTheAge@29: end ShadowTheAge@13: end ShadowTheAge@13: ShadowTheAge@13: function addon.ShowSettings(frame) ShadowTheAge@13: if not settingsMenu then ShadowTheAge@13: settingsMenu = CreateFrame("Frame", "CrossRealmAssistMenu") ShadowTheAge@13: settingsMenu.displayMode = "MENU" ShadowTheAge@13: settingsMenu.initialize = initMenu ShadowTheAge@13: end ShadowTheAge@13: ToggleDropDownMenu(1, nil, settingsMenu, frame, 10, 0) ShadowTheAge@12: end