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.
333 lines
16 KiB
333 lines
16 KiB
local _,rematch = ...
|
|
local L = rematch.localization
|
|
local C = rematch.constants
|
|
local settings = rematch.settings
|
|
rematch.loadTeam = {}
|
|
|
|
|
|
local loadPlan = {} -- ordered list of loadouts to change: {slot,petID,ability1,ability2,ability3}
|
|
local timeout = 0 -- timeout counter to stop trying to load
|
|
local loadingTeamID -- teamID being loaded
|
|
|
|
-- local functions to perform the load
|
|
local startLoad, runLoad, finishLoad
|
|
local getExcludePetIDs
|
|
|
|
-- indexed by pet slot, an issue with the team being loaded (C.UNPLANNED_PET_MISSING for missing pet, C.UNPLANNED_LOW_LEVEL for random pet under 25)
|
|
local unplanned = {}
|
|
|
|
-- call to load a teamID
|
|
function rematch.loadTeam:LoadTeamID(teamID)
|
|
if rematch.loadouts:CantSwapPets() then
|
|
return -- can't swap pets, leave
|
|
end
|
|
if teamID and rematch.savedTeams[teamID] then
|
|
rematch.rebuild:ValidateTeamID(teamID,true)
|
|
loadingTeamID = teamID
|
|
startLoad(teamID)
|
|
end
|
|
end
|
|
|
|
-- loads a team by its case-insensitive name and returns the teamID being loaded if one is going to load
|
|
function rematch.loadTeam:LoadTeamByName(teamName)
|
|
local teamID = rematch.savedTeams:GetTeamIDByName(teamName:trim())
|
|
if teamID then
|
|
rematch.loadTeam:LoadTeamID(teamID)
|
|
return teamID
|
|
end
|
|
end
|
|
|
|
function rematch.loadTeam:UnloadTeam()
|
|
settings.currentTeamID = nil
|
|
rematch.queue:Process()
|
|
rematch.events:Fire("REMATCH_TEAM_LOADED")
|
|
end
|
|
|
|
-- returns true if a team is currently loading
|
|
function rematch.loadTeam:IsTeamLoading()
|
|
return loadingTeamID and true or false
|
|
end
|
|
|
|
-- returns the healthiest version of the petID (possibly same petID if LoadHealthiest not enabled)
|
|
function rematch.loadTeam:FindHealthiestPetID(petID,excludePetIDs)
|
|
local bestPetID = petID
|
|
local petInfo = rematch.altInfo:Fetch(petID)
|
|
-- only looking for a healthier pet if setting enabled, player owns more than 1 of the species and petID injured
|
|
if settings.LoadHealthiest and petInfo.count>1 then
|
|
local bestHealth = petInfo.health
|
|
local speciesID = petInfo.speciesID
|
|
local maxHealth, power, speed = petInfo.maxHealth, petInfo.power, petInfo.speed
|
|
for ownedPetID in rematch.roster:AllSpeciesPetIDs(speciesID) do
|
|
petInfo = rematch.altInfo:Fetch(ownedPetID)
|
|
if petInfo.speciesID==speciesID and petInfo.isOwned and petInfo.health>bestHealth then
|
|
-- if LoadHealthiestAny is true, then don't need to match other stats
|
|
if (settings.LoadHealthiestAny or (petInfo.maxHealth==maxHealth and petInfo.power==power and petInfo.speed==speed)) and (ownedPetID==petID or (excludePetIDs and not excludePetIDs[ownedPetID])) then
|
|
bestPetID = ownedPetID
|
|
bestHealth = petInfo.health
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if bestPetID and petID~=bestPetID then
|
|
excludePetIDs[bestPetID] = true -- add this new petID to excluded pets so it's not loaded into another slot
|
|
end
|
|
return bestPetID
|
|
end
|
|
|
|
-- to be called when we want to make sure the already-loaded team has the healthiest pet (leaving battle, revive/bandages)
|
|
-- note to self: if this ever does anything on a delay, make sure to update rematch.main's delayedPetBattleClose too
|
|
-- (there's already some potential delay/queue processing for rematch.loadouts:SlotPet(), this is ok)
|
|
function rematch.loadTeam:AssertHealthiestPet()
|
|
if settings.LoadHealthiest then
|
|
local teamID = settings.currentTeamID
|
|
local team = teamID and rematch.savedTeams[teamID]
|
|
if team then
|
|
-- for asserting healthiest pets, just exclude loaded petIDs (team's pets may want back in and shouldn't be excluded)
|
|
local excludePetIDs = {}
|
|
for i=1,3 do
|
|
local petID = C_PetJournal.GetPetLoadOutInfo(i)
|
|
if petID then
|
|
excludePetIDs[petID] = true
|
|
end
|
|
end
|
|
for i=1,3 do
|
|
local loadedPetID = rematch.loadouts:GetLoadoutInfo(i)
|
|
local petInfo = rematch.petInfo:Fetch(loadedPetID)
|
|
if petInfo.idType=="pet" and petInfo.isOwned then
|
|
local newPetID = rematch.loadTeam:FindHealthiestPetID(loadedPetID,excludePetIDs)
|
|
if newPetID and loadedPetID~=newPetID then
|
|
rematch.loadouts:SlotPet(i,newPetID)
|
|
excludePetIDs[newPetID] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- sets up the load plan and kicks off loading
|
|
function startLoad(teamID)
|
|
wipe(loadPlan)
|
|
local team = teamID and rematch.savedTeams[teamID]
|
|
if team then
|
|
-- if all pets in a team are random, then use lenient rule
|
|
local randomRules = C.RANDOM_RULES_LENIENT
|
|
for i=1,3 do
|
|
if rematch.loadouts:GetSpecialPetIDType(team.pets[slot])~="random" then
|
|
randomRules = settings.RandomPetRules -- a non-random pet in team, used saved random rules
|
|
end
|
|
end
|
|
|
|
-- for random teams, build list of pets to exclude including slotted pets and incoming pets
|
|
local excludePetIDs = {}
|
|
for i=1,3 do
|
|
local petID = C_PetJournal.GetPetLoadOutInfo(i)
|
|
if petID then
|
|
excludePetIDs[petID] = true
|
|
end
|
|
local petInfo = rematch.petInfo:Fetch(team.pets[i])
|
|
if petInfo.idType=="pet" then
|
|
excludePetIDs[team.pets[i]] = true
|
|
end
|
|
end
|
|
|
|
rematch.queue:Update(teamID) -- update queue to the incoming team's preferences
|
|
local pickIndex = 1 -- 1-3 for leveling pet to load from queue
|
|
|
|
wipe(unplanned)
|
|
|
|
-- add each pet to the load plan for the team
|
|
for slot=1,3 do
|
|
local petID = team.pets[slot]
|
|
rematch.loadouts:SetSlotPetID(slot,petID) -- set slot's petID regardless if it loads for special slots
|
|
if petID then
|
|
local petInfo = rematch.petInfo:Fetch(petID)
|
|
-- every pet being slotted must be a valid owned pet BattlePet-0-etc
|
|
if petID==0 then -- leveling pet
|
|
local levelingPetID = rematch.queue:GetTopPick(pickIndex)
|
|
if levelingPetID then
|
|
tinsert(loadPlan,{slot,levelingPetID}) -- add leveling pet to load plan
|
|
excludePetIDs[levelingPetID] = true -- exclude leveling pet from potential randoms
|
|
elseif settings.QueueRandomWhenEmpty then -- if a leveling pet wasn't found and Random Pet When Queue Empty enabled, pick a random pet
|
|
local levelingPetID = rematch.randomPets:PickRandomPetID({excludePetIDs=excludePetIDs})
|
|
if levelingPetID then
|
|
tinsert(loadPlan,{slot,levelingPetID})
|
|
excludePetIDs[levelingPetID] = true
|
|
end
|
|
end
|
|
pickIndex = pickIndex + 1
|
|
elseif petInfo.idType=="pet" and petInfo.isValid and petInfo.isOwned and petInfo.isSummonable then
|
|
local ability1,ability2,ability3 = rematch.petTags:GetAbilities(team.tags[slot])
|
|
local healthiestPetID = rematch.loadTeam:FindHealthiestPetID(petID,excludePetIDs) -- returns same petID if option disabled
|
|
tinsert(loadPlan,{slot,healthiestPetID,ability1,ability2,ability3})
|
|
excludePetIDs[healthiestPetID] = true
|
|
elseif petInfo.idType=="pet" and not petInfo.isValid then
|
|
local newPetID = rematch.petTags:FindPetID(team.tags[slot],excludePetIDs)
|
|
if newPetID then
|
|
tinsert(loadPlan,{slot,newPetID,ability1,ability2,ability3})
|
|
excludePetIDs[newPetID] = true
|
|
end
|
|
elseif petInfo.idType=="random" then
|
|
local petType = tonumber(petID:match("^random:(%d+)"))
|
|
local randomPetID = rematch.randomPets:PickRandomPetID({petType=petType,rules=randomRules,excludePetIDs=excludePetIDs})
|
|
if randomPetID then
|
|
local petInfo = rematch.petInfo:Fetch(randomPetID)
|
|
if settings.RandomAbilitiesToo then -- if Random Abilities Too enabled, load random abilities too
|
|
tinsert(loadPlan,{slot,randomPetID,petInfo.abilityList[1+(random(100)>50 and 3 or 0)],petInfo.abilityList[2+(random(100)>50 and 3 or 0)],petInfo.abilityList[3+(random(100)>50 and 3 or 0)]})
|
|
else -- otherwise let game choose abilities and only slot petID
|
|
tinsert(loadPlan,{slot,randomPetID})
|
|
end
|
|
if settings.WarnWhenRandomNot25 and (not petInfo.level or petInfo.level<25) then
|
|
unplanned[slot] = {problem=C.UNPLANNED_LOW_LEVEL,petID=randomPetID}
|
|
end
|
|
excludePetIDs[randomPetID] = true -- add this random pet to exclude for other slots
|
|
end
|
|
elseif not settings.DontWarnMissing then
|
|
unplanned[slot] = {problem=C.UNPLANNED_PET_MISSING,petID=petID}
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
timeout = 0 -- start timeout counter
|
|
runLoad() -- kick off the load
|
|
end
|
|
|
|
-- goes through the load plan and removes anything that no longer needs to be loaded, returning true if something
|
|
-- still needs to be loaded; false if all done
|
|
function updatePlan()
|
|
local somethingNeedsLoaded = false -- becomes true if something still needs loaded
|
|
-- go through plan and remove anything that's been loaded; if any plan should be entirely removed, change slot to "remove"
|
|
for _,plan in ipairs(loadPlan) do
|
|
local slot,petID,ability1,ability2,ability3 = unpack(plan)
|
|
if type(slot)~="number" and not (slot==1 or slot==2 or slot==3) then
|
|
plan[1] = "remove" -- this slot is not valid, remove from plan
|
|
else
|
|
local loadedPetID,loadedAbility1,loadedAbility2,loadedAbility3,loadedLocked = C_PetJournal.GetPetLoadOutInfo(slot)
|
|
if loadedLocked then
|
|
plan[1] = "remove" -- this slot is locked, remove from plan
|
|
else
|
|
if petID and loadedPetID==petID then
|
|
plan[2] = nil -- pet doesn't need loaded
|
|
end
|
|
if not ability1 or ability1==0 or (ability1 and loadedAbility1==ability1) then
|
|
plan[3] = nil -- ability1 doesn't need loaded
|
|
end
|
|
if not ability2 or ability2==0 or (ability2 and loadedAbility2==ability2) then
|
|
plan[4] = nil -- ability2 doesn't need loaded
|
|
end
|
|
if not ability3 or ability3==0 or (ability3 and loadedAbility3==ability3) then
|
|
plan[5] = nil -- ability3 doesn't need loaded
|
|
end
|
|
if not plan[2] and not plan[3] and not plan[4] and not plan[5] then
|
|
plan[1] = "remove" -- petID and all abilities loaded, remove from plan
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- remove any plans flags for removal
|
|
for i=#loadPlan,1,-1 do
|
|
if loadPlan[i][1]=="remove" then
|
|
tremove(loadPlan,i)
|
|
else
|
|
somethingNeedsLoaded = true
|
|
end
|
|
end
|
|
return somethingNeedsLoaded
|
|
end
|
|
|
|
-- slots the pets planned from startLoad by going through each record and loading it if it's not loaded
|
|
function runLoad()
|
|
if timeout<C.TEAM_LOAD_TIMEOUT and updatePlan() then -- if retries remaining and something needs loaded
|
|
timeout = timeout + 1
|
|
for _,plan in ipairs(loadPlan) do
|
|
if plan[2] then -- petID needs loaded into this slot
|
|
rematch.loadouts:SlotPet(plan[1],plan[2])
|
|
end
|
|
if plan[3] then
|
|
C_PetJournal.SetAbility(plan[1],1,plan[3]) -- ability1
|
|
end
|
|
if plan[4] then
|
|
C_PetJournal.SetAbility(plan[1],2,plan[4]) -- ability2
|
|
end
|
|
if plan[5] then
|
|
C_PetJournal.SetAbility(plan[1],3,plan[5]) -- ability3
|
|
end
|
|
end
|
|
-- update plan now that stuff loaded; if something remains to be loaded, come back in a bit to continue loading
|
|
if updatePlan() then
|
|
rematch.timer:Start(C.TEAM_LOAD_WAIT,runLoad)
|
|
return
|
|
end
|
|
end
|
|
-- if reached here, either we hit timeout or team is fully loaded
|
|
finishLoad()
|
|
end
|
|
|
|
-- finishes loading and alerts if any pets missing/replaced and fires REMATCH_TEAM_LOADED
|
|
function finishLoad()
|
|
settings.currentTeamID = loadingTeamID
|
|
-- SetSlotPetID to set special slots after team loads
|
|
local team = rematch.savedTeams[loadingTeamID]
|
|
if not team then
|
|
return
|
|
end
|
|
for slot=1,3 do
|
|
local petID = team.pets[slot]
|
|
rematch.loadouts:SetSlotPetID(slot,petID) -- this sets special slots
|
|
end
|
|
if team.notes and settings.ShowNotesOnLoad then
|
|
rematch.cardManager:ShowCard(rematch.notes,loadingTeamID)
|
|
end
|
|
-- if any pets missing or unable to be loaded, show a warning
|
|
rematch.loadTeam:WarnProblemLoads()
|
|
loadingTeamID = nil
|
|
rematch.events:Fire("REMATCH_TEAM_LOADED",settings.currentTeamID)
|
|
end
|
|
|
|
function rematch.loadTeam:WarnProblemLoads()
|
|
local problem
|
|
for slot=1,3 do
|
|
if unplanned[slot] and unplanned[slot].problem==C.UNPLANNED_PET_MISSING then
|
|
problem = C.UNPLANNED_PET_MISSING
|
|
elseif not problem and unplanned[slot] and unplanned[slot].problem==C.UNPLANNED_LOW_LEVEL then
|
|
problem = C.UNPLANNED_LOW_LEVEL -- only care about this if no missing pets
|
|
end
|
|
end
|
|
if not problem then
|
|
return
|
|
end
|
|
rematch.dialog:Register("ProblemLoad",{
|
|
title = problem==C.UNPLANNED_PET_MISSING and L["Pets are missing"] or L["Low level random pet"],
|
|
accept = OKAY,
|
|
layout = {"Text","TeamWarning","CheckButton"},
|
|
refreshFunc = function(self,info,subject,firstRun)
|
|
self.Text:SetText(problem==C.UNPLANNED_PET_MISSING and L["Pets are missing in the team just loaded."] or L["A low level random pet just loaded."])
|
|
self.CheckButton:SetText(problem==C.UNPLANNED_PET_MISSING and L["Don't Warn About Missing Pets"] or L["Warn For Pets Below Max Level"])
|
|
self.CheckButton:SetChecked(problem==C.UNPLANNED_LOW_LEVEL) -- if seeing this dialog, then check is only checked for low level
|
|
for i=1,3 do
|
|
local petID
|
|
if unplanned[i] and unplanned[i].problem==problem then
|
|
self.TeamWarning.Warnings[i]:Show()
|
|
petID = unplanned[i].petID
|
|
else
|
|
self.TeamWarning.Warnings[i]:Hide()
|
|
petID = rematch.loadouts:GetLoadoutInfo(i)
|
|
end
|
|
self.TeamWarning.Pets[i].petID = petID
|
|
self.TeamWarning.Pets[i]:FillPet(petID)
|
|
end
|
|
end,
|
|
acceptFunc = function(self,info,subject)
|
|
if problem==C.UNPLANNED_LOW_LEVEL and not self.CheckButton:GetChecked() then
|
|
settings.WarnWhenRandomNot25 = false
|
|
rematch.frame:Update()
|
|
elseif problem==C.UNPLANNED_PET_MISSING and self.CheckButton:GetChecked() then
|
|
settings.DontWarnMissing = true
|
|
rematch.frame:Update()
|
|
end
|
|
end
|
|
})
|
|
rematch.dialog:ShowDialog("ProblemLoad")
|
|
end
|