local GlobalAddonName, ExRT = ... local module = ExRT:New("RaidGroups",ExRT.L.RaidGroups) local ELib,L = ExRT.lib,ExRT.L local LibDeflate = LibStub:GetLibrary("LibDeflate") local UnitGroupRolesAssigned = UnitGroupRolesAssigned or ExRT.NULLfunc local VMRT = nil function module.main:ADDON_LOADED() VMRT = _G.VMRT VMRT.RaidGroups = VMRT.RaidGroups or {} VMRT.RaidGroups.profiles = VMRT.RaidGroups.profiles or {} if not VMRT.RaidGroups.upd4550 then VMRT.RaidGroups.KeepPosInGroup = true VMRT.RaidGroups.upd4550 = true end module:RegisterSlash() end function module.options:Load() self:CreateTilte() local function EditOnDragStart(self) if self:IsMovable() then self:StartMoving() end end local function EditOnDragStop(self) self:StopMovingOrSizing() for i=1,#module.options.edits do local edit2 = module.options.edits[i] if edit2:IsMouseOver() and edit2 ~= self then local textSelf = self:GetText() local textMO = edit2:GetText() self:SetText(textMO) edit2:SetText(textSelf) self:SetCursorPosition(1) edit2:SetCursorPosition(1) break end end self:NewPoint("TOPLEFT",module.options,10+((self.index-1) % 10 < 5 and 0 or 165),-40-((self.index-1) % 5)*22-floor((self.index-1)/10)*132) self:ClearFocus() end local function EditOnDragStopNotInList(self) self:StopMovingOrSizing() for i=1,#module.options.edits do local edit2 = module.options.edits[i] if edit2:IsMouseOver() and edit2 ~= self then local textSelf = self.preName or self:GetText() edit2:SetText(textSelf) edit2:SetCursorPosition(1) break end end self:NewPoint("TOPLEFT",module.options,355,-40-(self.index-1)*14) self:ClearFocus() module.options:UpdateNotInList() end local function EditOnChange(self,isUser) local name = self:GetText() if name and UnitName(name) then local r,g,b = ExRT.F.classColorNum(select(2,UnitClass(name))) self:SetTextColor(r,g,b,1) self:ColorBorder() elseif self.preclass then local r,g,b = ExRT.F.classColorNum(self.preclass) self:SetTextColor(r,g,b,1) self:ColorBorder() else self:SetTextColor(.7,.7,.7,1) if name and #name > 0 then self:ColorBorder(0.5,0.25,0.3,1) else self:ColorBorder() end end if name and UnitName(name) and UnitGroupRolesAssigned(name) then local role = UnitGroupRolesAssigned(name) if role == "HEALER" then self.roleIcon:SetAtlas("groupfinder-icon-role-large-heal") self.roleIcon:Show() elseif role == "DAMAGER" then self.roleIcon:SetAtlas("groupfinder-icon-role-large-dps") self.roleIcon:Show() elseif role == "TANK" then self.roleIcon:SetAtlas("groupfinder-icon-role-large-tank") self.roleIcon:Show() else self.roleIcon:Hide() end else self.roleIcon:Hide() end if isUser then module.options:UpdateNotInList() end end function self:UpdateTextColors() for i=1,40 do EditOnChange(self.edits[i],false) end end self.edits = {} for i=1,40 do local edit = ELib:Edit(self):Size(150,18) self.edits[i] = edit edit:SetText(i) edit.index = i edit:Point("TOPLEFT",10+((i-1) % 10 < 5 and 0 or 165),-40-((i-1) % 5)*22-floor((i-1)/10)*132):OnChange(EditOnChange) edit.roleIcon = edit:CreateTexture(nil, "BACKGROUND") edit.roleIcon:SetPoint("RIGHT") edit.roleIcon:SetSize(16,16) edit.roleIcon:Hide() edit:SetMovable(true) edit:RegisterForDrag("LeftButton") edit:SetScript("OnDragStart", EditOnDragStart) edit:SetScript("OnDragStop", EditOnDragStop) end for i=1,4 do for j=1,2 do ELib:Text(self,GROUP.." "..((i-1)*2+j)):Point("TOPLEFT",10+(j == 1 and 0 or 165)+3,-40-(i-1)*132+14):Color():Shadow() end end ELib:Text(self,L.RaidGroupsTextMovable,8):Point("TOPLEFT",12,-547):Color():Shadow() self.scrollNotInList = ELib:ScrollBar(self):Point("TOPLEFT",478,-40):Size(12,558):SetMinMaxValues(0,1):SetValue(0):SetObey(true):OnChange(function() self:UpdateNotInList() end) self.edits_notinlist = {} function self:UpdateNotInList() local inList,notInList = {},{} local scrollShow for i=1,40 do local name = module.options.edits[i]:GetText() if name then inList[name] = true end end if self.isGuild then local myLvl = UnitLevel("player") local guildList = {} for i=1, GetNumGuildMembers() do local name, _, rankIndex, level, _, _, _, _, _, _, class = GetGuildRosterInfo(i) if select(2,strsplit("-",name)) == ExRT.SDB.realmKey then name = strsplit("-",name) end if not inList[name] and (level or 0) >= myLvl then guildList[#guildList+1] = {name,class,rankIndex,"|cffbbbbbb["..rankIndex.."]|r "..name} end end sort(guildList,function(a,b) if a[3] == b[3] then return a[1] < b[1] else return a[3] < b[3] end end) local start = floor(self.scrollNotInList:GetValue()+0.5) for i=start+1,#guildList do notInList[#notInList+1] = guildList[i] end if #guildList > 40 then scrollShow = #guildList - 40 end else for i=1,GetNumGroupMembers() do local name = GetRaidRosterInfo(i) if not inList[name] then notInList[#notInList+1] = name end end end if scrollShow then self.scrollNotInList:SetMinMaxValues(0,scrollShow) end self.scrollNotInList:SetShown(scrollShow and true or false) for i=1,min(#notInList,40) do local edit = self.edits_notinlist[i] if not edit then edit = ELib:Edit(self):Size(120,12) self.edits_notinlist[i] = edit edit.index = i edit:Point("TOPLEFT",355,-40-(i-1)*14):OnChange(EditOnChange) edit.roleIcon = edit:CreateTexture(nil, "BACKGROUND") edit.roleIcon:SetPoint("RIGHT") edit.roleIcon:SetSize(10,10) edit.roleIcon:Hide() edit:SetFont(edit:GetFont(),10,"") edit:SetEnabled(false) edit:SetMovable(true) edit:RegisterForDrag("LeftButton") edit:SetScript("OnDragStart", EditOnDragStart) edit:SetScript("OnDragStop", EditOnDragStopNotInList) end if type(notInList[i]) == "table" then edit:SetText("") edit:SetText(notInList[i][4]) edit.preclass = notInList[i][2] edit.preName = notInList[i][1] else edit:SetText("") edit:SetText(notInList[i]) edit.preclass = nil edit.preName = nil end edit:SetCursorPosition(1) edit:Show() end for i=#notInList+1,#self.edits_notinlist do self.edits_notinlist[i]:Hide() end end self.chk_raid = ELib:Radio(self,RAID,true):Point("TOPLEFT",355,-20):OnClick(function(self) module.options.isGuild = false self:SetChecked(true) module.options.chk_guild:SetChecked(false) module.options:UpdateNotInList() end) self.chk_guild = ELib:Radio(self,GUILD):Point("BOTTOM",self.chk_raid,"TOP",0,-2):OnClick(function(self) module.options.isGuild = true self:SetChecked(true) module.options.chk_raid:SetChecked(false) C_GuildInfo.GuildRoster() module.options:UpdateNotInList() C_Timer.After(1,function() module.options:UpdateNotInList() end) end) self.updateRoster = ELib:Button(self,L.RaidGroupsCurrentRoster):Size(315,20):Point("TOPLEFT",10,-565):OnClick(function() local roster = {} for i=1,8 do roster[i] = {} end for i=1,GetNumGroupMembers() do local name, rank, subgroup = GetRaidRosterInfo(i) tinsert(roster[subgroup],name) end for i=1,8 do for j=1,5 do local edit = module.options.edits[(i-1)*5+j] edit:SetText(roster[i][j] or "") edit:SetCursorPosition(1) end end module.options:UpdateNotInList() end) self.processRoster = ELib:Button(self,L.RaidGroupsSetGroups):Size(315,30):Point("TOP",self.updateRoster,"BOTTOM",0,-5):OnClick(function(self) local list = {} for i=1,40 do list[i] = module.options.edits[i]:GetText() end module:ApplyGroups(list) end) self.keepPosCheck = ELib:Check(self,L.RaidGroupsKeepPosInGroup,VMRT.RaidGroups.KeepPosInGroup):Point("BOTTOMLEFT",self.processRoster,"BOTTOMRIGHT",5,0):OnClick(function(self) if self:GetChecked() then VMRT.RaidGroups.KeepPosInGroup = true else VMRT.RaidGroups.KeepPosInGroup = nil end end):Shown(ExRT.isClassic) self.presetList = ELib:ScrollList(self):Size(190,505):Point("TOPRIGHT",-10,-40):AddDrag() ELib:Text(self,L.RaidGroupsQuickLoad..":"):Point("BOTTOMLEFT",self.presetList,"TOPLEFT",5,3):Color():Shadow() self.presetList.ButtonRemove = CreateFrame("Button",nil,self.presetList) self.presetList.ButtonRemove:Hide() self.presetList.ButtonRemove:SetSize(8,8) self.presetList.ButtonRemove:SetScript("OnClick",function(self) for i=#VMRT.RaidGroups.profiles,1,-1 do local entry = VMRT.RaidGroups.profiles[i] if entry == self.data then tremove(VMRT.RaidGroups.profiles,i) break end end module.options:UpdateList() end) self.presetList.ButtonRemove:SetScript("OnEnter",function(self) GameTooltip:SetOwner(self,"ANCHOR_RIGHT") GameTooltip:AddLine(DELETE) GameTooltip:Show() end) self.presetList.ButtonRemove:SetScript("OnLeave",function(self) GameTooltip_Hide() end) self.presetList.ButtonRemove.i = self.presetList.ButtonRemove:CreateTexture() self.presetList.ButtonRemove.i:SetPoint("CENTER") self.presetList.ButtonRemove.i:SetSize(16,16) self.presetList.ButtonRemove.i:SetTexture("Interface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128") self.presetList.ButtonRemove.i:SetTexCoord(0.5,0.5625,0.5,0.625) self.presetList.ButtonRemove.i:SetVertexColor(.8,0,0,1) function self.presetList:SetListValue(index) local data = self.L[index][2] for i=1,40 do local edit = module.options.edits[i] if data[i] then edit:SetText(data[i]) edit:SetCursorPosition(1) else edit:SetText("") end end module.options:UpdateNotInList() module.options.presetList.selected = nil module.options.presetList:Update() end function self.presetList:HoverListValue(isEnter,index,obj) if not isEnter then GameTooltip_Hide() if not self.ButtonRemove:IsMouseOver() then self.ButtonRemove:Hide() end else local data = obj.table[2] GameTooltip:SetOwner(obj,"ANCHOR_CURSOR") GameTooltip:AddLine(data.name) GameTooltip:AddLine(date("%x %X",data.time)) GameTooltip:Show() self.ButtonRemove.data = data self.ButtonRemove:SetPoint("RIGHT",obj,"RIGHT",-5,0) self.ButtonRemove:SetParent(obj) self.ButtonRemove:Show() end end function self.presetList:OnDragFunction(obj1,obj2) local data1,data2 = obj1.table[2],obj2.table[2] local tmp if obj1.index < obj2.index then for i=#VMRT.RaidGroups.profiles,1,-1 do if VMRT.RaidGroups.profiles[i] == data1 then tmp = VMRT.RaidGroups.profiles[i] VMRT.RaidGroups.profiles[i] = VMRT.RaidGroups.profiles[i-1] elseif VMRT.RaidGroups.profiles[i] == data2 then VMRT.RaidGroups.profiles[i] = tmp break elseif tmp then VMRT.RaidGroups.profiles[i] = VMRT.RaidGroups.profiles[i-1] end end else for i=1,#VMRT.RaidGroups.profiles do if VMRT.RaidGroups.profiles[i] == data1 then tmp = VMRT.RaidGroups.profiles[i] VMRT.RaidGroups.profiles[i] = VMRT.RaidGroups.profiles[i+1] elseif VMRT.RaidGroups.profiles[i] == data2 then VMRT.RaidGroups.profiles[i] = tmp break elseif tmp then VMRT.RaidGroups.profiles[i] = VMRT.RaidGroups.profiles[i+1] end end end module.options:UpdateList() end function self:UpdateList() local list = {} for i=#VMRT.RaidGroups.profiles,1,-1 do local entry = VMRT.RaidGroups.profiles[i] list[#list+1] = {entry.name,entry} end module.options.presetList.L = list module.options.presetList:Update() end local function SaveData(_,name) if not name or string.trim(name) == "" then return end local new = { name = name, time = time(), } for i=1,40 do local text = module.options.edits[i]:GetText() if text and string.trim(text) ~= "" then new[i] = text end end VMRT.RaidGroups.profiles[#VMRT.RaidGroups.profiles+1] = new module.options:UpdateList() end local function SaveInputOnEdit(self) local text = self:GetText() if text and string.trim(text) ~= "" then self:GetParent().OK:Enable() else self:GetParent().OK:Disable() end end self.presetListSave = ELib:Button(self,L.RaidGroupsSave):Size(192,20):Point("TOP",self.presetList,"BOTTOM",0,-5):OnClick(function(self) ExRT.F.ShowInput(L.RaidGroupsEnterName,SaveData,nil,nil,nil,SaveInputOnEdit) end) self.importWindow, self.exportWindow = ExRT.F.CreateImportExportWindows() do self.importWindow:SetHeight(180) self.importWindow.Edit:Point("TOP",0,-100) ELib:DecorationLine(self.importWindow):Point("TOPLEFT",0,-17):Point("BOTTOMRIGHT",'x',"TOPRIGHT",0,-18) ELib:DecorationLine(self.importWindow):Point("TOPLEFT",0,-95):Point("BOTTOMRIGHT",'x',"TOPRIGHT",0,-96) local importWindow = self.importWindow local function ButtonOnClick(self) local index = 1 local c = importWindow["c"..index] while c do c:Enable() if self == c then importWindow.importType = index VMRT.RaidGroups.importType = index end index = index + 1 c = importWindow["c"..index] end self:Disable() end local function CreateButton() local self = ELib:Template("ExRTButtonTransparentTemplate",importWindow) self:SetSize(importWindow:GetWidth()/4,77) self.DisabledTexture = self:CreateTexture() self.DisabledTexture:SetColorTexture(0.20,0.21,0.25,0.5) self.DisabledTexture:SetPoint("TOPLEFT") self.DisabledTexture:SetPoint("BOTTOMRIGHT") self:SetDisabledTexture(self.DisabledTexture) self:SetScript("OnClick",ButtonOnClick) return self end importWindow.c1 = CreateButton() importWindow.c1:SetPoint("TOPLEFT",0,-18) importWindow.c1:SetText("G1 G2\nG3 G4\nG5 G6\nG7 G8") importWindow.c2 = CreateButton() importWindow.c2:SetPoint("LEFT",importWindow.c1,"RIGHT",0,0) importWindow.c2:SetText("G1 G2 G3 G4 G5") importWindow.c3 = CreateButton() importWindow.c3:SetPoint("LEFT",importWindow.c2,"RIGHT",0,0) importWindow.c3:SetText("G1\nG2\nG3\nG4\nG5") importWindow.c4 = CreateButton() importWindow.c4:SetPoint("LEFT",importWindow.c3,"RIGHT",0,0) importWindow.c4:SetText("From ExRT export string") local importType = VMRT.RaidGroups.importType or 4 local c = importWindow["c"..importType] if c then c:Click() end end do self.exportWindow:SetHeight(130) self.exportWindow.Edit:Point("TOP",0,-100) ELib:DecorationLine(self.exportWindow):Point("TOPLEFT",0,-17):Point("BOTTOMRIGHT",'x',"TOPRIGHT",0,-18) ELib:DecorationLine(self.exportWindow):Point("TOPLEFT",0,-95):Point("BOTTOMRIGHT",'x',"TOPRIGHT",0,-96) local exportWindow = self.exportWindow local function ButtonOnClick(self) local index = 1 local c = exportWindow["c"..index] while c do c:Enable() if self == c then exportWindow.exportType = index VMRT.RaidGroups.exportType = index end index = index + 1 c = exportWindow["c"..index] end self:Disable() module.options:RecordToText() if exportWindow:IsShown() then exportWindow.Edit:SetFocus() exportWindow.Edit:HighlightText() end end local function CreateButton() local self = ELib:Template("ExRTButtonTransparentTemplate",exportWindow) self:SetSize(exportWindow:GetWidth()/4,77) self.DisabledTexture = self:CreateTexture() self.DisabledTexture:SetColorTexture(0.20,0.21,0.25,0.5) self.DisabledTexture:SetPoint("TOPLEFT") self.DisabledTexture:SetPoint("BOTTOMRIGHT") self:SetDisabledTexture(self.DisabledTexture) self:SetScript("OnClick",ButtonOnClick) return self end exportWindow.c1 = CreateButton() exportWindow.c1:SetPoint("TOPLEFT",0,-18) exportWindow.c1:SetText("G1 G2\nG3 G4\nG5 G6\nG7 G8") exportWindow.c2 = CreateButton() exportWindow.c2:SetPoint("LEFT",exportWindow.c1,"RIGHT",0,0) exportWindow.c2:SetText("G1 G2 G3 G4 G5") exportWindow.c3 = CreateButton() exportWindow.c3:SetPoint("LEFT",exportWindow.c2,"RIGHT",0,0) exportWindow.c3:SetText("G1\nG2\nG3\nG4\nG5") exportWindow.c4 = CreateButton() exportWindow.c4:SetPoint("LEFT",exportWindow.c3,"RIGHT",0,0) exportWindow.c4:SetText("MRT export string") local exportType = VMRT.RaidGroups.exportType or 4 local c = exportWindow["c"..exportType] if c then c:Disable() end exportWindow.exportType = exportType end local function SaveDataFromTable(rec,name) if not name or string.trim(name) == "" then return end rec.name = name rec.time = time() VMRT.RaidGroups.profiles[#VMRT.RaidGroups.profiles+1] = rec module.options:UpdateList() end function self.importWindow:ImportFunc(str) if self.importType == 4 then local headerLen = str:sub(1,4) == "EXRT" and 8 or 7 local header = str:sub(1,headerLen) if (header:sub(1,headerLen-1) ~= "EXRTRGR" and header:sub(1,headerLen-1) ~= "MRTRGR") or (header:sub(headerLen,headerLen) ~= "0" and header:sub(headerLen,headerLen) ~= "1") then StaticPopupDialogs["EXRT_RAIDGROUP_IMPORT"] = { text = "|cffff0000"..ERROR_CAPS.."|r "..L.ProfilesFail3, button1 = OKAY, timeout = 0, whileDead = true, hideOnEscape = true, preferredIndex = 3, } StaticPopup_Show("EXRT_RAIDGROUP_IMPORT") return end module.options:TextToRecord(str:sub(headerLen+1),header:sub(headerLen,headerLen)=="0") elseif self.importType == 1 then local res = {} local group = 1 local posInGroup = 0 local lines = {strsplit("\n",str)} for i=1,#lines do local left,right = strsplit(" ",lines[i]:gsub(" +"," "):gsub('"',''),nil) if left and left:trim() ~= "" then left = left:trim() else left = nil end if right and right:trim() ~= "" then right = right:trim() else right = nil end posInGroup = posInGroup + 1 if posInGroup > 5 and (left or right) then posInGroup = 1 group = group + 2 end if posInGroup <= 5 and group <= 8 then res[(group-1)*5+posInGroup] = left res[(group-0)*5+posInGroup] = right end end ExRT.F.ShowInput(L.RaidGroupsEnterName,SaveDataFromTable,res,nil,nil,SaveInputOnEdit) elseif self.importType == 3 then local res = {} local group = 1 local posInGroup = 0 local lines = {strsplit("\n",str)} for i=1,#lines do local left = lines[i] if left and left:trim() ~= "" then left = left:trim():gsub('"','') else left = nil end posInGroup = posInGroup + 1 if posInGroup > 5 and left then posInGroup = 1 group = group + 1 end if posInGroup <= 5 and group <= 8 then res[(group-1)*5+posInGroup] = left end end ExRT.F.ShowInput(L.RaidGroupsEnterName,SaveDataFromTable,res,nil,nil,SaveInputOnEdit) elseif self.importType == 2 then local res = {} local lines = {strsplit("\n",str)} for i=1,#lines do local group = 0 local name,line = strsplit(" ",lines[i]:gsub(" +"," "):gsub('"',''),2) while name do group = group + 1 if i <= 5 and group <= 8 then res[(group-1)*5+i] = name:trim() end if line then name,line = strsplit(" ",line,2) else break end end end ExRT.F.ShowInput(L.RaidGroupsEnterName,SaveDataFromTable,res,nil,nil,SaveInputOnEdit) end end function self:TextToRecord(str,uncompressed) local decoded = LibDeflate:DecodeForPrint(str) local decompressed if uncompressed then decompressed = decoded else decompressed = LibDeflate:DecompressDeflate(decoded) end decoded = nil local _,tableData = strsplit(",",decompressed,2) decompressed = nil local successful, res = pcall(ExRT.F.TextToTable,tableData) if ExRT.isDev then module.db.lastImportDB = res if module.db.exportTable and type(res)=="table" then module.db.diffTable = {} print("Compare table",ExRT.F.table_compare(res,module.db.exportTable,module.db.diffTable)) end end if successful and res then ExRT.F.ShowInput(L.RaidGroupsEnterName,SaveDataFromTable,res,nil,nil,SaveInputOnEdit) else StaticPopupDialogs["EXRT_RAIDGROUP_IMPORT"] = { text = L.ProfilesFail1..(res and "\nError code: "..res or ""), button1 = OKAY, timeout = 0, whileDead = true, hideOnEscape = true, preferredIndex = 3, } StaticPopup_Show("EXRT_RAIDGROUP_IMPORT") end end function self:RecordToText() local new = {} for i=1,40 do local text = module.options.edits[i]:GetText() if text and string.trim(text) ~= "" then new[i] = text end end local exportWindow = module.options.exportWindow if exportWindow.exportType == 1 then local text = "" for i=1,8,2 do for j=1,5 do text = text .. (new[(i-1)*5+j] or "") .. "\t" .. (new[(i-0)*5+j] or "") .. "\n" end end exportWindow.Edit:SetText(text) elseif exportWindow.exportType == 2 then local text = "" for j=1,5 do for i=1,8 do text = text .. (new[(i-1)*5+j] or "") .. "\t" end text = text .. "\n" end exportWindow.Edit:SetText(text) elseif exportWindow.exportType == 3 then local text = "" for i=1,8 do for j=1,5 do text = text .. (new[(i-1)*5+j] or "") .. "\n" end end exportWindow.Edit:SetText(text) else local strlist = ExRT.F.TableToText(new) strlist[1] = "0,"..strlist[1] local str = table.concat(strlist) local compressed if #str < 1000000 then compressed = LibDeflate:CompressDeflate(str,{level = 5}) end local encoded = "MRTRGR"..(compressed and "1" or "0")..LibDeflate:EncodeForPrint(compressed or str) ExRT.F.dprint("Str len:",#str,"Encoded len:",#encoded) if ExRT.isDev then module.db.exportTable = new end exportWindow.Edit:SetText(encoded) end exportWindow:Show() end self.butExport = ELib:Button(self,L.RaidGroupsExport):Size(192,20):Point("TOP",self.presetListSave,"BOTTOM",0,-5):OnClick(function(self) module.options:RecordToText() end) self.butImport = ELib:Button(self,L.Import):Size(192,20):Point("TOP",self.butExport,"BOTTOM",0,-5):OnClick(function(self) module.options.importWindow:NewPoint("CENTER",UIParent,0,0) module.options.importWindow:Show() end) self:UpdateList() self.updateRoster:Click() function self:OnShow() module.options:UpdateTextColors() module.options:UpdateNotInList() end local GRU = CreateFrame("Frame",nil,self) GRU:SetPoint("TOPLEFT") GRU:SetSize(1,1) GRU:RegisterEvent("GROUP_ROSTER_UPDATE") GRU:SetScript("OnEvent",function() if not self:IsVisible() then return end module.options:UpdateTextColors() module.options:UpdateNotInList() end) end function module:ApplyGroups(list) if not IsInRaid() then return end local UnitsInCombat for i=1,40 do local unit = "raid"..i if UnitAffectingCombat(unit) then UnitsInCombat = (UnitsInCombat or "") .. (UnitsInCombat and "," or "") .. UnitName(unit) end end if UnitsInCombat then print("|cffff0000"..ERROR_CAPS..".|r "..L.RaidGroupsPlayersInCombat..": "..UnitsInCombat) return end local needGroup = {} local needPosInGroup = {} local lockedUnit = {} local RLName,_,RLGroup = GetRaidRosterInfo(1) local isRLfound = false for i=1,8 do local pos = 1 for j=1,5 do local name = list[(i-1)*5+j] if name == RLName then needGroup[name] = i needPosInGroup[name] = pos pos = pos + 1 isRLfound = true break end end for j=1,5 do local name = list[(i-1)*5+j] if name and name ~= RLName and UnitName(name) then needGroup[name] = i needPosInGroup[name] = pos pos = pos + 1 end end end --reports saying that too many swap events can trigger disconnect on classic, unconfirmed cause: other addons or pure swap events if ExRT.isClassic and not VMRT.RaidGroups.KeepPosInGroup then wipe(needPosInGroup) end module.db.needGroup = needGroup module.db.needPosInGroup = needPosInGroup module.db.lockedUnit = lockedUnit module.db.groupsReady = false module.db.groupWithRL = isRLfound and 0 or RLGroup if module.options.processRoster then module.options.processRoster:Disable() end module:ProcessRoster() end local function Debug(currentGroup,currentPos,needGroup,needPosInGroup) local s = "" for k,v in pairs(currentGroup) do s = s..k.."["..v..":"..currentPos[k]..","..(needGroup[k] or "")..":"..(needPosInGroup[k] or "").."]" end print(s) end function module:ProcessRoster() local UnitsInCombat for i=1,40 do local unit = "raid"..i if UnitAffectingCombat(unit) then UnitsInCombat = (UnitsInCombat or "") .. (UnitsInCombat and "," or "") .. UnitName(unit) end end if UnitsInCombat then print("|cffff0000"..ERROR_CAPS..".|r "..L.RaidGroupsCombatStarted..": "..UnitsInCombat) module.db.needGroup = nil if module.options.processRoster then module.options.processRoster:Enable() end module:UnregisterEvents('GROUP_ROSTER_UPDATE') return end local needGroup = module.db.needGroup local needPosInGroup = module.db.needPosInGroup local lockedUnit = module.db.lockedUnit if not needGroup then return end module:RegisterEvents('GROUP_ROSTER_UPDATE') local currentGroup = {} local currentPos = {} local nameToID = {} local groupSize = {} wipe(currentGroup) for i=1,8 do groupSize[i] = 0 end for i=1,GetNumGroupMembers() do local name, rank, subgroup = GetRaidRosterInfo(i) currentGroup[name] = subgroup nameToID[name] = i groupSize[subgroup] = groupSize[subgroup] + 1 currentPos[name] = groupSize[subgroup] end --Debug(currentGroup,currentPos,needGroup,needPosInGroup) if not module.db.groupsReady then local WaitForGroup = false for unit,group in pairs(needGroup) do if currentGroup[unit] and currentGroup[unit] ~= needGroup[unit] then local currGroupUnit = currentGroup[unit] local needGroupUnit = needGroup[unit] if groupSize[ needGroupUnit ] < 5 then SetRaidSubgroup(nameToID[unit],needGroupUnit) groupSize[ currGroupUnit ] = groupSize[ currGroupUnit ] - 1 groupSize[ needGroupUnit ] = groupSize[ needGroupUnit ] + 1 WaitForGroup = true end end end if WaitForGroup then return end local SetToSwap = {} local WaitForSwap = false for unit,group in pairs(needGroup) do if not SetToSwap[unit] and currentGroup[unit] and currentGroup[unit] ~= group then local currGroupUnit = currentGroup[unit] local unitToSwap for unit2,group2 in pairs(currentGroup) do if not SetToSwap[unit2] and group2 == group and needGroup[unit2] ~= group2 then unitToSwap = unit2 break end end if unitToSwap then SwapRaidSubgroup(nameToID[unit], nameToID[unitToSwap]) WaitForSwap = true SetToSwap[unit] = true SetToSwap[unitToSwap] = true end end end if WaitForSwap then return end module.db.groupsReady = true end do local SetToSwap = {} local WaitForSwap = false for unit,pos in pairs(needPosInGroup) do if currentGroup[unit] == module.db.groupWithRL then pos = pos + 1 end if not lockedUnit[unit] and currentPos[unit] and currentPos[unit] ~= pos and nameToID[unit] ~= 1 and not SetToSwap[unit] then local currGroupUnit = currentGroup[unit] local unitToSwapBridge for unit2,group2 in pairs(currentGroup) do if group2 ~= currentGroup[unit] and nameToID[unit2] ~= 1 and not SetToSwap[unit2] then unitToSwapBridge = unit2 break end end local unitToSwap for unit2,pos2 in pairs(currentPos) do if currentGroup[unit2] == currentGroup[unit] and pos2 == pos and nameToID[unit2] ~= 1 and not SetToSwap[unit2] then unitToSwap = unit2 break end end if unitToSwap and unitToSwapBridge then lockedUnit[unit] = true SwapRaidSubgroup(nameToID[unit], nameToID[unitToSwapBridge]) SwapRaidSubgroup(nameToID[unitToSwapBridge], nameToID[unitToSwap]) SwapRaidSubgroup(nameToID[unit], nameToID[unitToSwapBridge]) WaitForSwap = true SetToSwap[unit] = true SetToSwap[unitToSwap] = true SetToSwap[unitToSwapBridge] = true end end end if WaitForSwap then return end end module.db.needGroup = nil if module.options.processRoster then module.options.processRoster:Enable() end module:UnregisterEvents('GROUP_ROSTER_UPDATE') end function module.main:GROUP_ROSTER_UPDATE() if self.timer then self.timer:Cancel() end self.timer = C_Timer.NewTimer(0.5,function() self.timer = nil module:ProcessRoster() end) end function module:slash(arg) if arg and arg:find("^raidgroup ") then local name = arg:match("^raidgroup (.-)$") if name then for i=#VMRT.RaidGroups.profiles,1,-1 do local entry = VMRT.RaidGroups.profiles[i] if entry.name == name then module:ApplyGroups(entry) return end end end elseif arg == "help" then print("|cff00ff00/rt raidgroup |cffffff00GROUPNAME|r|r - apply raid groups with name GROUPNAME") end end