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.
279 lines
11 KiB
279 lines
11 KiB
local _,rematch = ...
|
|
local settings = rematch.settings
|
|
rematch.roster = {}
|
|
|
|
--[[
|
|
In past versions, rematch.roster was a starting point for any type of changes to the pet list, from adding new pets
|
|
to a pet changing rarity or gaining a level, to even the pet list changing filters.
|
|
|
|
This new roster is treated as a data source only. It will watch for pets being added and removed and keep a list
|
|
of all current pets and species, but that's it.
|
|
|
|
The main list of pets is a list of either "BattlePet-0-etc" petID for owned pets, or a numeric speciesID for
|
|
uncollected pets. Another list is of distinct speciesIDs. These lists should be treated as a data source and are
|
|
not intended to be altered outside this module.
|
|
|
|
The lists can be read by one of three iterator functions:
|
|
for petID in rematch.roster:AllPets() do -- do something -- end -- loop over all petIDs (and unowned speciesIDs)
|
|
for petID in rematch.roster:AllOwnedPets() do -- do something -- end -- loop over all owned petIDs
|
|
for petID in rematch.roster:AllSpecies() do -- do something -- end -- loop over all distinct speciesIDs
|
|
|
|
The number of pets can be read by one of the following:
|
|
rematch.roster:GetNumPets() -- returns the total number of pets, both owned (including duplicates) and uncollected
|
|
rematch.roster:GetNumSpecies() -- returns the number of distinct speciesIDs in the journal, owned or not
|
|
rematch.roster:GetNumOwned() -- returns the number of pets owned by the player, including duplicates
|
|
rematch.roster:GetNumUniqueOwned() -- returns the number of distinct pets owned by the player (ignoring duplicates)
|
|
]]
|
|
|
|
-- master list of pets, either a petID ("BattlePet-0-etc") for owned pets, or a speciesID (42) for uncollected pets
|
|
local allPets = {}
|
|
-- list of all speciesIDs in the journal
|
|
local allSpecies = {}
|
|
-- indexed by speciesID, an ordered list of owned petIDs for the speciesID
|
|
local speciesPetIDs = {}
|
|
-- place to backup journal settings when we update the roster
|
|
local journalBackup = { search="", collected=nil, notCollected=nil, types={}, sources={} }
|
|
|
|
local isUpdatingRoster -- true while roster is updating (while expanding/collapsing journal and clears a frame after)
|
|
local uniqueOwnedCount = 0 -- number of distinct pets owned by the player
|
|
|
|
local waitingForFirstUpdate = true -- becomes nil after first update, to fire REMATCH_PETS_LOADED
|
|
|
|
rematch.events:Register(rematch.roster,"PLAYER_LOGIN",function(self)
|
|
rematch.events:Register(rematch.roster,"NEW_PET_ADDED",rematch.roster.NEW_PET_ADDED)
|
|
rematch.events:Register(rematch.roster,"PET_JOURNAL_PET_DELETED",rematch.roster.PET_JOURNAL_PET_DELETED)
|
|
rematch.events:Register(rematch.roster,"UPDATE_SUMMONPETS_ACTION",rematch.roster.UPDATE_SUMMONPETS_ACTION)
|
|
-- releasing a pet doesn't trigger any event except a PET_JOURNAL_LIST_UPDATE, so firing a fake PET_JOURNAL_PET_DELETD when it happens
|
|
hooksecurefunc(C_PetJournal,"ReleasePetByID",function(petID)
|
|
rematch.events:Fire("PET_JOURNAL_PET_DELETED",petID)
|
|
end)
|
|
end)
|
|
|
|
-- experimenting: is this a reliable event that fires on login after pets are ready?
|
|
function rematch.roster:UPDATE_SUMMONPETS_ACTION(...)
|
|
rematch.timer:Start(0,rematch.roster.Update) -- update allPets and allSpecies
|
|
rematch.events:Unregister(rematch.roster,"UPDATE_SUMMONPETS_ACTION") -- it served its purpose, now rely on add/delete
|
|
end
|
|
|
|
-- fires when a new pet is added to the journal
|
|
function rematch.roster:NEW_PET_ADDED(...)
|
|
if settings.StickyNewPets then
|
|
rematch.sort:AddStickiedPetID(...)
|
|
end
|
|
rematch.timer:Start(0,rematch.roster.Update) -- update allPets and allSpecies
|
|
end
|
|
|
|
-- fires when a pet is removed from the journal
|
|
function rematch.roster:PET_JOURNAL_PET_DELETED(...)
|
|
rematch.timer:Start(0,rematch.roster.Update) -- update allPets and allSpecies
|
|
end
|
|
|
|
function rematch.roster:PET_JOURNAL_LIST_UPDATE(...)
|
|
rematch.events:Unregister(rematch.roster,"PET_JOURNAL_LIST_UPDATE") -- this should've been a one-off call for releasing a pet
|
|
rematch.timer:Start(0,rematch.roster.Update) -- update allPets and allSpecies
|
|
end
|
|
|
|
-- called one frame after the number of owned pets changes; expands the journal (clears filters) if they're not already,
|
|
-- gathers into allPets/allSpecies, and then restores the journal filters to their previous state (if they changed)
|
|
function rematch.roster:Update()
|
|
if isUpdatingRoster or not rematch.main:IsPlayerInWorld() then
|
|
return -- already doing an Update or player is in a loading screen, leave
|
|
end
|
|
rematch.roster:StartUpdatingRoster()
|
|
local isAnyFilterUsed = rematch.roster:IsAnyFilterUsed()
|
|
|
|
if isAnyFilterUsed then -- before expanding filters, confirm any are being used first (can drop from 122ms to 2ms to skip this)
|
|
rematch.roster:ExpandJournal()
|
|
end
|
|
uniqueOwnedCount = 0
|
|
wipe(allPets)
|
|
wipe(allSpecies)
|
|
for speciesID,petIDs in pairs(speciesPetIDs) do
|
|
wipe(petIDs)
|
|
end
|
|
for i=1,C_PetJournal.GetNumPets() do
|
|
local petID,speciesID = C_PetJournal.GetPetInfoByIndex(i)
|
|
tinsert(allPets,petID or speciesID)
|
|
if not speciesPetIDs[speciesID] then
|
|
speciesPetIDs[speciesID] = {}
|
|
end
|
|
if petID then
|
|
if #speciesPetIDs[speciesID]==0 then
|
|
uniqueOwnedCount = uniqueOwnedCount + 1
|
|
end
|
|
tinsert(speciesPetIDs[speciesID],petID)
|
|
end
|
|
end
|
|
-- now rebuild allSpecies
|
|
for speciesID in pairs(speciesPetIDs) do
|
|
tinsert(allSpecies,speciesPetIDs)
|
|
end
|
|
if isAnyFilterUsed then
|
|
rematch.roster:RestoreJournal()
|
|
end
|
|
|
|
rematch.filters:ForceUpdate() -- set dirty flag on filter so list updates
|
|
|
|
rematch.timer:Start(0,rematch.roster.FinishUpdatingRoster)
|
|
end
|
|
|
|
-- external so speciesInfo can also use the Expand/RestoreJournal
|
|
function rematch.roster:StartUpdatingRoster()
|
|
isUpdatingRoster = true
|
|
end
|
|
|
|
-- delayed a frame in case a NEW_PET_ADDED and UPDATE_SUMMONPETS_ACTION fires in pairs; clears flag that says we're updating
|
|
-- and if this is the first update, then fire off a REMATCH_PETS_LOADED for anything waiting for pets to load on login
|
|
function rematch.roster:FinishUpdatingRoster()
|
|
isUpdatingRoster = nil
|
|
--rematch.savedTeams:ValidateAllTeams() -- if pets leaving/adding, adjust teams that might be impacted
|
|
if waitingForFirstUpdate then
|
|
waitingForFirstUpdate = nil
|
|
rematch.events:Fire("REMATCH_PETS_LOADED")
|
|
end
|
|
rematch.events:Fire("REMATCH_PETS_CHANGED")
|
|
end
|
|
|
|
--[[ counts ]]
|
|
|
|
-- returns the total number of pets, both owned (including duplicates) and uncollected
|
|
function rematch.roster:GetNumPets()
|
|
return #allPets
|
|
end
|
|
|
|
-- returns the number of distinct speciesIDs in the journal, owned or not
|
|
function rematch.roster:GetNumSpecies()
|
|
return #allSpecies
|
|
end
|
|
|
|
-- returns the number of pets owned by the player, including duplicates
|
|
function rematch.roster:GetNumOwned()
|
|
return select(2,C_PetJournal.GetNumPets())
|
|
end
|
|
|
|
-- returns the number of unique pets owned by the player (specifically, the number of different speciesIDs the player owns)
|
|
function rematch.roster:GetNumUniqueOwned()
|
|
return uniqueOwnedCount
|
|
end
|
|
|
|
-- returns a small ordered list of petIDs that are owned for the given speciesID (honor system here, nothing should update this return)
|
|
function rematch.roster:GetSpeciesPetIDs(speciesID)
|
|
return speciesID and speciesPetIDs[speciesID]
|
|
end
|
|
|
|
--[[ journal filter shenanigans ]]
|
|
|
|
-- since there is no C_PetJournal.GetSearchFilter, we need to watch for it changing
|
|
hooksecurefunc(C_PetJournal,"SetSearchFilter",function(search)
|
|
if not isUpdatingRoster then
|
|
journalBackup.search = search or ""
|
|
end
|
|
end)
|
|
hooksecurefunc(C_PetJournal,"ClearSearchFilter",function()
|
|
if not isUpdatingRoster then
|
|
journalBackup.search = ""
|
|
end
|
|
end)
|
|
|
|
-- clears all filters in the pet journal so all pets can be captured in roster:Update()
|
|
function rematch.roster:ExpandJournal()
|
|
journalBackup.collected = C_PetJournal.IsFilterChecked(LE_PET_JOURNAL_FILTER_COLLECTED)
|
|
journalBackup.notCollected = C_PetJournal.IsFilterChecked(LE_PET_JOURNAL_FILTER_NOT_COLLECTED)
|
|
for i=1,C_PetJournal.GetNumPetTypes() do
|
|
journalBackup.types[i] = C_PetJournal.IsPetTypeChecked(i)
|
|
end
|
|
for i=1,C_PetJournal.GetNumPetSources() do
|
|
journalBackup.sources[i] = C_PetJournal.IsPetSourceChecked(i)
|
|
end
|
|
C_PetJournal.ClearSearchFilter()
|
|
C_PetJournal.SetFilterChecked(LE_PET_JOURNAL_FILTER_COLLECTED,true)
|
|
C_PetJournal.SetFilterChecked(LE_PET_JOURNAL_FILTER_NOT_COLLECTED,true)
|
|
C_PetJournal.SetAllPetSourcesChecked(true)
|
|
C_PetJournal.SetAllPetTypesChecked(true)
|
|
end
|
|
|
|
-- restores all filters that were cleared in roster:ExpandJournal()
|
|
function rematch.roster:RestoreJournal()
|
|
C_PetJournal.SetFilterChecked(LE_PET_JOURNAL_FILTER_COLLECTED,journalBackup.collected)
|
|
C_PetJournal.SetFilterChecked(LE_PET_JOURNAL_FILTER_NOT_COLLECTED,journalBackup.notCollected)
|
|
for i=1,C_PetJournal.GetNumPetSources() do
|
|
C_PetJournal.SetPetSourceChecked(i,journalBackup.sources[i])
|
|
end
|
|
for i=1,C_PetJournal.GetNumPetTypes() do
|
|
C_PetJournal.SetPetTypeFilter(i,journalBackup.types[i])
|
|
end
|
|
C_PetJournal.SetSearchFilter(journalBackup.search)
|
|
end
|
|
|
|
-- returns true if any journal filters are used, since there's no need to expand/restore if it's already expanded
|
|
-- using this to skip the expand/restore drops an expand/capture/restore from 122ms to 2ms (!!!)
|
|
function rematch.roster:IsAnyFilterUsed()
|
|
if journalBackup.search~="" then
|
|
return true -- search is used
|
|
end
|
|
if not C_PetJournal.IsFilterChecked(LE_PET_JOURNAL_FILTER_COLLECTED) then
|
|
return true -- collected is unchecked
|
|
end
|
|
if not C_PetJournal.IsFilterChecked(LE_PET_JOURNAL_FILTER_NOT_COLLECTED) then
|
|
return true -- not collected is unchecked
|
|
end
|
|
for i=1,C_PetJournal.GetNumPetTypes() do
|
|
if not C_PetJournal.IsPetTypeChecked(i) then
|
|
return true -- a pet type is unchecked
|
|
end
|
|
end
|
|
for i=1,C_PetJournal.GetNumPetSources() do
|
|
if not C_PetJournal.IsPetSourceChecked(i) then
|
|
return true -- a pet source is unchecked
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
--[[ iterator functions ]]
|
|
|
|
-- loops over allPets, which is a list of owned petIDs ("BattlePet-0-etc") and unowned speciesIDs (42)
|
|
function rematch.roster:AllPets()
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
if i <= #allPets then
|
|
return allPets[i]
|
|
end
|
|
end
|
|
end
|
|
|
|
-- loops over all owned petIDs
|
|
function rematch.roster:AllOwnedPets()
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
if i <= #allPets then
|
|
if type(allPets[i])=="string" then
|
|
return allPets[i]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- loops over allSpecies, or all distinct speciesIDs
|
|
function rematch.roster:AllSpecies()
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
if i <= #allSpecies then
|
|
return allSpecies[i]
|
|
end
|
|
end
|
|
end
|
|
|
|
-- loops over all petIDs owned for the given speciesID
|
|
function rematch.roster:AllSpeciesPetIDs(speciesID)
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
if speciesPetIDs[speciesID] and i<=#speciesPetIDs[speciesID] then
|
|
return speciesPetIDs[speciesID][i]
|
|
end
|
|
end
|
|
end
|
|
|