comparison CrossRealmAssist.lua @ 12:0deef890ec99

Updated version
author ShadowTheAge
date Wed, 11 Mar 2015 22:51:00 +0300
parents 421508c17712
children 1f68e8154947
comparison
equal deleted inserted replaced
11:421508c17712 12:0deef890ec99
1 CrossRealmAssist = LibStub("AceAddon-3.0"):NewAddon("CrossRealmAssist", "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0") 1 CrossRealmAssist = LibStub("AceAddon-3.0"):NewAddon("CrossRealmAssist", "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0")
2 local AceGUI = LibStub("AceGUI-3.0")
3 local addon = CrossRealmAssist; 2 local addon = CrossRealmAssist;
4 local wholib = LibStub:GetLibrary('LibWho-2.0'):Library() 3 local wholib = LibStub:GetLibrary('LibWho-2.0'):Library()
5 4 local ScrollingTable = LibStub("ScrollingTable");
6 local homeRealm, realmSep, gui, btRefresh, btQuick, btManual, lbRealm, lbStatus, playerName 5
7 6 local homeRealm, realmSep, gui, btRefresh, btQuick, btManual, lbRealm, lbStatus, playerName, lfgui, lfgTabSelected, lfgTable, lbThrottle
7
8 local tabs = {}
8 local curRealmStat 9 local curRealmStat
9 local scanstate=0 10 local scanstate=0
10 local recentRealms={} 11 local recentRealms={}
12 local recentgroups={}
11 local active=false 13 local active=false
12 14
13 local lfgGroups={ 15 local lfgGroups={
14 6, -- Custom 16 6, -- Custom
15 10, -- Ashran 17 10, -- Ashran
16 1, -- Quests 18 1, -- Quests
17 3, -- Raids 19 3 -- Raids
18 8 -- BGs
19 } 20 }
20 21
21 local lfgTabs 22 local StatusTable = {
23 ["invited"]="Invited",
24 ["declined"]="Declined",
25 ["timedout"]="Timed out",
26 ["applied"]="Applied",
27 ["cancelled"]="Join cancelled",
28 ["inviteaccepted"]="Joined",
29 ["_init"]="Join request"
30 }
31
22 local curLfgGroup 32 local curLfgGroup
23 local sheduledScan 33 local sheduledScan
24 local wasInGroup 34 local wasInGroup
25 local wasInInstance 35 local inInstance
26 local lfgScanInProgress=false 36
37
38 -- Utils functions
39
40 local function PlayerName(fullname)
41 fullname = fullname or "???-???"
42 local name, realm = strsplit(realmSep, fullname)
43 realm = realm or homeRealm;
44 return name, realm;
45 end
46
47 local function canJoinGroup()
48 return (not IsInGroup()) or (UnitIsGroupLeader('player') and not IsInRaid())
49 end
50
51 local function sortByWeight(a,b)
52 return b.weight < a.weight
53 end
54
55
56 -- UI functions
57
58 local function createIcon(owner, icon, id)
59 local image = owner:CreateTexture(nil, "BACKGROUND")
60 image:SetWidth(16)
61 image:SetHeight(16)
62 image:SetTexture(icon)
63 image:SetPoint("TOPLEFT",owner,"TOPLEFT",id*16,0)
64 return image
65 end
27 66
28 local function setupWidget(widget, parameters, x, y) 67 local function setupWidget(widget, parameters, x, y)
29 if parameters then 68 if parameters then
30 for key,value in pairs(parameters) do widget[key](widget,value) end 69 for key,value in pairs(parameters) do widget[key](widget,value) end
31 end 70 end
51 widget.TooltipFactory = factory; 90 widget.TooltipFactory = factory;
52 widget:SetScript("OnEnter", ShowTooltip) 91 widget:SetScript("OnEnter", ShowTooltip)
53 widget:SetScript("OnLeave", HideTooltip) 92 widget:SetScript("OnLeave", HideTooltip)
54 end 93 end
55 94
56 function addon:OnInitialize() 95 local function SelectLfgTab(tab)
57 96 PanelTemplates_DeselectTab(lfgTabSelected)
58 end 97 lfgTabSelected = tab
98 addon.LfgScan(tab.searchID)
99 PanelTemplates_SelectTab(lfgTabSelected)
100 end
101
102 local function realmToolip()
103 if not curRealmStat then return end
104 local players = curRealmStat.players;
105 local threshold = curRealmStat.threshold
106 GameTooltip:AddLine("Players in zone: "..players)
107 if not curRealmStat.complete then
108 GameTooltip:AppendText("+")
109 end
110 for i=1,curRealmStat.realms do
111 local data = curRealmStat[i]
112 local percent = math.ceil(100 * data.count / players - 0.5) .. "%";
113 if data.count >= threshold then
114 GameTooltip:AddDoubleLine(data.realm, percent, 0,1,0,0,1,0)
115 else
116 GameTooltip:AddDoubleLine(data.realm, percent, 0.5,0.5,0.5,0.5,0.5,0.5)
117 end
118 end
119 end
120
121
122
123
124
125
126
127 -- LFG list data providers, filters and tooltips
128
129 local lfgScanInProgress=false
130 local hasLfgListChanges=false
131
132 local function addTooltipLineIcon(predicat, text, icon, r, g, b, wrap)
133 if predicat then
134 GameTooltip:AddLine(text, r, g, b, wrap)
135 if icon then GameTooltip:AddTexture(icon) end
136 end
137 end
138
139 local function WeightLfgItem(id, forAutoJoin)
140 local _, action, caption, desc, voice, ilvl, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(id)
141 if delisted then return 0 end
142 local name,realm = PlayerName(fullname);
143 if forAutoJoin then
144 if not autoinv or pcount >= 35 or pcount <= 5 or recentgroups[fullname] then return 0 end
145 end
146
147 local autoinvWeight = autoinv and 5 or 2
148
149 local visCoef = 1
150 if recentgroups[fullname] then
151 local ago = GetTime() - recentgroups[fullname].time;
152 visCoef = math.min(1,ago/600)
153 end
154
155 local leaderRealm = 3 -- recently visited realms
156 if (realm ~= "???") then leaderRealm = (5 - (recentRealms[realm] or 0)) end
157
158 local countWeight = 4 -- count weight
159 if pcount >= 39 or pcount <= 1 then countWeight = 1
160 elseif pcount >= 35 or pcount <= 4 then countWeight = 2
161 elseif pcount >= 30 or pcount <= 10 then countWeight = 3
162 else countWeight = 4 end
163
164 local ageWeight = 2
165 if time > 1200 then ageWeight = 4
166 elseif time > 300 then ageWeight = 3 end
167
168 return leaderRealm * countWeight * visCoef * autoinvWeight * ageWeight;
169 end
170
171 local function ShowLfgInfo(rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
172 if not realrow then return end
173 local rowdata = scrollingTable:GetRow(realrow);
174 local _, action, caption, desc, voice, ilvl, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(rowdata.id)
175 local friends = bnetfr+charfr+guild
176 GameTooltip:SetOwner(rowFrame, "ANCHOR_BOTTOMLEFT",-10,25)
177 GameTooltip:ClearLines()
178 GameTooltip:AddLine(caption,1,1,1)
179 addTooltipLineIcon(desc ~= "", desc, nil, 0.5, 0.5, 0.5, true)
180 local name, realm = PlayerName(fullname)
181 GameTooltip:AddDoubleLine("Leader:",name)
182 GameTooltip:AddDoubleLine("Leader realm:",realm)
183 GameTooltip:AddLine(" ")
184 GameTooltip:AddDoubleLine("Players:",pcount)
185 addTooltipLineIcon(ilvl > 0, "Min. ilvl: "..ilvl, READY_CHECK_WAITING_TEXTURE, 1, 1, 0)
186 addTooltipLineIcon(voice ~= "", "Voice: "..voice, READY_CHECK_WAITING_TEXTURE, 1, 1, 0)
187 addTooltipLineIcon(friends > 0, "Friends: "..friends, READY_CHECK_WAITING_TEXTURE, 1, 1, 0)
188 addTooltipLineIcon(autoinv, "Autoinvite!", READY_CHECK_READY_TEXTURE, 0, 1, 0)
189 local visitinfo = recentgroups[fullname]
190 if visitinfo then
191 local ago = GetTime() - visitinfo.time;
192 GameTooltip:AddDoubleLine(StatusTable[visitinfo.status] or visitinfo.status,SecondsToTime(ago, false, false, 1, false).." ago",1,0,0,1,0,0)
193 GameTooltip:AddTexture(READY_CHECK_NOT_READY_TEXTURE)
194 end
195 GameTooltip:Show()
196 end
197
198 local function updateTableData(rowFrame, cellFrame, data, cols, row, realrow, column, fShow, table, ...)
199 if fShow then
200 local rowdata = table:GetRow(realrow);
201 local icons = cellFrame.icons
202 local _, action, caption, desc, voice, ilvl, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(rowdata.id)
203 if not icons then
204 local miscdata = createIcon(cellFrame,READY_CHECK_WAITING_TEXTURE,0)
205 local autoinv = createIcon(cellFrame,READY_CHECK_READY_TEXTURE, 1)
206 local visited = createIcon(cellFrame,READY_CHECK_NOT_READY_TEXTURE, 2)
207 icons = {misc=miscdata, autoinv=autoinv, visited=visited}
208 cellFrame.icons = icons
209 end
210 icons.misc:SetShown(voice ~= "" or bnetfr > 0 or charfr > 0 or guild > 0 or ilvl > 0)
211 icons.autoinv:SetShown(autoinv)
212 icons.visited:SetShown(recentgroups[fullname])
213 if GameTooltip:GetOwner() == rowFrame then ShowLfgInfo(rowFrame, cellFrame, data, cols, row, realrow, column, table) end
214 end
215 end
216
217 local function updateGroupName(id)
218 return select(3, C_LFGList.GetSearchResultInfo(id))
219 end
220
221 local function updateGroupCount(id)
222 return select(13, C_LFGList.GetSearchResultInfo(id))
223 end
224
225 local function updateGroupRealm(id)
226 local name = select(12, C_LFGList.GetSearchResultInfo(id))
227 local pname, realm = PlayerName(name);
228 return realm
229 end
230
231 local function filterTable(self, row)
232 local delisted = select(11, C_LFGList.GetSearchResultInfo(row.id))
233 return not delisted;
234 end
235
236 function addon:UpdateResponseData(event, result)
237 if select(11, C_LFGList.GetSearchResultInfo(result)) then
238 lfgTable:SetFilter(filterTable)
239 end
240 hasLfgListChanges = true
241 end
242
243 local function refreshLFGList()
244 if lfgScanInProgress or not lfgTable then return end
245 local count, list = C_LFGList.GetSearchResults()
246 local tableData = {}
247 for i = 1,count do
248 local rid = list[i];
249 if not rid then break end
250 local data = list[i];
251 local cols = {}
252 local row = {rid}
253 cols[1] = {value=updateGroupName,args=row}
254 cols[2] = {value=updateGroupCount,args=row}
255 cols[3] = {value=updateGroupRealm,args=row}
256 cols[4] = {}
257 table.insert(tableData, {cols=cols,id=rid,weight=WeightLfgItem(rid)})
258 end
259 table.sort(tableData, sortByWeight);
260 lfgTable:SetData(tableData)
261 end
262
263 local function JoinGroup(rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
264 if not realrow or not canJoinGroup() then return end
265 local rowdata = scrollingTable:GetRow(realrow);
266 local tank, heal, dd = C_LFGList.GetAvailableRoles()
267 addon:SetGroupJoinStatus(rowdata.id, "_init")
268 C_LFGList.ApplyToGroup(rowdata.id, "", tank, heal, dd)
269 end
270
271
272
273
274
275
276 -- Addon functions and gui constructors
59 277
60 function addon:OnEnable() 278 function addon:OnEnable()
61 local tabCount = table.getn(lfgGroups) 279 local tabCount = table.getn(lfgGroups)
62 lfgTabs = {}
63 for i=1,tabCount do
64 local cat = lfgGroups[i]
65 table.insert(lfgTabs,{value=cat,text=(C_LFGList.GetCategoryInfo(cat))})
66 end
67 realmSep = _G.REALM_SEPARATORS 280 realmSep = _G.REALM_SEPARATORS
68 playerName = UnitName("player") 281 playerName = UnitName("player")
69 homeRealm = GetRealmName() 282 homeRealm = GetRealmName()
70 addon:RegisterChatCommand("cra", "Activate") 283 addon:RegisterChatCommand("cra", "Activate")
71 addon:RegisterChatCommand("crossrealmassist", "Activate") 284 addon:RegisterChatCommand("crossrealmassist", "Activate")
85 addon:updateCurrentRealm(); 298 addon:updateCurrentRealm();
86 addon:ForceRefreshZone(); 299 addon:ForceRefreshZone();
87 gui:Show() 300 gui:Show()
88 addon:RegisterEvent("ZONE_CHANGED_NEW_AREA", "ForceRefreshZone") 301 addon:RegisterEvent("ZONE_CHANGED_NEW_AREA", "ForceRefreshZone")
89 addon:RegisterEvent("SCENARIO_UPDATE", "ForceRefreshZone") 302 addon:RegisterEvent("SCENARIO_UPDATE", "ForceRefreshZone")
90 --addon:RegisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED", "LfgResponseData") 303 addon:RegisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED", "LfgResponseData")
91 --addon:RegisterEvent("LFG_LIST_SEARCH_FAILED", "LfgScanFailed") 304 addon:RegisterEvent("LFG_LIST_SEARCH_RESULT_UPDATED", "UpdateResponseData")
92 --addon:RegisterEvent("GROUP_ROSTER_UPDATE", "updatePartyInfo") 305 addon:RegisterEvent("LFG_LIST_SEARCH_FAILED", "LfgScanFailed")
93 --addon:RegisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED", "updateAppStatus") 306 addon:RegisterEvent("GROUP_ROSTER_UPDATE", "updatePartyInfo")
307 addon:RegisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED", "updateAppStatus")
308 addon.LfgScan(lfgGroups[1])
94 end 309 end
95 310
96 function addon:Deactivate() 311 function addon:Deactivate()
97 if not active then return end 312 if not active then return end
98 active = false 313 active = false
314 gui:Hide()
315 if lfgui then lfgui:Hide() end
99 scanstate = 0 316 scanstate = 0
100 lfgScanInProgress = false 317 lfgScanInProgress = false
101 addon:UnregisterEvent("ZONE_CHANGED_NEW_AREA") 318 addon:UnregisterEvent("ZONE_CHANGED_NEW_AREA")
102 addon:UnregisterEvent("PLAYER_REGEN_ENABLED") 319 addon:UnregisterEvent("PLAYER_REGEN_ENABLED")
103 addon:UnregisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED") 320 addon:UnregisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED")
321 addon:UnregisterEvent("LFG_LIST_SEARCH_RESULT_UPDATED")
104 addon:UnregisterEvent("LFG_LIST_SEARCH_FAILED") 322 addon:UnregisterEvent("LFG_LIST_SEARCH_FAILED")
105 addon:UnregisterEvent("GROUP_ROSTER_UPDATE") 323 addon:UnregisterEvent("GROUP_ROSTER_UPDATE")
106 addon:UnregisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED") 324 addon:UnregisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED")
107 end 325 end
108 326
113 lbStatus:SetText("") -- TODO 331 lbStatus:SetText("") -- TODO
114 end 332 end
115 end 333 end
116 334
117 function addon:CreateUI() 335 function addon:CreateUI()
118 gui = setupWidget(CreateFrame("Frame",nil,nil,"InsetFrameTemplate3"), {SetFrameStrata="DIALOG",SetWidth=208,SetHeight=60,EnableMouse=true,SetMovable=true}) 336 gui = setupWidget(CreateFrame("Frame","CrossRealmAssistMainUI",nil,"InsetFrameTemplate3"), {SetFrameStrata="LOW",SetWidth=208,SetHeight=60,EnableMouse=true,SetMovable=true})
119 local title = setupWidget(CreateFrame("Frame",nil,gui), {SetWidth=190,SetHeight=18,EnableMouse=true,RegisterForDrag="LeftButton"}, 0, 6); 337 local title = setupWidget(CreateFrame("Frame",nil,gui), {SetWidth=190,SetHeight=18,EnableMouse=true,RegisterForDrag="LeftButton"}, 0, 6);
120 title:SetScript("OnDragStart", function() gui:StartMoving() end) 338 title:SetScript("OnDragStart", function() gui:StartMoving() end)
121 title:SetScript("OnDragStop", function() gui:StopMovingOrSizing() end) 339 title:SetScript("OnDragStop", function() gui:StopMovingOrSizing() end)
122 gui:SetScript("OnHide", addon.Deactivate) 340 gui:SetScript("OnHide", addon.Deactivate)
123 setupTooltip(title, "ANCHOR_TOP", addon.realmToolip) 341 setupTooltip(title, "ANCHOR_TOP", realmToolip)
124 342
125 lbRealm = setupWidget(gui:CreateFontString(nil,"BACKGROUND", "GameFontNormal"), {SetWidth=200,SetHeight=18}, 0, 6) 343 lbRealm = setupWidget(gui:CreateFontString(nil,"BACKGROUND", "GameFontNormal"), {SetWidth=200,SetHeight=18}, 0, 6)
126 lbStatus = setupWidget(gui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmallLeft"), {SetWidth=200,SetHeight=10}, 6, 23) 344 lbStatus = setupWidget(gui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmallLeft"), {SetWidth=200,SetHeight=10}, 6, 23)
127 345
128 btQuick = setupWidget(CreateFrame("Button",nil,gui,"UIMenuButtonStretchTemplate"),{EnableMouse=true,SetWidth=90,SetHeight=20,SetText="Quick join"},4,36) 346 btQuick = setupWidget(CreateFrame("Button",nil,gui,"UIMenuButtonStretchTemplate"),{SetWidth=90,SetHeight=20,SetText="Quick join"},4,36)
129 btManual = setupWidget(CreateFrame("Button",nil,gui,"UIMenuButtonStretchTemplate"),{EnableMouse=true,SetWidth=90,SetHeight=20,SetText="Manual join"},94,36) 347 btQuick:SetScript("OnClick",addon.DoAutoAction)
348 btManual = setupWidget(CreateFrame("Button",nil,gui,"UIMenuButtonStretchTemplate"),{SetWidth=90,SetHeight=20,SetText="Manual join"},94,36)
349 btManual:SetScript("OnClick",addon.ShowManualLfg)
130 setupWidget(CreateFrame("Button",nil,gui,"UIPanelCloseButton"),{EnableMouse=true,SetWidth=20,SetHeight=20},188,0) 350 setupWidget(CreateFrame("Button",nil,gui,"UIPanelCloseButton"),{EnableMouse=true,SetWidth=20,SetHeight=20},188,0)
131 351
132 btRefresh = setupWidget(CreateFrame("Button",nil,gui,"UIPanelSquareButton"),{EnableMouse=true,SetWidth=20,SetHeight=20},184,36) 352 btRefresh = setupWidget(CreateFrame("Button",nil,gui,"UIPanelSquareButton"),{SetWidth=20,SetHeight=20},184,36)
133 btRefresh.icon:SetTexture("Interface/BUTTONS/UI-RefreshButton") 353 btRefresh.icon:SetTexture("Interface/BUTTONS/UI-RefreshButton")
134 btRefresh.icon:SetTexCoord(0,1,0,1); 354 btRefresh.icon:SetTexCoord(0,1,0,1);
135 btRefresh:SetScript("OnClick",addon.RefreshZone) 355 btRefresh:SetScript("OnClick",addon.RefreshZone)
136 356
137 gui:SetPoint("CENTER",0,0) 357 gui:SetPoint("CENTER",0,0)
138 358 addon:UpdateAutoButtonStatus()
139 --[[gui = addon:AddUI(nil,"Window",{SetTitle="Cross Realm Assist",EnableResize=false,SetLayout="Flow"},true,{OnClose=addon.Deactivate}) 359 end
140 360
141 local tabgroup = addon:AddUI(gui,"TabGroup",{SetFullHeight=true,SetTabs=lfgTabs,SetLayout="Fill"},true,{OnGroupSelected=addon.LfgScan}) 361 function addon:ShowManualLfg()
142 tabgroup:SelectTab(lfgGroups[1]) 362 if not lfgui then addon:CreateLFGUI() end
143 lfgContainer = addon:AddUI(tabgroup,"ScrollFrame") 363 lfgui:Show()
144 364 end
145 local hgroupc = addon:AddUI(gui,"InlineGroup",{SetLayout="Fill",SetFullHeight=true,SetTitle="Realm info"},true) 365
146 hgroup = addon:AddUI(hgroupc,"ScrollFrame") 366 function addon.lfgUpdate()
147 367 if hasLfgListChanges then
148 addon:AddUI(hgroup,"Heading",{SetText="Current realm"}) 368 lfgTable:Refresh()
149 currealm = addon:AddUI(hgroup,"SimpleGroup"); 369 hasLfgListChanges = false
150 addon:AddUI(hgroup,"Button",{SetText="Refresh",SetRelativeWidth=0.5,SetHeight=20},true,{OnClick=addon.ScanRealm}) 370 end
151 371 end
152 addon:AddUI(hgroup,"Heading",{SetText="Party statistics"}) 372
153 partyrealm = addon:AddUI(hgroup,"SimpleGroup"); 373 function addon:CreateLFGUI()
154 leavebtn = addon:AddUI(hgroup,"Button",{SetText="Leave",SetRelativeWidth=0.5,SetHeight=20,SetDisabled=not IsInGroup()},true,{OnClick=LeaveParty}) 374 lfgui = setupWidget(CreateFrame("Frame","CrossRealmAssistJoinUI",nil,"UIPanelDialogTemplate"), {SetFrameStrata="DIALOG",SetWidth=405,SetHeight=300,EnableMouse=true,SetMovable=true})
155 375 lfgui.title:SetText("Click to join group")
156 addon:AddUI(hgroup,"Heading",{SetText="Recent realms"}) 376 lfgui:SetScript("OnUpdate",addon.lfgUpdate)
157 recrealm = addon:AddUI(hgroup,"SimpleGroup"); 377 local titlereg = lfgui:CreateTitleRegion()
158 addon:AddUI(hgroup,"Button",{SetText="Clear",SetRelativeWidth=0.5,SetHeight=20},true,{OnClick=addon.ClearRecentRealms}) 378 titlereg:SetAllPoints(lfgui.title)
159 379 addon:CreateTabs()
160 gui:DoLayout() 380
161 gui:PauseLayout() 381 lfgTable = ScrollingTable:CreateST({
162 382 {name="Title",width=160},
163 tabgroup:SetPoint("BOTTOMRIGHT", gui.content, "BOTTOMRIGHT", -200, 0) 383 {name="#",width=30,align="CENTER"},
164 hgroupc:SetPoint("TOPLEFT", gui.content, "TOPRIGHT", -200, 0) 384 {name="Realm",width=120,align="RIGHT"},
165 hgroupc:SetPoint("BOTTOMRIGHT", gui.content, "BOTTOMRIGHT") 385 {name="",width=50,DoCellUpdate=updateTableData}
166 386 },15,16,nil,lfgui);
167 if curRealmStat then addon:updateCurrentRealm() end 387
168 addon:updatePartyInfo() 388 lfgTable:RegisterEvents({OnEnter=ShowLfgInfo,OnLeave=HideTooltip,OnClick=JoinGroup})
169 addon:updateRecentRealms()]] 389
390 setupWidget(lfgTable.frame, nil, 10, 45);
391 lfgTable.frame:SetBackdrop(nil)
392 lfgui:SetPoint("CENTER",0,0)
393 refreshLFGList()
394
395 lbThrottle = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetWidth=300}, 50, 100)
396 lbThrottle:Hide();
397
398 local btRefresh = setupWidget(CreateFrame("Button",nil,lfgui,"UIPanelSquareButton"),{SetWidth=22,SetHeight=22},379,27)
399 btRefresh.icon:SetTexture("Interface/BUTTONS/UI-RefreshButton")
400 btRefresh.icon:SetTexCoord(0,1,0,1);
401 btRefresh:SetScript("OnClick",addon.refreshLfgCurrent)
402 end
403
404 function addon:CreateTabs()
405 local prevTab
406 for i=1,#lfgGroups do
407 local tab = CreateFrame("Button","$parentTab"..i,lfgui,"CharacterFrameTabButtonTemplate")
408 tab:SetText((C_LFGList.GetCategoryInfo(lfgGroups[i])));
409 tab.searchID = lfgGroups[i];
410 tab:SetID(i);
411 PanelTemplates_TabResize(tab, 0)
412 if i == 1 then
413 tab:SetPoint("TOPLEFT", lfgui, "BOTTOMLEFT", 10, 7)
414 lfgTabSelected = tab
415 PanelTemplates_SelectTab(tab)
416 else
417 tab:SetPoint("TOPLEFT", prevTab, "TOPRIGHT",-15,0)
418 PanelTemplates_DeselectTab(tab)
419 end
420 tab:SetScript("OnClick", SelectLfgTab)
421 tabs[i] = tab
422 prevTab = tab
423 end
170 end 424 end
171 425
172 -- LFG scanning routine 426 -- LFG scanning routine
173 427
174 --[[function addon.refreshLfgCurrent() 428 function addon.refreshLfgCurrent()
175 addon.LfgScan(nil,nil,curLfgGroup) 429 addon.LfgScan(curLfgGroup)
176 end 430 end
177 431
178 function addon.LfgScan(widget, callback, tab) 432 function addon.LfgScan(group)
179 if not tab then return end 433 if lfgTable then lfgTable:SetData({}) end
180 lfgScanInProgress = true 434 lfgScanInProgress = true
181 if lfgContainer then lfgContainer:ReleaseChildren() end 435 curLfgGroup = group
182 curLfgGroup = tab
183 C_LFGList.Search(curLfgGroup,"") 436 C_LFGList.Search(curLfgGroup,"")
184 end 437 end
185 438
186 function addon:LfgScanFailed(event, reason) 439 function addon:LfgScanFailed(event, reason)
187 print("scan failed "..reason)
188 if reason == "throttled" then 440 if reason == "throttled" then
189 addon:ScheduleTimer(addon.LfgScan, 2, nil, nil, curLfgGroup) 441 addon:ScheduleTimer(addon.LfgScan, 2, curLfgGroup)
190 end 442 lbThrottle:SetText("LFG scan is delayed (throttled).\nThis page will update automatically...")
191 end 443 else
192 444 lbThrottle:SetText("Scan failed ("..reason..")")
193 local function WeightLfgItem(item) 445 end
194 local leaderRealm = 3 446 lbThrottle:Show()
195 if (item.realm ~= "???") then leaderRealm = (5 - (recentRealms[item.realm] or 0)) end
196 local weight =
197 (item.autoinv and 5 or 2) *
198 ((item.friends > 0) and 2 or 3) *
199 ((item.ilvl > 0) and 2 or 3) *
200 ((item.voice ~= "") and 2 or 4)
201 local count = item.pcount;
202 local countWeight
203 if count >= 39 or count <= 1 then countWeight = 1
204 elseif count >= 35 or count <= 4 then countWeight = 2
205 elseif count >= 30 or count <= 10 then countWeight = 3
206 else countWeight = 4 end
207 return weight * leaderRealm * countWeight;
208 end 447 end
209 448
210 function addon:LfgResponseData() 449 function addon:LfgResponseData()
211 lfgScanInProgress = false; 450 lfgScanInProgress = false;
212 addon:UpdateCurrentLfgInfo() 451 if lbThrottle then lbThrottle:Hide() end
213 end 452 refreshLFGList()
214
215 function addon:UpdateCurrentLfgInfo(repeated)
216 if lfgScanInProgress then return end
217 local count, list = C_LFGList.GetSearchResults()
218 local lfgList = {}
219 local lfgEntries = 0
220 local hasUnknowns = false
221 for i = 1,count do
222 local rid = list[i];
223 if not rid then break end
224 local _, action, caption, desc, voice, ilvl, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(rid)
225 if not fullname then
226 fullname = "???-???"
227 hasUnknowns = true
228 end
229 if not delisted then
230 local pname, realm = strsplit(realmSep, fullname)
231 realm = realm or homeRealm
232 local item = {
233 rid=rid,
234 action=action,
235 caption=caption,
236 desc=desc,
237 ilvl=ilvl,
238 voice=voice,
239 time=time,
240 friends=bnetfr+charfr+guild,
241 name=pname,
242 realm = realm,
243 pcount=pcount,
244 autoinv=autoinv
245 }
246 item.weight = WeightLfgItem(item)
247 table.insert(lfgList, item)
248 lfgEntries = lfgEntries + 1
249 end
250 end
251 addon:refreshLFGList(lfgList, lfgEntries);
252 if hasUnknowns and repeated ~= true then addon:ScheduleTimer("UpdateCurrentLfgInfo", 1, true) end
253 end
254
255 function addon:refreshLFGList(list, count)
256 if not lfgContainer then return end
257 lfgContainer:PauseLayout()
258 lfgContainer:ReleaseChildren()
259 table.sort(list, addon.SortLfgItems)
260
261 local canJoin = addon.canJoinGroup()
262
263 for i=1,count do
264 local data = list[i];
265 local renderer = addon:AddUI(lfgContainer,"SimpleGroup",{SetLayout="Flow",SetHeight=20,SetAutoAdjustHeight=false});
266
267 addon:AddUI(renderer,"Label",{SetText=data.caption,SetRelativeWidth=0.4},true)
268 addon:AddUI(renderer,"Label",{SetText=data.pcount,SetRelativeWidth=0.05},true)
269 local realm = addon:AddUI(renderer,"Label",{SetText=data.realm,SetRelativeWidth=0.25},true)
270 if recentRealms[data.realm] then
271 local r,g,b = GetItemQualityColor(recentRealms[data.realm]);
272 realm:SetColor(r,g,b)
273 end
274
275 local tooltip = {}
276 if data.voice ~= "" then table.insert(tooltip,"Voice: "..data.voice) end
277 if data.friends > 0 then table.insert(tooltip,"Friends: "..data.friends) end
278 if data.ilvl > 0 then table.insert(tooltip,"Min. Ilvl: "..data.ilvl) end
279 addon:AddIcon(renderer, "Interface/GossipFrame/ActiveQuestIcon", 16, tooltip[1] ~= nil, tooltip)
280 addon:AddIcon(renderer, READY_CHECK_READY_TEXTURE, 16, data.autoinv, {"Auto invite!"})
281 local btn = addon:AddUI(renderer,"Button",{SetText="Join",SetRelativeWidth=0.2,SetHeight=20,SetDisabled=not canJoin},true,{OnClick=addon.joinGroup})
282 btn:SetUserData('rid',data.rid)
283 end
284 addon:AddUI(lfgContainer,"Button",{SetText="Refresh",SetWidth=100,SetHeight=20},true,{OnClick=addon.refreshLfgCurrent})
285
286 lfgContainer:ResumeLayout()
287 lfgContainer:DoLayout()
288 end
289
290 function addon.SortLfgItems(a,b)
291 return a.weight > b.weight
292 end
293
294 function addon.canJoinGroup()
295 return (not IsInGroup()) or (UnitIsGroupLeader('player') and not IsInRaid())
296 end
297
298 function addon.joinGroup(widget)
299 if not addon.canJoinGroup() then return end
300 local rid = widget:GetUserData('rid');
301 widget:SetDisabled(true)
302 C_LFGList.ApplyToGroup(rid, "", C_LFGList.GetAvailableRoles())
303 end 453 end
304 454
305 function addon:updateAppStatus(event, id, status, oldstatus) 455 function addon:updateAppStatus(event, id, status, oldstatus)
306 if status == "invited" then 456 if status == "invited" then
307 LFGListInviteDialog_Accept(LFGListInviteDialog) 457 LFGListInviteDialog_Accept(LFGListInviteDialog)
308 end 458 end
309 end]] 459 addon:UpdateAutoButtonStatus()
310 460 addon:SetGroupJoinStatus(id, status)
311 -- Zone scanning routine 461 end
312 462
313 function addon:LeaveCombat() 463 function addon:SetGroupJoinStatus(id, status)
314 addon:UnregisterEvent("PLAYER_REGEN_ENABLED") 464 local name = select(12, C_LFGList.GetSearchResultInfo(id))
315 scanstate = 0 465 recentgroups[name] = {status=status, time=GetTime()}
316 addon:ScanRealm();
317 end
318
319 function addon:ForceRefreshZone()
320 addon:RefreshZone(true)
321 end
322
323 function addon:RefreshZone(shedule)
324 local inst, instType = IsInInstance()
325 if (inst or instType ~= "none") then
326 lbRealm:SetText("Instanced zone")
327 curRealmStat = nil
328 btQuick:Disable()
329 else
330 btQuick:Enable()
331 if scanstate == 0 then
332 addon:ScanRealm()
333 elseif shedule == true and scanstate == 2 then
334 addon:SetStatus("Rescan sheduled...")
335 scanstate = 3
336 end
337 end
338 end
339
340 function addon:ScanRealm()
341 if scanstate > 0 then return end
342 if InCombatLockdown() then
343 addon:RegisterEvent("PLAYER_REGEN_ENABLED","LeaveCombat")
344 scanstate = 1
345 addon:SetStatus("Scan sheduled after combat...");
346 return
347 end
348 scanstate = 2
349 addon:SetStatus("Scanning current realm...");
350 local searchString = _G.WHO_TAG_ZONE .. '"' .. GetZoneText() .. '"';
351 wholib:Who(searchString, {callback = "ScanResult", handler=addon})
352 end
353
354 function addon:ScanResult(query, results, complete)
355 local realms = {}
356 for _, player in ipairs(results) do
357 addon:AddRealmStat(player.Name, realms);
358 end
359 curRealmStat = addon:GetRealmStat(realms);
360 curRealmStat.complete = complete
361 addon:updateCurrentRealm();
362 local rescan = scanstate == 3
363 scanstate = 0;
364 if rescan then addon:ScanRealm() end
365 end
366
367 function addon:AddRealmStat(name, realms)
368 if (name == playerName) then return end
369 local _, realm = strsplit(realmSep, name)
370 realm = realm or homeRealm
371 realms[realm] = (realms[realm] or 0) + 1
372 end
373
374 function addon:AddUnitIdStat(unitid, realms)
375 local name, realm = UnitName(unitid);
376 if not name then return end
377 if realm == "" then realm = homeRealm end
378 realm = realm or homeRealm
379 realms[realm] = (realms[realm] or 0) + 1
380 end
381
382 function addon:GetRealmStat(realms)
383 local rcount = 0;
384 local stat = {};
385 local pcount = 0;
386 for realm,count in pairs(realms) do
387 table.insert(stat,{realm=realm,count=count})
388 rcount = rcount + 1;
389 pcount = pcount + count;
390 end
391 if rcount > 1 then
392 table.sort(stat, function(a,b) return a.count > b.count end)
393 stat.max = stat[1].count
394 else stat.max = 0 end
395 stat.players = pcount;
396 stat.realms = rcount;
397 return stat;
398 end
399
400 function addon:updateCurrentRealm()
401 addon:SetStatus();
402 if not curRealmStat or curRealmStat.realms < 1 then
403 lbRealm:SetText("Unknown realm (No players)")
404 return;
405 end
406
407 local bestRealm = curRealmStat[1]
408 local prevThreshold = math.min(bestRealm.count/3,5)
409 local mixCount = 0
410 for i=2,curRealmStat.realms do
411 local data = curRealmStat[i]
412 if data.count >= prevThreshold then
413 mixCount = mixCount + 1
414 prevThreshold = math.min(data.count/3,5)
415 end
416 end
417 curRealmStat.threshold = prevThreshold
418
419 if (mixCount > 0) then
420 lbRealm:SetText("Mixed "..bestRealm.realm.." +"..mixCount)
421 else
422 lbRealm:SetText(bestRealm.realm)
423 end
424 end
425
426 function addon:realmToolip()
427 if not curRealmStat then return end
428 local players = curRealmStat.players;
429 local threshold = curRealmStat.threshold
430 GameTooltip:AddLine("Players in zone: "..players)
431 if not curRealmStat.complete then
432 GameTooltip:AppendText("+")
433 end
434 for i=1,curRealmStat.realms do
435 local data = curRealmStat[i]
436 local percent = math.ceil(100 * data.count / players - 0.5) .. "%";
437 if data.count >= threshold then
438 GameTooltip:AddDoubleLine(data.realm, percent, 0,1,0,0,1,0)
439 else
440 GameTooltip:AddDoubleLine(data.realm, percent, 0.5,0.5,0.5,0.5,0.5,0.5)
441 end
442 end
443 end
444
445 --[[function addon:addLabels(container, stats, epict, whitet, grayt, emptytext)
446 if stats.realms == 0 then
447 addon:AddLabel(container, emptytext)
448 else
449 local players = stats.players
450 local pleft = players;
451 for i=1,stats.realms do
452 local data = stats[i]
453 local count = data.count;
454 local percent = math.ceil(100 * count / players - 0.5)
455 local label = data.realm .. " (" .. percent .. "%)";
456 local color
457 if count < grayt then break
458 elseif count < whitet then color = 1
459 elseif count < epict then color = 2
460 else color = 4 end
461 pleft = pleft - count
462 addon:AddLabel(container, label, color);
463 end
464 if pleft > 0 then
465 addon:AddLabel(container, "Other" .. " (" .. math.ceil(100 * pleft / players - 0.5) .. "%)", 0);
466 end
467 end
468 end
469
470 function addon:updateRecentRealms()
471 if not recrealm then return end
472 recrealm:ReleaseChildren()
473 local nothing = true;
474 for realm,color in pairs(recentRealms) do
475 addon:AddLabel(recrealm, realm,color);
476 nothing = false;
477 end
478 if nothing then
479 addon:AddLabel(recrealm, "No recent realms");
480 end
481 end
482
483 function addon:ClearRecentRealms()
484 recentRealms = {}
485 addon:UpdateCurrentLfgInfo()
486 addon:updateRecentRealms()
487 end 466 end
488 467
489 function addon:updatePartyInfo() 468 function addon:updatePartyInfo()
490 if not partyrealm then return end
491 partyrealm:ReleaseChildren()
492 local realms = {} 469 local realms = {}
493 local inGroup = IsInGroup() 470 local inGroup = IsInGroup()
494 if IsInGroup() then 471 if inGroup then
495 if IsInRaid() then 472 if IsInRaid() then
496 for i=1, MAX_RAID_MEMBERS do 473 for i=1, MAX_RAID_MEMBERS do
497 addon:AddUnitIdStat("raid"..i, realms) 474 addon:AddUnitIdStat("raid"..i, realms)
498 end 475 end
499 else 476 else
501 addon:AddUnitIdStat("party"..i, realms) 478 addon:AddUnitIdStat("party"..i, realms)
502 end 479 end
503 end 480 end
504 end 481 end
505 if inGroup ~= wasInGroup then 482 if inGroup ~= wasInGroup then
506 addon:SheduleScan() 483 addon:ForceRefreshZone()
507 wasInGroup = inGroup 484 wasInGroup = inGroup
508 addon:UpdateCurrentLfgInfo() 485 addon:UpdateAutoButtonStatus()
509 leavebtn:SetDisabled(not inGroup) 486 end
510 end 487 end
511 local partyStat = addon:GetRealmStat(realms); 488
512 addon:addLabels(partyrealm, partyStat, partyStat.players/2, 2, 0, "Not in party"); 489
513 end]] 490
491
492 -- Zone scanning routine
493
494 function addon:LeaveCombat()
495 addon:UnregisterEvent("PLAYER_REGEN_ENABLED")
496 scanstate = 0
497 addon:ScanRealm();
498 end
499
500 function addon:ForceRefreshZone()
501 addon:RefreshZone(true)
502 end
503
504 function addon:RefreshZone(shedule)
505 local inst, instType = IsInInstance()
506 inInstance = (inst or instType ~= "none")
507 if inInstance then
508 lbRealm:SetText("Instanced zone")
509 curRealmStat = nil
510 inInstance = true
511 else
512 inInstance = false;
513 if scanstate == 0 then
514 addon:ScanRealm()
515 elseif shedule == true and scanstate == 2 then
516 addon:SetStatus("Rescan sheduled...")
517 scanstate = 3
518 end
519 end
520 addon:UpdateAutoButtonStatus()
521 end
522
523 function addon:ScanRealm()
524 if scanstate > 0 then return end
525 if InCombatLockdown() then
526 addon:RegisterEvent("PLAYER_REGEN_ENABLED","LeaveCombat")
527 scanstate = 1
528 addon:SetStatus("Scan sheduled after combat...");
529 return
530 end
531 scanstate = 2
532 addon:SetStatus("Scanning current realm...");
533 local searchString = _G.WHO_TAG_ZONE .. '"' .. GetZoneText() .. '"';
534 wholib:Who(searchString, {callback = "ScanResult", handler=addon})
535 end
536
537 function addon:ScanResult(query, results, complete)
538 local realms = {}
539 for _, player in ipairs(results) do
540 addon:AddRealmStat(player.Name, realms);
541 end
542 curRealmStat = addon:GetRealmStat(realms);
543 curRealmStat.complete = complete
544 addon:updateCurrentRealm();
545 local rescan = scanstate == 3
546 scanstate = 0;
547 if rescan then addon:ScanRealm() end
548 end
549
550 function addon:AddRealmStat(name, realms)
551 if (name == playerName) then return end
552 local _, realm = strsplit(realmSep, name)
553 realm = realm or homeRealm
554 realms[realm] = (realms[realm] or 0) + 1
555 end
556
557 function addon:AddUnitIdStat(unitid, realms)
558 local name, realm = UnitName(unitid);
559 if not name then return end
560 if realm == "" then realm = homeRealm end
561 realm = realm or homeRealm
562 realms[realm] = (realms[realm] or 0) + 1
563 end
564
565 function addon:GetRealmStat(realms)
566 local rcount = 0;
567 local stat = {};
568 local pcount = 0;
569 for realm,count in pairs(realms) do
570 table.insert(stat,{realm=realm,count=count})
571 rcount = rcount + 1;
572 pcount = pcount + count;
573 end
574 if rcount > 1 then
575 table.sort(stat, function(a,b) return a.count > b.count end)
576 stat.max = stat[1].count
577 else stat.max = 0 end
578 stat.players = pcount;
579 stat.realms = rcount;
580 return stat;
581 end
582
583 function addon:updateCurrentRealm()
584 addon:SetStatus();
585 if not curRealmStat or curRealmStat.realms < 1 then
586 lbRealm:SetText("Unknown realm (No players)")
587 return;
588 end
589
590 local bestRealm = curRealmStat[1]
591 local prevThreshold = math.min(bestRealm.count/3,10)
592 local mixCount = 0
593 for i=2,curRealmStat.realms do
594 local data = curRealmStat[i]
595 if data.count >= prevThreshold then
596 mixCount = mixCount + 1
597 prevThreshold = math.min(data.count/3,10)
598 end
599 end
600 curRealmStat.threshold = prevThreshold
601
602 if (mixCount > 0) then
603 lbRealm:SetText("Mixed "..bestRealm.realm.." +"..mixCount)
604 else
605 lbRealm:SetText(bestRealm.realm)
606 end
607 end
608
609
610
611
612
613
614 -- Auto action button
615
616 local action;
617
618 local function CancelJoin()
619 local apps = C_LFGList.GetApplications();
620 if apps[1] then
621 C_LFGList.CancelApplication(apps[1])
622 end
623 end
624
625 local function findGroupToJoin()
626 local count, list = C_LFGList.GetSearchResults()
627 local tableData = {}
628 for i = 1,count do
629 local rid = list[i];
630 if not rid then break end
631 local _, action, caption, desc, voice, ilvl, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(rid)
632
633 local data = list[i];
634 local cols = {}
635 local row = {rid}
636 cols[1] = {value=updateGroupName,args=row}
637 cols[2] = {value=updateGroupCount,args=row}
638 cols[3] = {value=updateGroupRealm,args=row}
639 cols[4] = {}
640 table.insert(tableData, {cols=cols,id=rid})
641
642 end
643 end
644
645 local function QuickJoin()
646
647 end
648
649 function addon:DoAutoAction()
650 if action then action() end
651 addon:UpdateAutoButtonStatus()
652 end
653
654 function addon:UpdateAutoButtonStatus()
655 btQuick:Enable()
656 if IsInGroup() then
657 action = LeaveParty;
658 btQuick:SetText("Leave group")
659 elseif C_LFGList.GetNumApplications() > 0 then
660 action = CancelJoin;
661 btQuick:SetText("Cancel join")
662 else
663 if inInstance then btQuick:Disable() end
664 btQuick:SetText("Quick join")
665 end
666 end