You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
769 lines
31 KiB
769 lines
31 KiB
local _,L = ...
|
|
local rematch = Rematch
|
|
local share = RematchDialog.Share
|
|
local settings
|
|
|
|
local rxData = nil -- will be a string built from messages sent from other clients
|
|
|
|
-- there are two styles of strings:
|
|
-- string: "name of team:npcID:pet1:p1a1:p1a2:p1a3:pet2:p2a1:p2a2:p2a3:pet3:p3a1:p3a2:p3a3:P:minHP:allowMM:expectedDD:maxHP:minXP:maxXP:N:notes+"
|
|
-- in string format, P:etc are optional, as is N:notes+
|
|
-- plain text: "name of team\n(NPC#123)\n1: Name of Pet (1,2,1)\netc"
|
|
|
|
rematch:InitModule(function()
|
|
settings = RematchSettings
|
|
local radios = rematch.Dialog.ConflictRadios
|
|
radios.MakeUnique.text:SetFontObject("GameFontHighlight")
|
|
radios.Overwrite.text:SetFontObject("GameFontHighlight")
|
|
-- stuff for sending/receiving teams
|
|
C_ChatInfo.RegisterAddonMessagePrefix("Rematch")
|
|
rematch:RegisterEvent("CHAT_MSG_ADDON")
|
|
rematch:RegisterEvent("BN_CHAT_MSG_ADDON")
|
|
end)
|
|
|
|
--[[ Export Dialog ]]
|
|
|
|
-- takes a pet table entry (team[1] team[2] or team[3]) and returns it broken down
|
|
-- if plain is false: "speciesID:ability1:ability2:ability3:"
|
|
-- if plain is true: speciesID, 1, 2, 1
|
|
function rematch:ExportPet(pet,plain)
|
|
local speciesID
|
|
local idType = rematch:GetIDType(pet[1])
|
|
if idType=="species" then
|
|
speciesID = pet[1]
|
|
elseif idType=="pet" then
|
|
speciesID = C_PetJournal.GetPetInfoByPetID(pet[1])
|
|
if not speciesID then -- if pet doesn't exist, grab its speciesID
|
|
speciesID = pet[5]
|
|
end
|
|
end
|
|
-- if creating a string, this is simple
|
|
if not plain then
|
|
if speciesID then
|
|
return format("%d:%d:%d:%d:",speciesID,pet[2] or 0,pet[3] or 0,pet[4] or 0)
|
|
else
|
|
return "0:0:0:0:" -- anything we can't interpret is a leveling pet
|
|
end
|
|
end
|
|
-- this is intended for plain text, convert abilities to 1/2 format
|
|
if speciesID then
|
|
local name = C_PetJournal.GetPetInfoBySpeciesID(speciesID)
|
|
if name then
|
|
local info = rematch.info
|
|
wipe(info)
|
|
C_PetJournal.GetPetAbilityList(speciesID,rematch.abilityList,rematch.levelList)
|
|
for j=1,3 do
|
|
if pet[j+1]==rematch.abilityList[j] then
|
|
tinsert(info,1)
|
|
elseif pet[j+1]==rematch.abilityList[j+3] then
|
|
tinsert(info,2)
|
|
else
|
|
tinsert(info,0)
|
|
end
|
|
end
|
|
if #info==3 then
|
|
return speciesID,unpack(info)
|
|
end
|
|
end
|
|
end
|
|
-- if this is a special slot, fill first return with special petID (0, "ignored", "random:x")
|
|
local specialPetID = pet[1]
|
|
if rematch:GetSpecialPetIDType(specialPetID) then
|
|
return specialPetID,0,0,0
|
|
end
|
|
-- if we reached here, this pet is a leveling pet (empty slots get turned into leveling pets)
|
|
return 0,0,0,0
|
|
end
|
|
|
|
function rematch:ShowExportDialog(key,wholeTab)
|
|
local dialog = rematch:ShowDialog("ExportDialog",340,296,wholeTab and L["Export Tab"] or L["Export Team"],nil,nil,nil,OKAY)
|
|
dialog:SetContext("wholeTab",wholeTab) -- if wholeTab is true, all teams in current tab exported
|
|
share:SetPoint("TOP",0,-36)
|
|
share:Show()
|
|
share.TopText:SetText(wholeTab and L["Press Ctrl+C to copy these teams to the clipboard."] or L["Press Ctrl+C to copy this team to the clipboard."])
|
|
|
|
dialog.MultiLine:SetSize(280,150)
|
|
dialog.MultiLine:SetPoint("TOP",share.TopText,"BOTTOM",0,-12)
|
|
dialog.MultiLine:Show()
|
|
|
|
-- preferences and notes checkboxes
|
|
if not rematch:UpdateShareIncludes(wholeTab) then
|
|
dialog:SetHeight(280)
|
|
else
|
|
dialog.ShareIncludes:SetPoint("TOP",dialog.MultiLine,"BOTTOM",0,-8)
|
|
dialog.ShareIncludes:Show()
|
|
end
|
|
share:FillExportEditBox()
|
|
dialog.MultiLine.EditBox:SetFocus(true)
|
|
end
|
|
|
|
function share:FillExportEditBox()
|
|
local text
|
|
if rematch.Dialog:GetContext("wholeTab") then -- if exporting a whole tab
|
|
local data = {}
|
|
for _,key in pairs(rematch.TeamPanel:GetWorkingList()) do
|
|
rematch:SetSideline(key,RematchSaved[key])
|
|
tinsert(data,rematch:ConvertSidelineToString())
|
|
end
|
|
text = table.concat(data,"\n")
|
|
else -- otherwise export plain or string single team
|
|
text = rematch:GetSidelineContext("plain") and rematch:ConvertSidelineToPlainText() or rematch:ConvertSidelineToString()
|
|
end
|
|
local editBox = rematch.Dialog.MultiLine.EditBox
|
|
if text~=editBox:GetText() then
|
|
editBox:SetText(text)
|
|
editBox:SetCursorPosition(0)
|
|
editBox:HighlightText(0)
|
|
end
|
|
editBox:SetScript("OnTextChanged",share.FillExportEditBox)
|
|
end
|
|
|
|
--[[ Share Includes (checkboxes to Include Preferences and Include Notes) ]]
|
|
|
|
-- updates the Include Preferences/Notes checkboxes and returns true if notes or preferences
|
|
-- are used by the sidelined team (or force is passed); make force true to enable both
|
|
-- checkboxes (multi-team export)
|
|
function rematch:UpdateShareIncludes(force)
|
|
local incl = rematch.Dialog.ShareIncludes
|
|
incl.IncludePreferences.text:SetText(L["Include Preferences"])
|
|
incl.IncludeNotes.text:SetText(L["Include Notes"])
|
|
incl.IncludePreferences:SetChecked(not settings.DontIncludePreferences)
|
|
incl.IncludeNotes:SetChecked(not settings.DontIncludeNotes)
|
|
local team = rematch:GetSideline()
|
|
local hasPref = force or rematch:HasPreferences(team)
|
|
local hasNotes = force or team.notes and true
|
|
incl.IncludePreferences:SetEnabled(hasPref)
|
|
incl.IncludePreferences.text:SetFontObject(hasPref and "GameFontNormalSmall" or "GameFontDisableSmall")
|
|
incl.IncludeNotes:SetEnabled(hasNotes)
|
|
incl.IncludeNotes.text:SetFontObject(hasNotes and "GameFontNormalSmall" or "GameFontDisableSmall")
|
|
return force or hasNotes or hasPref
|
|
end
|
|
|
|
-- onclick of checkbox will directly change setting
|
|
function rematch:ShareIncludeOnClick()
|
|
settings[self.var] = not self:GetChecked()
|
|
if rematch:IsDialogOpen("ExportDialog") then
|
|
share:FillExportEditBox()
|
|
end
|
|
end
|
|
|
|
--[[ Import Dialog ]]
|
|
|
|
function rematch:ShowImportDialog()
|
|
local dialog = rematch:ShowDialog("ImportDialog",340,306,L["Import Team"],nil,SAVE,share.AcceptImport,CANCEL,share.ImportDialogOnHide,L["Load"],share.ImportLoadTeamOnly)
|
|
share:SetPoint("TOP",0,-36)
|
|
share:Show()
|
|
share.TopText:SetText(L["Press Ctrl+V to paste a team from the clipboard."])
|
|
|
|
dialog.MultiLine:SetSize(280,150)
|
|
dialog.MultiLine:SetPoint("TOP",share.TopText,"BOTTOM",0,-12)
|
|
dialog.MultiLine:Show()
|
|
dialog.MultiLine.EditBox:SetScript("OnTextChanged",share.ImportEditBoxOnTextChanged)
|
|
dialog.MultiLine.EditBox:SetFocus(true)
|
|
|
|
dialog.TabPicker:SetPoint("TOP",dialog.MultiLine,"BOTTOM",0,-12)
|
|
dialog.TabPicker:Show()
|
|
dialog.Accept:Disable()
|
|
dialog.Other:Disable()
|
|
|
|
dialog.Other:SetScript("OnEnter",share.ShowImportLoadTooltip)
|
|
dialog.Other:SetScript("OnLeave",rematch.HideTooltip)
|
|
end
|
|
|
|
function share:ShowImportLoadTooltip()
|
|
rematch.ShowTooltip(self,L["Only Load This Team"],L["This will only load the team and not save it.\n\nThis is for loading teams you do not intend to use more than once, like Family Familiar teams."])
|
|
end
|
|
|
|
function share:ImportDialogOnHide()
|
|
rematch.Dialog.Other:SetScript("OnEnter",nil)
|
|
rematch.Dialog.Other:SetScript("OnLeave",nil)
|
|
end
|
|
|
|
-- for the "Load" button on the import dialog; saves the team to npcID 1 and loads it
|
|
function share:ImportLoadTeamOnly()
|
|
local title = rematch:GetSidelineTitle()
|
|
rematch:ChangeSidelineKey(1) -- changing key to 1, special npcID for imported team
|
|
rematch:GetSideline().teamName = title -- keep name of team still
|
|
rematch:SetSidelineContext("receivedTeam",true)
|
|
rematch:PushSideline()
|
|
rematch:LoadTeam(1) -- load npcID
|
|
end
|
|
|
|
-- returns true if the passed name,npcID form an already-used team key
|
|
function share:IsKeyUsed(name,npcID)
|
|
if not npcID or npcID==0 or npcID=="0" then
|
|
return RematchSaved[name] and true
|
|
else
|
|
return RematchSaved[tonumber(npcID)] and true
|
|
end
|
|
end
|
|
|
|
-- when editbox changes, its contents are tested to see if any teams are in its text
|
|
-- the dialog is adjusted based on result
|
|
function share:ImportEditBoxOnTextChanged()
|
|
local text = (self:GetText() or ""):trim()
|
|
local numTeams,numConflicts = rematch:TestTextForStringTeams(text)
|
|
|
|
local dialog = rematch.Dialog
|
|
dialog.Accept:SetEnabled(numTeams and numTeams>0)
|
|
dialog.Other:SetEnabled(numTeams==1)
|
|
dialog:SetContext("numTeams",numTeams)
|
|
|
|
if text:len()==0 then -- nothing in editbox, show minimal dialog awaiting input
|
|
dialog.Warning:Hide()
|
|
dialog.Team:Hide()
|
|
dialog.Text:Hide()
|
|
dialog.ConflictRadios:Hide()
|
|
dialog:SetHeight(306)
|
|
elseif not numTeams or numTeams==0 then -- no discernable teams in editbox, show warning only
|
|
dialog.Warning.Text:SetText(L["This is not a recognizable team."])
|
|
dialog.Warning:SetPoint("TOP",dialog.TabPicker,"BOTTOM",0,-4)
|
|
dialog.Warning:Show()
|
|
dialog.Team:Hide()
|
|
dialog.Text:Hide()
|
|
dialog.ConflictRadios:Hide()
|
|
dialog:SetHeight(338)
|
|
elseif numTeams==1 then -- one team is found, show the team
|
|
dialog.Warning:Hide()
|
|
dialog.Team:SetPoint("TOP",dialog.TabPicker,"BOTTOM",0,-28)
|
|
local team,key = rematch:GetSideline()
|
|
dialog:FillTeam(dialog.Team,team)
|
|
dialog.Team:Show()
|
|
dialog:ShowText(rematch:GetSidelineTitle(true),280,20,"TOP",dialog.TabPicker,"BOTTOM",0,-4)
|
|
dialog.Text:SetJustifyH("CENTER")
|
|
if not RematchSaved[key] then
|
|
dialog:SetHeight(410)
|
|
dialog.ConflictRadios:Hide()
|
|
else
|
|
dialog.ConflictRadios:SetPoint("TOP",dialog.Team,"BOTTOM",0,-8)
|
|
dialog.ConflictRadios:Show()
|
|
share:UpdateConflictRadios(format(L["An existing team already has this %s."],type(key)=="number" and L["target"] or L["name"]),L["Create a new copy"],L["Overwrite existing team"])
|
|
dialog:SetHeight(480)
|
|
end
|
|
else -- this is a multi-team import
|
|
dialog.Warning:Hide()
|
|
dialog.Team:Hide()
|
|
dialog:ShowText(format(L["%s%d\124r teams are in this import."],rematch.hexWhite,numTeams),280,20,"TOP",dialog.TabPicker,"BOTTOM",0,-8)
|
|
dialog.Text:SetJustifyH("CENTER")
|
|
if not numConflicts or numConflicts==0 then
|
|
dialog.ConflictRadios:Hide()
|
|
dialog:SetHeight(334)
|
|
else
|
|
dialog.ConflictRadios:SetPoint("TOP",dialog.Text,"BOTTOM",0,-4)
|
|
dialog.ConflictRadios:Show()
|
|
share:UpdateConflictRadios(format(L["%s%d\124r have a name or target already used."],rematch.hexRed,numConflicts),L["Create new copies"],L["Overwrite existing teams"])
|
|
dialog:SetHeight(402)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- sets text (if passed) of radio buttons and updates their checked state
|
|
function share:UpdateConflictRadios(text,opt1,opt2)
|
|
local radios = rematch.Dialog.ConflictRadios
|
|
if text then
|
|
radios.Text:SetText(text)
|
|
radios.MakeUnique.text:SetText(opt1)
|
|
radios.Overwrite.text:SetText(opt2)
|
|
end
|
|
radios.MakeUnique:SetChecked(not settings.ConflictOverwrite)
|
|
radios.Overwrite:SetChecked(settings.ConflictOverwrite and true)
|
|
end
|
|
|
|
-- click of either "Create Copy" or "Overwrite Team" radio buttons
|
|
function share:ConflictRadioOnClick()
|
|
settings.ConflictOverwrite = self:GetID()==2 and true
|
|
share:UpdateConflictRadios()
|
|
end
|
|
|
|
-- when the Save button is clicked on the import dialog
|
|
function share:AcceptImport()
|
|
local numTeams = rematch.Dialog:GetContext("numTeams")
|
|
if numTeams==1 then
|
|
-- if ConflictOverwrite not checked, then make sure sidelined team has a unique key
|
|
if not settings.ConflictOverwrite then
|
|
rematch:MakeSidelineUnique()
|
|
end
|
|
rematch:SetSidelineContext("receivedTeam",true)
|
|
rematch:PushSideline()
|
|
local team,key = rematch:GetSideline()
|
|
rematch:ShowTeam(key)
|
|
rematch:LoadTeam(key)
|
|
elseif numTeams and numTeams>1 then -- multiline import
|
|
if not rematch:GetSidelineContext("plain") then -- importing string format
|
|
local teamStrings = {}
|
|
local tabMap = {}
|
|
rematch:TestTextForStringTeams(rematch.Dialog.MultiLine.EditBox:GetText():trim(),teamStrings,tabMap)
|
|
tabMap3 = tabMap
|
|
for _,line in ipairs(teamStrings) do
|
|
rematch:ConvertStringToSideline(line)
|
|
if not settings.ConflictOverwrite then
|
|
rematch:MakeSidelineUnique()
|
|
end
|
|
|
|
-- if ImportTeamTabsToo is set, then change sideline's tab to the tabMap entry for the line
|
|
if settings.ImportTeamTabsToo then
|
|
local tab = rematch:GetTabFromTabMap(tabMap,line)
|
|
if tab then -- only if a valid tab is returned (if tabs full or something weird; keep it in selected tab)
|
|
local sideline = rematch:GetSideline()
|
|
sideline.tab = tab
|
|
end
|
|
end
|
|
|
|
rematch:SetSidelineContext("receivedTeam",true)
|
|
rematch:PushSideline()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function share:ExportTeamTab()
|
|
rematch:ShowExportDialog(nil,true)
|
|
end
|
|
|
|
function rematch:GetTabFromTabMap(tabMap,teamLine)
|
|
for mapName,mapLines in pairs(tabMap) do
|
|
for _,mapLine in ipairs(mapLines) do
|
|
if mapLine==teamLine then -- found the team in the NAMED tab mapName, need to find a tab with that name
|
|
for i=1,#settings.TeamGroups do
|
|
if settings.TeamGroups[i] and settings.TeamGroups[i][1]==mapName then
|
|
return i -- found an existing tab with this mapName, return it
|
|
end
|
|
end
|
|
-- no existing tab found, need to create a new team tab (without switching to it)
|
|
if #settings.TeamGroups < rematch.TeamTabs.MAX_TABS then
|
|
tinsert(settings.TeamGroups,{mapName,"Interface\\Icons\\PetJournalPortrait"})
|
|
return #settings.TeamGroups
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[ Send ]]
|
|
|
|
-- a sideline should be set before calling this; the dialog is re-summoned on accept to show the send status
|
|
function rematch:ShowSendDialog()
|
|
local sending = rematch:GetSidelineContext("sending")
|
|
local hasIncludes = rematch:UpdateShareIncludes()
|
|
local height = 250 + (hasIncludes and 16 or 0) + (sending and 26 or 0)
|
|
local dialog = rematch:ShowDialog("SendDialog",300,height,L["Send Team"],nil,L["Send"],share.SendAccept,CANCEL,share.SendCancel)
|
|
dialog:ShowText(rematch:GetSidelineTitle(true),280,32,"TOP",0,-28)
|
|
dialog.Text:SetJustifyH("CENTER")
|
|
dialog.Team:SetPoint("TOP",dialog.Text,"BOTTOM",0,-4)
|
|
local team,key = rematch:GetSideline()
|
|
dialog:FillTeam(dialog.Team,team)
|
|
dialog.Team:Show()
|
|
dialog.Send:SetPoint("TOP",dialog.Team,"BOTTOM",0,-8)
|
|
dialog.Send.TopText:SetText(L["Who do you want to send this team to?"])
|
|
dialog.Send:Show()
|
|
if hasIncludes then
|
|
dialog.ShareIncludes:SetPoint("BOTTOM",0,30)
|
|
dialog.ShareIncludes:Show()
|
|
end
|
|
if sending then -- this dialog is the result of the send button being clicked (or enter hit)
|
|
dialog.Send.EditBox:ClearFocus()
|
|
share:SetSendResult(L["Sending..."],"Interface\\Icons\\Achievement_GuildPerk_GMail",true)
|
|
else -- if this is before send is hit, initialize stuff to be blank
|
|
share:SetSendResult()
|
|
dialog.Send.EditBox:SetText("")
|
|
dialog.Send.EditBox:SetFocus(true)
|
|
end
|
|
end
|
|
|
|
-- if text has any value, displays the text and icon to appear beneath the editbox
|
|
-- "Sending..." "Team successfully received!" "They are not online. Send Failed." etc
|
|
function share:SetSendResult(text,icon,round)
|
|
local send = rematch.Dialog.Send
|
|
send.ResultIcon:SetShown(text and true)
|
|
send.ResultText:SetShown(text and true)
|
|
if text then
|
|
send.ResultText:SetText(text)
|
|
if round then
|
|
SetPortraitToTexture(send.ResultIcon,icon)
|
|
else
|
|
send.ResultIcon:SetTexture(icon)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- when user hit send (or enter) it will resummon the send dialog with "sending" context true
|
|
function share:SendAccept()
|
|
share:SendCancel() -- stop any pending teams being sent
|
|
rematch:SetSidelineContext("sending",true)
|
|
rematch:ShowSendDialog()
|
|
local teamString = rematch:ConvertSidelineToString()
|
|
local recipient = rematch.Dialog.Send.EditBox:GetText()
|
|
if teamString and recipient then
|
|
rematch:SetSidelineContext("recipient",nil)
|
|
rematch:StartTimer("SendTimeout",5,share.SendTimeout)
|
|
-- first step is to figure out who to send this to: bnet or character
|
|
local bnetIDAccount = BNet_GetBNetIDAccount(recipient)
|
|
if bnetIDAccount then
|
|
local bnInfo = C_BattleNet.GetAccountInfoByID(bnetIDAccount)
|
|
if bnInfo then
|
|
local bnetIDGameAccount = bnInfo.gameAccountInfo.gameAccountID
|
|
local client = bnInfo.gameAccountInfo.clientProgram
|
|
if bnetIDGameAccount and client=="WoW" then
|
|
rematch:SetSidelineContext("recipient",bnetIDGameAccount)
|
|
end
|
|
end
|
|
end
|
|
if not rematch:GetSidelineContext("recipient") then
|
|
-- recipient is not bnet, we'll send via chat
|
|
rematch:SetSidelineContext("recipient",recipient)
|
|
end
|
|
-- next step is to fill sideline context data table with string(s)
|
|
share:SerializeTeamString(teamString)
|
|
-- first line is sent right away
|
|
share:SendNextLine()
|
|
end
|
|
end
|
|
|
|
-- sends the next line of txData to the recipient; returns the percent of lines sent
|
|
function share:SendNextLine()
|
|
local data = rematch:GetSidelineContext("txData")
|
|
local recipient = rematch:GetSidelineContext("recipient")
|
|
if type(data)=="table" and #data>0 and recipient then
|
|
if not rematch:GetSidelineContext("txLines") then
|
|
-- if sending out first line (txLines not defined), set it as the number of lines being sent
|
|
rematch:SetSidelineContext("txLines",#data)
|
|
end
|
|
if #data>0 then
|
|
share:SendMessage(data[1],recipient) -- send top-most line
|
|
tremove(data,1) -- remove first line
|
|
rematch:StartTimer("SendTimeout",5,share.SendTimeout) -- restart timeout timer
|
|
else
|
|
share:SendCancel() -- all done, can stop sending
|
|
end
|
|
return (1-(#data/rematch:GetSidelineContext("txLines")))*100
|
|
end
|
|
end
|
|
|
|
-- called 5 seconds after a send begins; if this isn't cancelled before then, error displayed
|
|
-- and send stopped (within SendFailed)
|
|
function share:SendTimeout()
|
|
share:SendFailed(L["No response. Lag or they don't have Rematch?"])
|
|
end
|
|
|
|
-- call with a message to indiciate why the send failed
|
|
function share:SendFailed(reason)
|
|
share:SetSendResult(reason,"Interface\\RaidFrame\\ReadyCheck-NotReady")
|
|
rematch.Dialog.Send.EditBox:SetFocus(true)
|
|
share:SendCancel()
|
|
end
|
|
|
|
-- when user cancels a send (closing dialog or clicking cancel) or from SendFailed
|
|
function share:SendCancel()
|
|
rematch:StopTimer("SendTimeout")
|
|
rematch:SetSidelineContext("sending",nil)
|
|
rematch:SetSidelineContext("recipient",nil)
|
|
rematch:SetSidelineContext("txData",nil)
|
|
rematch:SetSidelineContext("txLines",nil)
|
|
end
|
|
|
|
-- all out-bound communication should go through here
|
|
-- sends message to sendTo via BNSendGameData if sendTo is an id (number),
|
|
-- regular SendAddonMessage otherwise
|
|
function share:SendMessage(message,sendTo)
|
|
if type(sendTo)=="number" then -- this is a bnet id
|
|
BNSendGameData(sendTo,"Rematch",message)
|
|
elseif type(sendTo)=="string" then -- this is a string name
|
|
C_ChatInfo.SendAddonMessage("Rematch",message,"WHISPER",sendTo)
|
|
end
|
|
end
|
|
|
|
-- creates sideline context "txData" as a table of each line to send.
|
|
-- if a teamString is less than 253 characters, it only has one line.
|
|
-- when a line is incomplete (more are incoming) then it ends with \003.
|
|
-- when a line is a continuation (not the first line) then it begins with \002.
|
|
-- when an incoming team begins without \002 it should start a new team.
|
|
-- when an incoming line ends with \003 it should wait for the next line.
|
|
function share:SerializeTeamString(teamString)
|
|
local data = {}
|
|
repeat
|
|
tinsert(data,teamString:sub(1,253))
|
|
teamString = teamString:sub(254)
|
|
until teamString:len()==0
|
|
if #data>1 then -- if more than one line is being sent
|
|
for i=1,#data-1 do
|
|
data[i] = data[i].."\003" -- append \003 byte to end of incomplete lines
|
|
end
|
|
for i=2,#data do
|
|
data[i] = "\002"..data[i] -- prefix \002 to start of continuing lines
|
|
end
|
|
end
|
|
rematch:SetSidelineContext("txData",data)
|
|
end
|
|
|
|
-- handles incoming messages via the regular SendAddonMessage
|
|
function rematch:CHAT_MSG_ADDON(prefix,message,_,sender)
|
|
if prefix=="Rematch" then
|
|
share:HandleReceivedMessage(message,sender)
|
|
end
|
|
end
|
|
|
|
-- handles incoming messages via battle.net (sender will be a numeric toonID)
|
|
function rematch:BN_CHAT_MSG_ADDON(prefix,message,_,sender)
|
|
if prefix=="Rematch" then
|
|
share:HandleReceivedMessage(message,sender)
|
|
end
|
|
end
|
|
|
|
function share:HandleReceivedMessage(message,sender)
|
|
-- first check whether received message is a response to one we sent out
|
|
if message=="ok" then
|
|
share:SendCancel()
|
|
share:SetSendResult(L["Team successfully received!"],"Interface\\RaidFrame\\ReadyCheck-Ready")
|
|
rematch.Dialog.Send.EditBox:SetFocus(true)
|
|
elseif message=="ack" then -- one line of an incomplete txData received
|
|
local percent = share:SendNextLine() -- send next line and update % in send.Result
|
|
share:SetSendResult(format(L["Sending...%d%%"],percent),"Interface\\Icons\\Achievement_GuildPerk_GMail",true)
|
|
elseif message=="busy" then
|
|
share:SendFailed(L["They're busy. Try again later."])
|
|
elseif message=="combat" then
|
|
share:SendFailed(L["They're in combat. Try again later."])
|
|
elseif message=="block" then
|
|
share:SendFailed(L["They have team sharing disabled."])
|
|
else -- any other messages are unsolicited, likely an incoming team
|
|
|
|
-- first check if user able to receive a team
|
|
if settings.DisableShare then
|
|
share:SendMessage("block",sender)
|
|
elseif InCombatLockdown() then
|
|
share:SendMessage("combat",sender)
|
|
elseif rematch.Dialog:IsVisible() then
|
|
share:SendMessage("busy",sender)
|
|
else
|
|
|
|
-- lines that do NOT begin with \002 are brand new teams...maybe
|
|
if not message:match("^\002") then
|
|
local name,npcID = rematch:GetTeamStringNameAndNpcID(message)
|
|
if name then -- this looks like a team woot
|
|
-- we'll convert it to a team once we're sure we have the whole thing
|
|
rxData = message:gsub("\002",""):gsub("\003","")
|
|
end
|
|
else -- this message is a continuation (began with \002), so append it to rxData
|
|
if rxData then
|
|
rxData = rxData..(message:gsub("\002",""):gsub("\003",""))
|
|
end
|
|
end
|
|
|
|
-- lines that end with \003 are incomplete. send back an ack and wait
|
|
if message:match("\003$") then -- message is incomplete, send back an ack that it was received
|
|
share:SendMessage("ack",sender)
|
|
else -- lines that don't end with \003 are the final line
|
|
share:SendMessage("ok",sender) -- message fully received
|
|
if rematch:ConvertStringToSideline(rxData) then
|
|
if type(sender)=="number" then -- for bnet-sent teams, sender is a numeric toonID
|
|
rematch:SetSidelineContext("sender",(select(2,C_BattleNet.GetGameAccountInfoByID(sender))))
|
|
else -- for regularly sent teams, sender is the name
|
|
rematch:SetSidelineContext("sender",sender)
|
|
end
|
|
rematch:ShowReceiveDialog()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[ Receive ]]
|
|
|
|
-- called when a team is received (received team is sidelined in message handling before this is called)
|
|
function rematch:ShowReceiveDialog()
|
|
local dialog = rematch:ShowDialog("ReceiveDialog",300,264,L["Incoming Rematch Team!"],L["Save this team?"],SAVE,share.ReceiveAccept,CANCEL)
|
|
local team,key = rematch:GetSideline()
|
|
local sender,form,npcName = rematch:GetSidelineContext("sender") or UNKNOWN
|
|
if type(key)=="number" then -- this is a targeted team
|
|
npcName = rematch:GetNameFromNpcID(key)
|
|
if team.teamName~=npcName then
|
|
form = L["%s%s\124r has sent you a team named \"%s\" (for %s)."]
|
|
else
|
|
form = L["%s%s\124r has sent you a team for %s."]
|
|
end
|
|
else
|
|
form = L["%s%s\124r has sent you a team named \"%s\"."]
|
|
end
|
|
dialog:ShowText(format(form,rematch.hexWhite,sender,rematch:GetSidelineTitle(true),npcName),260,64,"TOP",0,-24)
|
|
dialog.Team:SetPoint("TOP",dialog.Text,"BOTTOM")
|
|
dialog:FillTeam(dialog.Team,team)
|
|
dialog.Team:Show()
|
|
dialog.TabPicker:SetPoint("TOP",dialog.Team,"BOTTOM",0,-12)
|
|
dialog.TabPicker:Show()
|
|
if RematchSaved[key] then
|
|
dialog.ConflictRadios:SetPoint("TOP",dialog.TabPicker,"BOTTOM",0,-8)
|
|
dialog.ConflictRadios:Show()
|
|
share:UpdateConflictRadios(format(L["An existing team already has this %s."],type(key)=="number" and L["target"] or L["name"]),L["Create a new copy"],L["Overwrite existing team"])
|
|
dialog:SetHeight(332)
|
|
end
|
|
end
|
|
|
|
-- when the save button is clicked in the receive dialog
|
|
function share:ReceiveAccept()
|
|
if not settings.ConflictOverwrite then
|
|
rematch:MakeSidelineUnique()
|
|
end
|
|
rematch:SetSidelineContext("receivedTeam",true)
|
|
rematch:PushSideline()
|
|
local team,key = rematch:GetSideline()
|
|
rematch:ShowTeam(key)
|
|
end
|
|
|
|
-- when PetBattleTeams is enabled, Team menu has "Import Pet Battle Teams" which calls this
|
|
function rematch:ShowImportPBTDialog()
|
|
local dialog = rematch:ShowDialog("ImportPBT",300,130,L["Import From Pet Battle Teams"],L["Import these teams?"],L["Import"],share.ImportPBTAccept,CANCEL)
|
|
local PBTSaved = PetBattleTeamsDB.namespaces.TeamManager.global.teams
|
|
dialog:ShowText(format("%s%d\124r teams in are in Pet Battle Teams.",rematch.hexWhite,#PBTSaved),270,32,"TOP",0,-32)
|
|
dialog.Text:SetJustifyH("CENTER")
|
|
local numConflicts = 0
|
|
for i=1,#PBTSaved do
|
|
if RematchSaved[(PBTSaved[i].name or "Team: "..i)] then
|
|
numConflicts = numConflicts+1
|
|
end
|
|
end
|
|
if numConflicts>0 then
|
|
dialog.ConflictRadios:SetPoint("TOP",dialog.Text,"BOTTOM",0,-4)
|
|
dialog.ConflictRadios:Show()
|
|
share:UpdateConflictRadios(format(L["%s%d\124r Rematch teams have the same name."],rematch.hexRed,numConflicts),L["Create new copies"],L["Overwrite existing teams"])
|
|
dialog:SetHeight(200)
|
|
end
|
|
end
|
|
|
|
-- import button from ImportPBT dialog
|
|
function share:ImportPBTAccept()
|
|
local PBTSaved = PetBattleTeamsDB.namespaces.TeamManager.global.teams
|
|
for i=1,#PBTSaved do
|
|
local team,key = rematch:SetSideline(PBTSaved[i].name or "Team: "..i,{})
|
|
team.tab = settings.SelectedTab>1 and settings.SelectedTab or nil
|
|
for j=1,3 do -- add the three pets
|
|
local petID = PBTSaved[i][j].petID
|
|
if petID then
|
|
local hex = petID:match("BattlePet%-(.+)")
|
|
if hex then -- old teams had lower case hex digits
|
|
petID = format("BattlePet-%s",hex:upper())
|
|
end
|
|
if rematch:GetIDType(petID)=="pet" and petID~="BattlePet-0-000000000000" then
|
|
local speciesID = C_PetJournal.GetPetInfoByPetID(petID)
|
|
if not speciesID then -- this is not a valid petID, use its speciesID instead
|
|
speciesID = PBTSaved[i][j].speciesID
|
|
if type(speciesID)=="number" then
|
|
team[j] = {speciesID} -- but there is a speciesID, so use that instead of a petID
|
|
else
|
|
speciesID = nil -- no idea what this is, nil it
|
|
end
|
|
else
|
|
team[j] = {petID} -- petID is valid, use it for the pet
|
|
end
|
|
if team[j] and speciesID then -- a pet was found, add its abilities
|
|
for k=1,3 do
|
|
team[j][k+1] = PBTSaved[i][j].abilities[k]
|
|
end
|
|
team[j][5] = speciesID -- add its speciesID too
|
|
end
|
|
end
|
|
end
|
|
if not team[j] then -- no pet was successfully made for this slot, add a leveling slot
|
|
team[j] = {0,0,0,0}
|
|
end
|
|
end
|
|
if not settings.ConflictOverwrite then
|
|
rematch:MakeSidelineUnique() -- if "Create new copies", make name unique if needed
|
|
end
|
|
rematch:SetSidelineContext("receivedTeam",true)
|
|
rematch:PushSideline() -- and save the team
|
|
end
|
|
end
|
|
|
|
-- does a backup of all teams across all tabs
|
|
function rematch:ShowBackupDialog()
|
|
local dialog = rematch:ShowDialog("BackupTeams",340,430,L["Backup All Teams"],nil,nil,nil,OKAY,share.FinishBackup)
|
|
dialog:ShowText(L["Please Wait..."],300,100,"TOP",0,-32)
|
|
dialog.MultiLine:SetSize(280,150)
|
|
dialog.MultiLine:SetPoint("TOP",dialog.Text,"BOTTOM",0,-8)
|
|
dialog.MultiLine:Show()
|
|
dialog.SmallText:SetSize(280,100)
|
|
dialog.SmallText:SetPoint("TOP",dialog.MultiLine,"BOTTOM",0,-8)
|
|
dialog.SmallText:SetText(L["Note: These are just your teams and their notes and preferences. Tab information, sort orders, win records and other settings are not included.\n\nFor the most complete backup of all your addon data, please backup your Word of Warcraft\\WTF folder."])
|
|
dialog.SmallText:Show()
|
|
|
|
-- backup these two user settings
|
|
dialog:SetContext("backupDontIncludePreferences",settings.DontIncludePreferences)
|
|
dialog:SetContext("backupDontIncludeNotes",settings.DontIncludeNotes)
|
|
-- and then clear them so we include preferences and notes with all teams
|
|
settings.DontIncludePreferences = nil
|
|
settings.DontIncludeNotes = nil
|
|
|
|
dialog:SetContext("backupCurrentTab",1) -- start at first tab
|
|
rematch:StartTimer("BackupTeams",0.1,share.BackupTeamTab) -- and start timer to gather each tab one at a time
|
|
end
|
|
|
|
-- inserts an exported tab into dialog.MultiLine.EditBox
|
|
-- to prevent the client locking up from extreme amounts of text inserted into an editbox,
|
|
-- we're only adding one tab every 0.1 seconds
|
|
function share:BackupTeamTab()
|
|
local dialog = rematch.Dialog
|
|
local tab = dialog:GetContext("backupCurrentTab")
|
|
if tab<=#settings.TeamGroups then
|
|
local out = {}
|
|
if tab>1 then -- add some space between last team of previous tab if this isn't first
|
|
tinsert(out,"\n")
|
|
end
|
|
tinsert(out,format("__ %s __\n",settings.TeamGroups[tab][1]))
|
|
-- first gather all teams for this tab into a scratch table
|
|
local scratch = {}
|
|
for key,team in pairs(RematchSaved) do
|
|
if team.tab==tab or (not team.tab and tab==1) then
|
|
tinsert(scratch,key)
|
|
end
|
|
end
|
|
-- sort the teams in the scratch table
|
|
table.sort(scratch,rematch.TeamSort)
|
|
|
|
-- now go through and add each team to the out table
|
|
for _,key in ipairs(scratch) do
|
|
rematch:SetSideline(key,RematchSaved[key])
|
|
local text = rematch:ConvertSidelineToString()
|
|
tinsert(out,text)
|
|
end
|
|
|
|
dialog.MultiLine.EditBox:Insert(table.concat(out,"\n"))
|
|
-- move on to the next tab
|
|
dialog:SetContext("backupCurrentTab",tab+1)
|
|
rematch:StartTimer("BackupTeams",0.1,share.BackupTeamTab) -- call this again in 0.1 seconds
|
|
else
|
|
-- we've added all tabs to the dialog; highlight everything and set focus
|
|
dialog.MultiLine.EditBox:SetFocus(true)
|
|
dialog.MultiLine.EditBox:SetCursorPosition(0)
|
|
dialog.MultiLine.EditBox:HighlightText(0)
|
|
dialog.Text:SetText(L["Press Ctrl+C to copy these teams to the clipboard. Then paste them into an email to yourself or a text file someplace safe.\n\nIf you ever need to restore your teams, paste them back in with Import Teams."])
|
|
rematch:StopTimer("BackupTeams")
|
|
end
|
|
end
|
|
|
|
-- called when the backup dialog closes
|
|
function share:FinishBackup()
|
|
local dialog = rematch.Dialog
|
|
settings.DontIncludePreferences = dialog:GetContext("backupDontIncludePreferences")
|
|
settings.DontIncludeNotes = dialog:GetContext("backupDontIncludeNotes")
|
|
rematch:StopTimer("BackupTeams")
|
|
settings.BackupCount = rematch:GetNumTeams()
|
|
end
|
|
|
|
function rematch:CheckForBackupReminder()
|
|
if not settings.NoBackupReminder then
|
|
settings.BackupCount = settings.BackupCount or 0
|
|
local numTeams = rematch:GetNumTeams()
|
|
if numTeams>=(settings.BackupCount+50) then
|
|
settings.BackupCount = numTeams -- if they declined, don't ask again until another 50 teams
|
|
local dialog = rematch:ShowDialog("BackupReminder",300,220,L["Backup All Rematch Teams?"],nil,YES,rematch.ShowBackupDialog,NO)
|
|
dialog:ShowText(format(L["You have %s%d\124r Rematch teams.\n\nWould you like to back them up?"],rematch.hexWhite,numTeams),260,48,"TOP",0,-32)
|
|
dialog.SmallText:SetSize(260,72)
|
|
dialog.SmallText:SetPoint("TOP",dialog.Text,"BOTTOM",0,-2)
|
|
dialog.SmallText:SetText(L["Choosing Yes will export all teams to copy and paste in an email to yourself or someplace safe.\n\nYou can also do this at any time from the Teams button at the top of the Teams panel of Rematch."])
|
|
dialog.SmallText:Show()
|
|
dialog.CheckButton:SetPoint("TOPLEFT",dialog.SmallText,"BOTTOMLEFT",24,-2)
|
|
dialog.CheckButton.text:SetText(L["Don't Remind About Backups"])
|
|
dialog.CheckButton:Show()
|
|
dialog.CheckButton:SetScript("OnClick",function(self) settings.NoBackupReminder = self:GetChecked() end)
|
|
end
|
|
end
|
|
end
|
|
|