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.

697 lines
31 KiB

--[[
Rematch refers to pets as a single number or string, depending on their
context. This reference, called a petID, can be one of seven idTypes:
idType example petID value description
---------- --------------------- -----------------------------------
"pet" "Battle-0-0000000etc" a player-owned pet in the journal
"species" 42 speciesID species number
"leveling" 0 leveling slot
"ignored" "ignored" ignored slot
"link" "battlepet:42:25:etc" linked pet
"battle" "battle:2:1" pet in battle (battle:owner:index)
"random" "random:10" random mechanical pet (random:0 for any pet type)
"unknown" (anything, even nil) indecipherable/undefined pet
To simplify getting information about these different types of pets, to
eliminate the scattered code to independently call the various API through
C_PetJournal and C_PetBattles, and to reduce redundant API calls for
information already retrieved (or information not used!), this module
encapsulates a "front end" for information about pets.
To use, first create a petInfo instance:
local petInfo = rematch:CreatePetInfo()
Then fetch a petID to make it the pet of interest:
petInfo:Fetch(petID)
After a pet of interest is fetched, simply index the stat you want:
print(petInfo.name,"is level",petInfo.level,"and breed",petInfo.breedName)
The stat can be any of these:
petID: this is the pet reference Fetched (string, number, link, etc)
idType: "pet" "species" "leveling" "ignored" "link" "battle" "random" or "unknown" (string)
speciesID: numeric speciesID of the pet (integer)
customName: user-renamed pet name (string)
speciesName: name of the species (string)
name: customName if defined, speciesName otherwise (string)
level: whole level 1-25 (integer)
xp: amount of xp in current level (integer)
maxXp: total xp to reach next level (integer)
fullLevel: level+xp/maxXp (float)
displayID: id of the pet's skin (integer)
isFavorite: whether pet is favorited (bool)
icon: fileID of pet's icon or specific filename (integer or string)
petType: numeric type of pet 1-10 (integer)
creatureID: npcID of summoned pet (integer)
sourceText: formatted text about where pet is from (string)
loreText: "back of the card" lore (string)
isWild: whether the pet is found in the wild (bool)
canBattle: whether pet can battle (bool)
isTradable: whether pet can be caged (bool)
isUnique: whether only one of pet can be learned (bool)
isObtainable: whether this pet is in the journal (bool)
health: current health of the pet (integer)
maxHealth: maximum health of the pet (integer)
power: power stat of the pet (integer)
speed: speed stat of the pet (integer)
rarity: rarity 1-4 of pet (integer)
isDead: whether the pet is dead (bool)
isInjured: whether the pet has less than max health (bool)
isSummonable: whether the pet can be summoned (bool)
isRevoked: whether the pet is revoked (bool)
abilityList: table of pet's abilities (table)
levelList: table of pet's ability levels (table)
valid: whether the petID is valid and petID is not missing (bool)
owned: whether the petID is a valid pet owned by the player (bool)
count: number of pet the player owns (integer)
maxCount: maximum number of this pet the player can own (integer)
hasBreed: whether pet can battle and there's a breed source (bool)
breedID: 3-12 for known breeds, 0 for unknown breed, nil for n/a (integer)
breedName: text version of breed like P/P or S/B (string)
possibleBreedIDs: list of breedIDs possible for the pet's species (table)
possibleBreedNames: list of breedNames possible for the pet's species (table)
numPossibleBreeds: number of known breeds for the pet (integer)
needsFanfare: whether a pet is wrapped (bool)
battleOwner: whether ally(1) or enemy(2) pet in battle (integer)
battleIndex: 1-3 index of pet in battle (integer)
isSlotted: whether pet is slotted (bool)
inTeams: whether pet is in any teams (pet and species idTypes only) (bool)
numTeams: number of teams the pet belongs to (pet and species only) (integer)
sourceID: the source index (1=Drop, 2=Quest, 3=Vendor, etc) of the pet (integer)
moveset: the exact moveset of the pet ("123,456,etc") (string)
speciesAt25: whether the pet has a version at level 25 (bool)
hasNotes: whether the pet has notes (bool)
notes: the text of the pet's notes (string)
isLeveling: whether the pet is in the queue (bool)
isSummoned: whether the pet is currently summoned (bool)
expansionID: the numeric index of the expansion the pet is from: 0=classic, 1=BC, 2=WotLK, etc. (integer)
expansionName: the name of the expansion the pet is from (string)
How it works:
petInfo:Fetch(petID) will check if the petID is different from the last-
fetched pet. If so, it will wipe the existing information and store the
petID and idType within the table, ready for stats to be queried/indexed.
The created petInfo table has a __index metamethod to look up indexes
that don't exist.
If a petInfo[stat] has no value, the __index metamethod will call the
appropriate API (depending on the idType of the pet) and fill in its
value. Future references to petInfo[stat] will have a value and not
invoke a __index.
Also:
rematch.petInfo and rematch.altInfo are defined at the end of this file
for use throughout the addon.
The script filter system has its own petInfo that's already fetched for each
pet. Script filters do not need to fetch a the current pet.
petInfo:Reset() will force a wipe of information.
When the petID is guaranteed to be from the journal (either a valid,
owned petID string or speciesID), Fetch(petID,true) will skip the
test of its type to improve performance.
link format:
"battlepet:<speciesID>:<level>:<rarity>:<health>:<power>:<speed>"
]]
local _,L = ...
local rematch = Rematch
local GetPetInfoByPetID = C_PetJournal.GetPetInfoByPetID
local GetPetInfoBySpeciesID = C_PetJournal.GetPetInfoBySpeciesID
-- every petInfo key added needs to be added here; key="Group", where Group is a key in queryAPI
local apiByStat = {
speciesID="Info", customName="Info", level="Info", xp="Info", maxXp="Info",
displayID="Info", isFavorite="Info", speciesName="Info", name="Info", icon="Info",
petType="Info", creatureID="Info", sourceText="Info", loreText="Info", isWild="Info",
canBattle="Info", isTradable="Info", isUnique="Info", isObtainable="Info", health="Stats",
maxHealth="Stats", power="Stats", speed="Stats", rarity="Stats", isDead="Dead", isInjured="Dead",
isSummonable="SummonInfo", summonError="SummonInfo", summonErrorText="SummonInfo", summonShortError="SummonInfo",
isRevoked="Other", abilityList="Abilities", levelList="Abilities",
valid="Valid", count="Count", maxCount="Count", fullLevel="FullLevel", needsFanfare="Fanfare",
breedID="Breed", breedName="Breed", possibleBreedIDs="PossibleBreeds",
possibleBreedNames="PossibleBreeds", numPossibleBreeds="PossibleBreeds", hasBreed="Breed",
owned="Valid", battleOwner="Battle", battleIndex="Battle", isSlotted="Slotted",
inTeams="Teams", numTeams="Teams", sourceID="Source", moveset="Moveset", speciesAt25="SpeciesAt25",
notes="Notes", hasNotes="Notes", isLeveling="IsLeveling", isSummoned="IsSummoned",
expansionID="Expansion", expansionName="Expansion",
}
-- indexed by petInfo table reference, this will contain reused tables like fetchedAPI
-- and abilityList to prevent garbage creation
local hiddenTables = {}
-- for Breed stat group
local breedSource -- addon that's providing breed data: "BattlePetBreedID", "PetTracker_Breeds" or "LibPetBreedInfo-1.0"
local breedLib -- for LibPetBreedInfo-1.0 only
local breedNames = {nil,nil,"B/B","P/P","S/S","H/H","H/P","P/S","H/S","P/B","S/B","H/B"}
-- in general, when a pet is added alongside others in an expansion they all clump to a range of speciesIDs
-- (with some outliers listed below). this is a list of expansions and the range of speciesIDs in that
-- epxansion: [expansionID] = {firstSpeciesID,lastSpeciesID}
local expansionRanges = {
[0] = {39,128}, -- Classic
[1] = {130,186}, -- Burning Crusade
[2] = {187,258}, -- Wrath of the Lich King
[3] = {259,343}, -- Cataclysm
[4] = {346,1365}, -- Mists of Pandaria
[5] = {1384,1693}, -- Warlords of Draenor
[6] = {1699,2163}, -- Legion
[7] = {2165,2872}, -- Battle for Azeroth
[8] = {2878,3255}, -- Shadowlands
[9] = {3256,9999}, -- Dragonflight
}
-- the majority of pets fall into a range for each expansion above, except for some outliers. these are the
-- species ID and the expansionID they belong to
local expansionOutliers = {
[1563] = 0, -- Bronze Whelpling
[191] = 1, -- Clockwork Rocket Bot
[1073] = 1, -- Terky
[1351] = 2, -- Macabre Marionette
[220] = 3, -- Withers
[255] = 3, -- Celestial Dragon
[231] = 4, -- Jade Tiger
[1386] = 4, -- Dread Hatchling
[1943] = 4, -- Noblegarden Bunny
[115] = 5, -- Land Shark
[1725] = 5, -- Grumpling
[1730] = 5, -- Spectral Spinner
[1740] = 5, -- Ghost Maggot
[1741] = 5, -- Ghastly Rat
[1761] = 5, -- Echo Batling
[1764] = 5, -- Energized Manafiend
[1765] = 5, -- Empyreal Manafiend
[1766] = 5, -- Empowered Manafiend
[1828] = 5, -- Baby Winston
[2143] = 7, -- Tottle
[2157] = 7, -- Dart
[2798] = 8, -- Plagueborn Slime
}
-- short reason that the pet can't be summoned
local summonErrors = {
[Enum.PetJournalError.JournalIsLocked] = L["Journal Is Locked"],
[Enum.PetJournalError.InvalidFaction] = L["Wrong Faction"],
[Enum.PetJournalError.InvalidCovenant] = L["Wrong Covenant"]
}
-- getIDType takes a petID and returns what type of id it is
-- possible: "pet" "species" "leveling" "ignored" "link" "battle" "random" or "unknown"
local function getIDType(id)
local idType = type(id)
if idType=="string" then
if id:match("^BattlePet%-%x%-%x%x%x%x%x%x%x%x%x%x%x%x$") then
return "pet"
elseif id:match("battlepet:%d+:%d+:%d+:%d+:%d+:%d+") then
return "link"
elseif id:match("battle:%d:%d") then
return "battle"
elseif id:match("random:%d+") then
return "random"
elseif id=="ignored" then
return "ignored"
end
elseif idType=="number" then
if id>0 then
return "species"
elseif id==0 then
return "leveling"
end
end
return "unknown" -- if we reached here, no idea what this petID is!
end
-- used in Info functions to gather info by petID (BattlePet-0-000etc)
local function fillInfoByPetID(self,petID)
local customName, speciesName -- prevent a __index lookup if petID is invalid or not renamed
self.speciesID,customName,self.level,self.xp,self.maxXp,self.displayID,
self.isFavorite,speciesName,self.icon,self.petType,self.creatureID,
self.sourceText,self.loreText,self.isWild,self.canBattle,self.isTradable,
self.isUnique,self.isObtainable = GetPetInfoByPetID(petID)
self.name = customName or speciesName
self.customName = customName
self.speciesName = speciesName
end
-- used in Info functions to gather info by speciesID (42)
local function fillInfoBySpeciesID(self,speciesID)
local speciesName -- prevent a __index lookup if speciesID is invalid
speciesName,self.icon,self.petType,self.creatureID,self.sourceText,
self.loreText,self.isWild,self.canBattle,self.isTradable,self.isUnique,
self.isObtainable,self.displayID = GetPetInfoBySpeciesID(speciesID)
self.speciesName = speciesName
self.name = speciesName
self.speciesID = speciesID
if not self.icon then
self.icon = "Interface\\Icons\\INV_Pet_BattlePetTraining"
end
end
-- indexed by API group ("Info", "Stats", etc) these are the functions that are called
-- if fetchedAPI[key] is nil; they fill petInfo with values depending on the pet idType
local queryAPIs = {
Info = function(self)
-- the majority of info is behind GetPetInfoByPetID and GetPetInfoBySpeciesID
local idType = self.idType
if idType=="pet" then
fillInfoByPetID(self,self.petID)
elseif idType=="species" then
fillInfoBySpeciesID(self,self.petID)
elseif idType=="leveling" then
self.name = L["Leveling Pet"]
self.icon = "Interface\\AddOns\\Rematch\\Textures\\LevelingIcon.blp"
elseif idType=="ignored" then
self.name = L["Ignored Pet"]
self.icon = "Interface\\AddOns\\Rematch\\Textures\\IgnoredIcon.blp"
elseif idType=="link" then
local speciesID,level = self.petID:match("battlepet:(%d+):(%d+):")
speciesID = tonumber(speciesID)
if speciesID then
fillInfoBySpeciesID(self,speciesID)
self.level = tonumber(level)
end
elseif idType=="battle" then
local owner = self.battleOwner
local index = self.battleIndex
if owner==1 then -- for ally battle pets, just use the loaded pet
local petID = C_PetJournal.GetPetLoadOutInfo(index)
if petID then
fillInfoByPetID(self,petID)
end
elseif owner==2 then
local speciesID = C_PetBattles.GetPetSpeciesID(owner,index)
if speciesID then
fillInfoBySpeciesID(self,speciesID)
self.level = C_PetBattles.GetLevel(owner,index)
self.displayID = C_PetBattles.GetDisplayID(owner,index)
end
end
elseif idType=="random" then
-- petType always defined as 0-10 for random pets
local petType = math.min(10,math.max(0,tonumber(self.petID:match("random:(%d+)")) or 0))
self.petType = petType
-- name is "Random Pet" or "Random Humanoid", "Random Dragonkin", etc
local suffix = PET_TYPE_SUFFIX[petType]
self.name = suffix and format(L["Random %s"],_G["BATTLE_PET_NAME_"..petType]) or L["Random Pet"]
self.icon = suffix and format("Interface\\Icons\\Icon_PetFamily_%s",suffix) or "Interface\\Icons\\INV_Misc_Dice_02"
else
self.name = L["Unknown"]
self.icon = "Interface\\Icons\\INV_Misc_QuestionMark"
end
end,
-- only owned pets, linked pets and battle pets have real stats
Stats = function(self)
local idType = self.idType
if idType=="pet" then
self.health,self.maxHealth,self.power,self.speed,self.rarity = C_PetJournal.GetPetStats(self.petID)
elseif idType=="link" then
local rarity,health,power,speed = self.petID:match("battlepet:%d+:%d+:(%d+):(%d+):(%d+):(%d+)")
if rarity then
self.rarity = tonumber(rarity)+1 -- links are 0-3 rarity intead of 1-4
self.health = tonumber(health)
self.maxHealth = tonumber(health)
self.power = tonumber(power)
self.speed = tonumber(speed)
end
elseif idType=="battle" then -- pets in a battle fetch live stats (but note values cache!)
local owner = self.battleOwner
local index = self.battleIndex
if C_PetBattles.GetPetSpeciesID(owner,index) then
self.rarity = C_PetBattles.GetBreedQuality(owner,index)
self.health = C_PetBattles.GetHealth(owner,index)
self.maxHealth = C_PetBattles.GetMaxHealth(owner,index)
self.power = C_PetBattles.GetPower(owner,index)
self.speed = C_PetBattles.GetSpeed(owner,index)
end
end
end,
-- intended to be functions that are only called for journal listing; may separate these later
Other = function(self)
if self.idType=="pet" then
local petID = self.petID
--self.isSummonable = C_PetJournal.PetIsSummonable(petID)
self.isRevoked = C_PetJournal.PetIsRevoked(petID)
end
end,
-- isSummonable moved to this for new GetPetSummonInfo
SummonInfo = function(self)
if self.idType=="pet" then
local isSummonable, error, errorText = C_PetJournal.GetPetSummonInfo(self.petID)
if not isSummonable and error==Enum.PetJournalError.PetIsDead then
isSummonable = true -- treating summonable pets that are just dead as summonable
end
self.isSummonable = isSummonable
self.summonError = error
self.summonErrorText = errorText -- this text is a bit too long for pet card but usable in tooltips
self.summonShortError = error and summonErrors[error] or L["Can't Summon"] -- usable for pet card
else
self.isSummonable = true
end
end,
-- fills petInfo.abilityList and .levelList
Abilities = function(self)
if self.speciesID then
local abilityList = hiddenTables[self].abilityList
local levelList = hiddenTables[self].levelList
C_PetJournal.GetPetAbilityList(self.speciesID,abilityList,levelList)
self.abilityList = abilityList
self.levelList = levelList
end
end,
-- petInfo.valid verifies the pet contains information (not a reassigned petID or bad speciesID)
Valid = function(self)
local idType = self.idType
if idType=="pet" and self.speciesID then -- if speciesID read ok then "pet" petID is functional
self.valid = true
self.owned = true -- owned is only true if regular petID is valid
elseif (idType=="species" and self.name) or (idType=="leveling" or idType=="ignored" or idType=="random") or (idType=="link" and self.name) or (idType=="battle" and self.name) then
self.valid = true
self.owned = false
else
self.valid = false
end
end,
-- fills petInfo.count and petInfo.maxCount with the number of a species the player owns
Count = function(self)
if self.speciesID then
self.count,self.maxCount = C_PetJournal.GetNumCollectedInfo(self.speciesID)
end
end,
-- the regular level is an Info function (which this will use if .level not defined)
FullLevel = function(self)
local xp = self.xp
if xp then
self.fullLevel = self.level + (xp/self.maxXp)
else
self.fullLevel = self.level
end
end,
-- whether a pet is wrapped
Fanfare = function(self)
self.needsFanfare = self.idType=="pet" and C_PetJournal.PetNeedsFanfare(self.petID)
end,
-- whether a pet isDead
Dead = function(self)
if self.maxHealth and self.maxHealth > 0 then
self.isDead = self.health==0
self.isInjured = self.health<self.maxHealth
end
end,
-- this fills petInfo.breedID and petInfo.breedName depending on which breed addon is enabled, if any
Breed = function(self)
local source = rematch:GetBreedSource()
local idType = self.idType
if source and self.valid and self.canBattle and (idType=="pet" or idType=="link" or idType=="battle") then
local breedID, breedName
if source=="BattlePetBreedID" then
if idType=="pet" or idType=="link" then
breedID = BPBID_Internal.CalculateBreedID(self.speciesID,self.rarity,self.level,self.maxHealth,self.power,self.speed,false,false)
elseif idType=="battle" then
breedID = BPBID_Internal.breedCache[self.battleIndex + (self.battleOwner==2 and 3 or 0)]
end
elseif source=="PetTracker_Breeds" then
if idType=="pet" then
breedID = PetTracker.Journal:GetBreed(self.petID)
elseif idType=="link" then
breedID = PetTracker.Predict:Breed(self.speciesID,self.level,self.rarity,self.maxHealth,self.power,self.speed)
elseif idType=="battle" then
breedID = PetTracker.Battle:Get(self.battleOwner,self.battleIndex):GetBreed()
end
if breedID then
breedName = PetTracker:GetBreedIcon(breedID,.85) -- using PetTracker's breed icon
end
elseif source=="PetTracker" then
if idType=="pet" then
breedID = PetTracker.Pet(self.petID):GetBreed()
elseif idType=="link" then
breedID = PetTracker.Predict:Breed(self.speciesID,self.level,self.rarity,self.maxHealth,self.power,self.speed)
elseif idType=="battle" then
breedID = PetTracker.Battle(self.battleOwner,self.battleIndex):GetBreed()
end
if breedID and not RematchSettings.PetTrackerLetterBreeds then
breedName = PetTracker.Breeds:Icon(breedID,0.85)
end
elseif source=="LibPetBreedInfo-1.0" then
if idType=="pet" then
breedID = breedLib:GetBreedByPetID(self.petID)
elseif idType=="link" then
breedID = breedLib:GetBreedByStats(self.speciesID,self.level,self.rarity,self.maxHealth,self.power,self.speed)
elseif idType=="battle" then
breedID = breedLib:GetBreedByPetBattleSlot(self.battleOwner,self.battleIndex)
end
end
-- make unknown breeds breedID 0 and named "NEW" if no known breeds or "???" otherwise
if type(breedID)~="number" then
breedID = 0
breedName = self.numPossibleBreeds==0 and "NEW" or "???"
end
self.breedID = breedID
self.breedName = breedName or breedNames[breedID]
self.hasBreed = true
else
self.hasBreed = false
end
end,
-- for possibleBreedIDs and possibleBreedNames, only need a speciesID (and a breed source)
PossibleBreeds = function(self)
wipe(hiddenTables[self].possibleBreedIDs)
wipe(hiddenTables[self].possibleBreedNames)
local possibleBreedIDs = hiddenTables[self].possibleBreedIDs
local possibleBreedNames = hiddenTables[self].possibleBreedNames
local source = rematch:GetBreedSource()
local speciesID = self.speciesID
if source and type(speciesID)=="number" and self.canBattle then
local data -- the table that contains possible breeds
if source=="BattlePetBreedID" then
if not BPBID_Arrays.BreedsPerSpecies then
BPBID_Arrays.InitializeArrays()
end
data = BPBID_Arrays.BreedsPerSpecies[speciesID]
elseif source=="PetTracker_Breeds" then
data = PetTracker.Breeds[speciesID]
elseif source=="PetTracker" then
data = PetTracker.SpecieBreeds[speciesID]
elseif source=="LibPetBreedInfo-1.0" then
data = breedLib:GetAvailableBreeds(speciesID)
end
-- if there's a table of breeds, copy them to possibleBreeds
if data and type(data)=="table" then
for _,breed in ipairs(data) do
tinsert(possibleBreedIDs,breed)
if source=="PetTracker_Breeds" then
tinsert(possibleBreedNames,PetTracker:GetBreedIcon(breed,0.85))
elseif source=="PetTracker" and not RematchSettings.PetTrackerLetterBreeds then
tinsert(possibleBreedNames,PetTracker.Breeds:Icon(breed,0.85))
else
tinsert(possibleBreedNames,breedNames[breed])
end
end
end
self.possibleBreedIDs = possibleBreedIDs
self.possibleBreedNames = possibleBreedNames
self.numPossibleBreeds = #possibleBreedIDs
end
end,
-- pulls battleOwner and battleIndex from the "battle" petID
Battle = function(self)
if self.idType=="battle" then
local owner,index = self.petID:match("battle:(%d):(%d)")
self.battleOwner = tonumber(owner)
self.battleIndex = tonumber(index)
end
end,
-- whether the pet is slotted
Slotted = function(self)
local idType = self.idType
self.isSlotted = (idType=="pet" and C_PetJournal.PetIsSlotted(self.petID)) or (idType=="battle" and self.battleOwner==1)
end,
-- pulls the number of teams the pet of interest belongs to
Teams = function(self)
-- defining the actual stats inTeams and numTeams
local idType = self.idType
if idType=="pet" or idType=="species" then
local numTeams = rematch.petsInTeams[self.petID] or 0
self.inTeams = numTeams>0
self.numTeams = numTeams
end
end,
-- sourceID is source pet filter category (1=Drop, 2=Vendor, 3=Quest, etc)
Source = function(self)
self.sourceID = rematch.sourceIDs[self.speciesID]
end,
-- moveset is the list of abilityIDs separated by commas like "429,492,538,535,357,536" for a black tabby cat
Moveset = function(self)
self.moveset = rematch.movesetsBySpecies[self.speciesID]
end,
SpeciesAt25 = function(self)
self.speciesAt25 = rematch.speciesAt25[self.speciesID] and true
end,
Notes = function(self)
local speciesID = self.speciesID
self.notes = RematchSettings.PetNotes[speciesID]
if self.notes then
self.hasNotes = true
end
end,
IsLeveling = function(self)
self.isLeveling = self.owned and rematch:IsPetLeveling(self.petID)
end,
IsSummoned = function(self)
self.isSummoned = C_PetJournal.GetSummonedPetGUID() == self.petID
end,
Expansion = function(self)
local speciesID = self.speciesID
local expansionID
local idType = self.idType
if idType=="leveling" or idType=="random" or idType=="ignored" then
return
end
-- first check if this is one of the species that doesn't fit into an expansion's range
if expansionOutliers[speciesID] then
expansionID = expansionOutliers[speciesID]
self.expansionID = expansionID
self.expansionName = _G["EXPANSION_NAME"..expansionID]
return
end
-- start at expansionID 0 and work upward, comparing speciesID to the expansion's range of speciesIDs
local expansionID = 0
while expansionRanges[expansionID] do
if speciesID >= expansionRanges[expansionID][1] and speciesID <= expansionRanges[expansionID][2] then
self.expansionID = expansionID
self.expansionName = _G["EXPANSION_NAME"..expansionID]
return
end
expansionID = expansionID + 1
end
end,
}
-- rematch:GetBreedSource() is used by the Breed and PossibleBreeds API
-- the first time this runs it looks for a breed addon enabled and returns it
-- future runs will just return the saved source (so this only looks for a breed addon once)
-- addons are used in this priority: BattlePetBreedID, PetTracker_Breeds then LibPetBreedInfo-1.0
function rematch:GetBreedSource()
if breedSource==nil then
if IsAddOnLoaded("BattlePetBreedID") then
breedSource = "BattlePetBreedID"
return "BattlePetBreedID"
elseif IsAddOnLoaded("PetTracker_Breeds") and GetAddOnMetadata("PetTracker_Breeds","Version")~="7.1.4" then
if not PetTracker.Pet then -- only set this source if new PetTracker isn't enabled (PetTracker has its own issues when this is enabled alongside newer versions that don't include this)
breedSource = "PetTracker_Breeds"
return "PetTracker_Breeds"
end
elseif IsAddOnLoaded("PetTracker") and PetTracker and PetTracker.Pet and PetTracker.Pet.GetBreed then
breedSource = "PetTracker"
return "PetTracker"
end
-- one of the sources is not loaded, try loading LibPetBreedInfo separately
LoadAddOn("LibPetBreedInfo-1.0")
if LibStub then
for lib in LibStub:IterateLibraries() do
if lib=="LibPetBreedInfo-1.0" then
breedLib = LibStub("LibPetBreedInfo-1.0")
if lib then
breedSource = lib
return lib
end
end
end
end
breedSource = false -- none found, only attempt to find a source once
end
return breedSource
end
-- either "text" or "icon", the format of breed to display
function rematch:GetBreedFormat()
local source = rematch:GetBreedSource()
if source=="PetTracker_Breeds" or (source=="PetTracker" and not RematchSettings.PetTrackerLetterBreeds) then
return "icon"
else
return "text"
end
end
-- returns the name of a breed by its ID (used by PetMenus' breed menu; not petInfo)
function rematch:GetBreedNameByID(breedID)
local breedSource = rematch:GetBreedSource()
if breedSource=="PetTracker_Breeds" then
return PetTracker:GetBreedIcon(breedID,.85)
elseif breedSource=="PetTracker" and PetTracker.Breeds.Names[breedID] and not RematchSettings.PetTrackerLetterBreeds then
return PetTracker.Breeds:Icon(breedID,.85) .. " " .. PetTracker.Breeds.Names[breedID]
else
return breedNames[breedID]
end
end
local reset -- function used in fetch and petInfo, definining it after fetch
-- makes a petID the "pet of interest" to a petInfo(self)
-- if journal is true, the petID is guaranteed to be a valid owned petID or a valid speciesID
local function fetch(self,petID,journal)
if petID~=self.petID then
reset(self)
self.petID = petID
if journal then
self.idType = type(petID)=="string" and "pet" or "species"
else
self.idType = getIDType(petID)
end
end
return self
end
-- wipes a petInfo(self) for new data
function reset(self)
wipe(self)
wipe(hiddenTables[self].fetchedAPI)
self.Fetch = fetch
self.Reset = reset
end
-- __index lookup when stat(index) is nil
-- if its API has not been fetched yet, call the API to fill in stats
-- then return the fetched value (or the old nil if it's been fetched before)
local function lookup(self,stat)
local api = apiByStat[stat]
local fetchedAPI = hiddenTables[self].fetchedAPI
if api and not fetchedAPI[api] and queryAPIs[api] then
fetchedAPI[api] = true
queryAPIs[api](self)
end
return rawget(self,stat)
end
-- this creates a new petInfo and returns it
function rematch:CreatePetInfo()
local info = {}
hiddenTables[info] = {
fetchedAPI = {}, -- lookup of API functions that have been called for current pet
abilityList = {}, -- cached result of C_PetJournal.GetPetAbilityList
levelList = {}, -- cached result of C_PetJournal.GetPetAbilityList
possibleBreedIDs = {}, -- table of breedIDs possible for a speciesID
possibleBreedNames = {}, -- table of breedNames possible for a speciesID
}
reset(info)
setmetatable(info,{__index=lookup})
return info
end
-- create two petInfos for use in the addon
rematch.petInfo = rematch:CreatePetInfo()
rematch.altInfo = rematch:CreatePetInfo()