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.

258 lines
9.8 KiB

3 years ago
--[[
This module's purpose is to assign petIDs to teams and queue where a petID has
been reassigned (by the server, by caging and relearning a pet, etc) or when a
missing pet is learned (convert a speciesID placeholder to a live petID).
UpdateSanctuary should be called after an UpdateOwned during the UpdateUI.
When a pet is caged, or a total petID reassignment happens by the server, the pet will
still exist but with a new petID. This module will store enough stats from a petID
(level, maxHealth, power, speed, rarity) to find its new petID when needed.
ONLY pets that are in a team or in the leveling queue are stored here.
[petID] = {count,exists,speciesID,level,maxHealth,power,speed,rarity}
count is the number of instances this petID is used; when it reaches 0 it's removed.
exists is set in UpdateOwned and is true when the petID is known to exist.
]]
local _,L = ...
local rematch = Rematch
local settings, saved
local sanctuary
rematch.sanctuaryCandidates = {} -- list of petID candidates for potential replacement
rematch:InitModule(function()
settings = RematchSettings
saved = RematchSaved
sanctuary = settings.Sanctuary
-- convert 3.x sanctuary to new format
if settings.SanctuaryPets then
for _,pet in ipairs(settings.SanctuaryPets) do
local petID,speciesID,level,maxHealth,power,speed = strsplit(",",pet)
if petID:len()>0 then
-- old sanctuary didn't include rarity; rarity will be pulled on next UpdateSanctuary
settings.Sanctuary[petID] = {0,nil,tonumber(speciesID),tonumber(level),tonumber(maxHealth),tonumber(power),tonumber(speed),0}
end
end
settings.SanctuaryPets = nil -- remove old sanctuary
end
end)
-- adds a petID to the sanctuary; if update is true then it will update its stats if
-- it already existed.
function rematch:AddToSanctuary(petID,update)
if petID and petID~=0 then
local existed = true
if type(sanctuary[petID])~="table" then
if rematch:GetIDType(petID)=="pet" then
local speciesID,_,level = C_PetJournal.GetPetInfoByPetID(petID)
local _, maxHealth, power, speed, rarity = C_PetJournal.GetPetStats(petID)
sanctuary[petID] = {0,true,speciesID,level,maxHealth,power,speed,rarity}
else
sanctuary[petID] = {0} -- this petID has no stats (likely a speciesiD)
end
existed = false
end
sanctuary[petID][1] = sanctuary[petID][1] + 1 -- increment occurance of petID
if existed and update then
rematch:UpdatePetInSanctuary(petID)
end
end
end
-- this updates the stats of a single petID in the sanctuary
-- called during AddToSanctuary if a pet already existed and in UpdateUI to update
-- loadout and summoned pets if they exist.
-- if level has a value, then no need to re-pull value
function rematch:UpdatePetInSanctuary(petID)
local petInfo = rematch.petInfo:Fetch(petID)
if petInfo.idType=="pet" and sanctuary[petID] and petInfo.level then
sanctuary[petID][4] = petInfo.level
sanctuary[petID][5] = petInfo.maxHealth
sanctuary[petID][6] = petInfo.power
sanctuary[petID][7] = petInfo.speed
sanctuary[petID][8] = petInfo.rarity
end
end
-- this is safe to call anytime, but should be called after an UpdateOwned() which
-- flags whether a petID is known to exist
function rematch:UpdateSanctuary(force)
if rematch.isLoaded and (rematch.sanctuaryNeedsUpdated or force) and not settings.DebugNoSanctuary then
-- reset counters for all pets
for petID,info in pairs(sanctuary) do
sanctuary[petID][1] = 0 -- team counter
end
-- go through all teams and add any un-sanctuary'ed pet
for key,team in pairs(saved) do
for i=1,3 do
rematch:AddToSanctuary(team[i][1])
end
end
-- go through the leveling queue and add any un-sanctuary'ed pet
for _,petID in pairs(settings.LevelingQueue) do
rematch:AddToSanctuary(petID)
end
-- this removes any pets that no longer belong to a team or are in the queue
for petID,info in pairs(sanctuary) do
if sanctuary[petID][1]==0 then
sanctuary[petID] = nil
end
end
-- now go through and see if any invalid petIDs need found
for petID,info in pairs(sanctuary) do
if not info[2] then -- if this pet is known not to exist
local idType = rematch:GetIDType(petID)
if idType=="pet" then
local _,_,level = C_PetJournal.GetPetInfoByPetID(petID)
if not level then -- confirm petID doesn't exist before finding a replacement
rematch:FindReplacementPet(petID,sanctuary[petID][3])
end
elseif idType=="species" then -- a numeric petID that's not 0 is a species with no owned versions
rematch:FindReplacementPet(nil,petID)
end
else -- if pet exists, it's (very likely) a valid petID; update its stats
rematch:UpdatePetInSanctuary(petID)
end
end
rematch.sanctuaryNeedsUpdated = nil
end
end
-- in the event of a petID reassignment, or when learning a new speciesID, this will
-- replace all instances of petID (or speciesID if petID not given) in teams
-- when petID has a value, only exact matches will be considered
-- when petID has no value, any of the found speciesID will be considered
function rematch:FindReplacementPet(petID,speciesID)
local count = type(speciesID)=="number" and C_PetJournal.GetNumCollectedInfo(speciesID)
if not count or count==0 then
return -- pet still not known, can leave
end
local sanctuaryPet = petID and sanctuary[petID]
local candidates = rematch.sanctuaryCandidates
wipe(candidates)
-- if only one version of this speciesID exists, our work is easy
if count==1 then
local _,candidatePetID = C_PetJournal.FindPetIDByName((select(1,C_PetJournal.GetPetInfoBySpeciesID(speciesID))))
if not petID then -- if no petID was given, we're looking to replace an as-yet unlearned species
tinsert(candidates,candidatePetID)
else -- a petID was given, we want to replace only with a pet that matches stats
local _,_,level = C_PetJournal.GetPetInfoByPetID(candidatePetID)
local _,maxHealth,power,speed,rarity = C_PetJournal.GetPetStats(candidatePetID)
if level==sanctuaryPet[4] and maxHealth==sanctuaryPet[5] and power==sanctuaryPet[6] and speed==sanctuaryPet[7] and rarity==sanctuaryPet[8] then
tinsert(candidates,candidatePetID)
end
end
else
-- if there are more than 1 copies of the species, we'll need to dig through the roster for the best
for candidatePetID in rematch.Roster:AllOwnedPets() do
local candidateSpeciesID,_,level = C_PetJournal.GetPetInfoByPetID(candidatePetID)
if candidateSpeciesID==speciesID then -- we found one of the intended species
if petID then -- if petID passed, we're looking for a precise version of this pet
if level==sanctuaryPet[4] then
local _, maxHealth, power, speed, rarity = C_PetJournal.GetPetStats(candidatePetID)
if maxHealth==sanctuaryPet[5] and power==sanctuaryPet[6] and speed==sanctuaryPet[7] and rarity==sanctuaryPet[8] then
tinsert(candidates,candidatePetID)
end
end
else -- no petID was passed, we want to find/replace the best version of the species just learned
tinsert(candidates,candidatePetID)
end
-- decrement the count to stop looking once we found all copies of the speciesID
count = count-1
if count==0 then
break
end
end
end
end
if #candidates==0 then
return -- no candidates found :(
end
-- at this point at least one candidate was found to replace this petID
local replaced -- becomes true if any pet was replaced
-- check teams
for key,team in pairs(saved) do
for i=1,3 do
if team[i][1]==(petID or speciesID) then
if rematch:ReplaceCandidateInTeam(key,petID or speciesID) then
replaced = true
end
end
end
end
-- a pet was replaced, update the UI
if replaced and (rematch.Frame:IsVisible() or rematch.Journal:IsVisible()) then
-- in the case of server petID reassignment, this can happen hundreds of times!
-- wait until they're all done before doing an UpdateUI
rematch:StartTimer("UpdateUI",0.1,rematch.UpdateUI)
end
end
function rematch:ReplaceCandidateInTeam(key,petID)
local candidates = rematch.sanctuaryCandidates
local team = saved[key]
for i=1,#candidates do
-- check to make sure candidate is not already in a team before replacing
local found
for j=1,3 do
if team[j][1]==candidates[i] then
found = true
end
end
-- this candidate was not found already in the team, safe to replace
if not found then
for j=1,3 do
if team[j][1]==petID then
team[j][1] = candidates[i]
return true
end
end
end
end
end
-- when all of the above fails to find a replacement, pet loading will load
-- a temporary replacement: the highest level of a speciesID it can find
-- the optional teammates are other petIDs on a team; if passed the temporary petID
-- will not be one of these
function rematch:FindTemporaryPetID(speciesID,teammate1,teammate2,teammate3)
if speciesID then
local count = C_PetJournal.GetNumCollectedInfo(speciesID)
if not count then
return -- this speciesID probably isn't valid
elseif count==1 then -- only one of this species, return sole petID owned
return select(2,C_PetJournal.FindPetIDByName((C_PetJournal.GetPetInfoBySpeciesID(speciesID))))
elseif count>1 then
-- there's more than one of this speciesID, go through all owned pets
local bestPetID
local bestLevel = 0
for candidatePetID in rematch.Roster:AllOwnedPets() do
local candidateSpeciesID,_,level = C_PetJournal.GetPetInfoByPetID(candidatePetID)
if candidateSpeciesID==speciesID and level>bestLevel and candidatePetID~=teammate1 and candidatePetID~=teammate2 and candidatePetID~=teammate3 then
bestPetID = candidatePetID
bestLevel = level
count = count-1
if count==0 then
break
end
end
end
return bestPetID
end
end
end