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.

575 lines
20 KiB

local PetJournalEnhanced = LibStub("AceAddon-3.0"):GetAddon("PetJournalEnhanced")
local Sorting = PetJournalEnhanced:NewModule("Sorting", "AceEvent-3.0")
local BreedInfo = LibStub("LibPetBreedInfo-1.0")
local BREED_HIGH_CONFIDENCE = 2
local MAX_BALANCED = 1
local MAX_SPEED = 2
local MAX_STAMINA = 3
local MAX_ATTACK = 4
local ASCENDING = 1
local DESCENDING = 2
local USER = nil
-- GLOBALS: C_PetJournal PetJournal LE_PET_JOURNAL_FILTER_COLLECTED LE_PET_JOURNAL_FILTER_NOT_COLLECTED PetJournalSearchBox
local petMapping = {}
local SetPet, GetPet
do
local petStore = {}
function SetPet(pet)
if pet.isOwned then
petStore[pet.petID] = pet
else
petStore[pet.speciesID] = pet
end
end
function Sorting:GetPet(petID)
return petStore[petID]
end
end
local GetSortFunctions
do
local function GetCompareFunc(var,func,direction)
return function(a,b)
local order = Sorting.db.global.sorting.order
local avar = a[var]
local bvar = b[var]
if type(avar) == "boolean" then
avar = avar and 1 or 0
bvar = bvar and 1 or 0
end
if avar == bvar and func then
return func(a,b)
end
if direction then
if direction == ASCENDING then
return avar < bvar
elseif direction == DESCENDING then
return avar > bvar
end
elseif order == ASCENDING then
return avar < bvar
elseif order == DESCENDING then
--if not avar or not bvar then print(avar,bvar,var) print(a.name,b.name) end
return avar > bvar
end
end
end
local function ComposeSortFunction(...)
local args = {...}
local func = nil
for i=#args,1,-2 do
local name = args[i-1];
local direction = args[i]
func = GetCompareFunc(name, func, direction)
end
return func
end
local sortFunctions = {
ComposeSortFunction("isOwned", DESCENDING, "level", USER, "name", ASCENDING),
ComposeSortFunction("isOwned", DESCENDING, "name", USER, "level", DESCENDING),
ComposeSortFunction("isOwned", DESCENDING, "petType", USER, "level", DESCENDING, "name", ASCENDING),
ComposeSortFunction("isOwned", DESCENDING, "rarity", USER, "level", DESCENDING, "name", ASCENDING),
ComposeSortFunction("isOwned", DESCENDING, "maxStat", USER, "level", DESCENDING, "name", ASCENDING),
ComposeSortFunction("isOwned", DESCENDING, "breed", USER, "level", DESCENDING, "name", ASCENDING),
}
local sortFunctionsFavoritesFirst = {}
for i=1,#sortFunctions do
sortFunctionsFavoritesFirst[i] = GetCompareFunc("favorite", sortFunctions[i], DESCENDING)
end
function GetSortFunctions()
if Sorting.sorting.favoritesFirst then
return sortFunctionsFavoritesFirst
else
return sortFunctions
end
end
end
function Sorting:OnInitialize()
-- self.ZoneFiltering = PetJournalEnhanced:GetModule("ZoneFiltering")
self.callbacks = LibStub("CallbackHandler-1.0"):New(self)
local defaults = {
global = {
filtering = {
rarity = {
[1] = true,
[2] = true,
[3] = true,
[4] = true
},
breed = {
[3] = true,
[4] = true,
[5] = true,
[6] = true,
[7] = true,
[8] = true,
[9] = true,
[10] = true,
[11] = true,
[12] = true,
},
specialization = {
[1] = true,
[2] = true,
[3] = true,
[4] = true
},
level = {
[1] = true,
[2] = true,
[3] = true,
[4] = true,
[5] = true
},
quantity = { [1] = true, [2] = true, [3] = true },
currentZone = false,
canBattle = true,
cantBattle = true,
unknownZone = true,
cantTrade = true,
canTrade = true,
abilityType = {
[1] = true,
[2] = true,
[3] = true,
[3] = true,
[4] = true,
[5] = true,
[6] = true,
[7] = true,
[8] = true,
[9] = true,
[10] = true
},
hiddenSpecies = false,
favroritesOnly = false,
},
sorting = {
selection = 1,
order = ASCENDING,
favoritesFirst = false,
},
hiddenSpecies = {},
}
}
local db = LibStub("AceDB-3.0"):New("PetJournalEnhancedDB", {}, true)
local name = self:GetName()
self.db = db:RegisterNamespace(name, defaults)
self.db.global.filtering.unknownZone = true --always reset to true
self.filtering = self.db.global.filtering
self.sorting = self.db.global.sorting
self:RegisterEvent("ZONE_CHANGED_NEW_AREA")
self:RegisterEvent("PET_JOURNAL_PET_DELETED")
local LibPetJournal = LibStub("LibPetJournal-2.0")
LibPetJournal.RegisterCallback(self, "PostPetListUpdated", "ScanPets")
PetJournalSearchBox:HookScript("OnTextChanged", function() Sorting:SortPets() end)
hooksecurefunc(C_PetJournal,"SetFavorite", function() Sorting:UpdatePets() end)
end
function Sorting:IsSpeciesHidden(speciesID)
--print(speciesID)
if self.db.global.hiddenSpecies[speciesID] then
return true
end
end
function Sorting:SetSpeciesHidden(speciesID, hidden)
self.db.global.hiddenSpecies[speciesID] = hidden
end
function Sorting:ResetSpeciesHidden()
self.db.global.hiddenSpecies = {}
end
function Sorting:GetPetByIndex(index)
return petMapping[index]
end
function Sorting:GetNumPets()
return #petMapping
end
function Sorting:Reset()
C_PetJournal.SetFilterChecked(LE_PET_JOURNAL_FILTER_COLLECTED, true)
C_PetJournal.SetFilterChecked(LE_PET_JOURNAL_FILTER_NOT_COLLECTED, true)
C_PetJournal.SetAllPetTypesChecked(true)
C_PetJournal.SetAllPetSourcesChecked(true)
self.ZoneFiltering:SetAllFiltered(true)
local filtering = self.db.global.filtering
local sorting = self.db.global.sorting
for i=1,#filtering.rarity do
filtering.rarity[i] = true
end
for i=1,#filtering.abilityType do
filtering.abilityType[i] = true
end
for i=1,#filtering.level do
filtering.level[i] = true
end
for i=1,#filtering.specialization do
filtering.specialization[i] = true
end
for i=1,#filtering.quantity do
filtering.quantity[i] = true
end
for i=1,#filtering.breed do
filtering.breed[i] = true
end
filtering.currentZone = false
filtering.canBattle = true
filtering.cantBattle = true
filtering.unknownZone = true
filtering.canTrade = true
filtering.cantTrade = true
filtering.favoritesOnly = false
sorting.selection = 2
sorting.order = ASCENDING
sorting.favoritesFirst = false
self:SortPets()
end
function Sorting:ScanPets()
self:SortPets()
end
function Sorting:ZONE_CHANGED_NEW_AREA()
if self.filtering.currentZone then
self:SortPets()
end
end
function Sorting:PETJOURNAL_ENHANCED_OPTIONS_UPDATE()
self:SortPets()
end
function Sorting:PET_JOURNAL_PET_DELETED()
self:SortPets()
end
do
--Return highest stat for a pet. Check constants for return values.
local function GetMaxStat(maxHealth, attack, speed)
maxHealth = tonumber(maxHealth)
local stamina = tonumber(math.floor((maxHealth -100)/5))
attack = tonumber(attack)
speed = tonumber(speed)
if attack > speed and attack > stamina then
return MAX_ATTACK
elseif speed > attack and speed > stamina then
return MAX_SPEED
elseif stamina > attack and stamina > speed then
return MAX_STAMINA
end
return MAX_BALANCED
end
local function CreatePet(petID, speciesID, isOwned, name, petType, canBattle, tradable, rarity, level, sourceText, maxHealth, attack, speed)
local pet = {}
pet.speciesID = speciesID
pet.petID = petID
pet.isOwned = isOwned
pet.name = name
pet.petType = petType
pet.canBattle = canBattle
pet.tradable = tradable
pet.rarity = rarity or 0
pet.maxStat = 0
pet.abilityFilter = 0
pet.breed = 0
pet.breedConfidence = 0
pet.level = level or 0
pet.sourceText = sourceText
if isOwned and canBattle and maxHealth and attack and speed then
pet.maxStat = GetMaxStat(maxHealth, attack, speed)
local breed, breedConfidence = BreedInfo:GetBreedByPetID(petID)
if breed then
pet.breed, pet.breedConfidence = breed, breedConfidence
end
end
if canBattle then
local abilityIDs = C_PetJournal.GetPetAbilityList(pet.speciesID);
for j=1, #abilityIDs do
local _, _, abilityType = C_PetJournal.GetPetAbilityInfo(abilityIDs[j]);
pet.abilityFilter = bit.bor(pet.abilityFilter, 2^abilityType);
end
else
pet.level = 0
pet.rarity = 0
pet.petType = 0
end
return pet
end
local function UpdatePet(petID, pet, level, favorite, index, rarity)
pet.owned = C_PetJournal.GetNumCollectedInfo(pet.speciesID)
pet.favorite = favorite
pet.index = index
pet.petID = petID
if pet.canBattle and pet.isOwned then
if pet.breedConfidence < BREED_HIGH_CONFIDENCE and level > pet.level then
local breed, breedConfidence = BreedInfo:GetBreedByPetID(petID)
if breed then
pet.breed, pet.breedConfidence = breed, breedConfidence
end
end
pet.level = level
pet.rarity = rarity
end
end
function Sorting:SortPets()
--local start = debugprofilestop()
local numPets = C_PetJournal.GetNumPets(PetJournal.isWild)
local ZoneFiltering = self.ZoneFiltering
wipe(petMapping)
local activeFilters = self:GetActiveFilters()
for i=1,numPets do
local petID, speciesID, isOwned, _, level, favorite, _, name, _, petType, _, sourceText, _, _, canBattle, tradable, _ = C_PetJournal.GetPetInfoByIndex(i, PetJournal.isWild)
local maxHealth, attack, speed, rarity
if petID then
_, maxHealth, attack, speed, rarity = C_PetJournal.GetPetStats(petID)
end
local id = nil
if isOwned then id = petID else id = speciesID end
local pet = self:GetPet(id)
if not pet then
pet = CreatePet(petID, speciesID, isOwned, name, petType, canBattle, tradable, rarity, level, sourceText, maxHealth, attack, speed)
SetPet(pet)
end
UpdatePet(petID, pet, level, favorite, i, rarity)
--filter pet
local exclude = false
for i=1, #activeFilters do
exclude = activeFilters[i]:exclude(pet)
if exclude then break end
end
if not exclude then
table.insert(petMapping,pet)
end
end
local sortFuncs = GetSortFunctions()
local sortFunc = sortFuncs[self.sorting.selection]
table.sort(petMapping, sortFunc)
self.callbacks:Fire("PETS_SORTED")
--local stop = debugprofilestop() - start
--print(stop)
end
Sorting.UpdatePets = Sorting.SortPets
end
do
local function BitwiseAndTable(tbl)
local truth = true;
for k,v in pairs(tbl) do
truth = truth and v
end
return truth
end
local function InitializeFilters()
local filtering = Sorting.filtering
local sorting = Sorting.sorting
local ZoneFiltering = Sorting.ZoneFiltering
Sorting.filters = {
--[[
{
initialize = function(self) end,
enabled = function(self) return false end,
exclude = function(self,pet) return false end
},
]]
{
name = "can battle",
enabled = function() return not filtering.canBattle end,
exclude = function(self, pet) return pet.canBattle end
},
{
name = "favorites only",
enabled = function() return filtering.favoritesOnly end,
exclude = function(self, pet)
if pet.isOwned and not pet.favorite then
return true
end
return false
end
},
{
name = "cant battle",
enabled = function() return not filtering.cantBattle end,
exclude = function(self, pet) return not pet.canBattle end
},
{
name = "can trade",
enabled = function() return not filtering.canTrade end,
exclude = function(self, pet) return pet.tradable end
},
{
name = "cant trade",
enabled = function() return not filtering.cantTrade end,
exclude = function(self, pet) return not pet.tradable end
},
{
name = "rarity",
enabled = function() return not BitwiseAndTable(filtering.rarity) end,
exclude = function(self, pet) return pet.rarity and pet.rarity > 0 and not filtering.rarity[pet.rarity] end
},
{
name = "quantity",
enabled = function() return not BitwiseAndTable(filtering.quantity) end,
exclude = function(self, pet) return pet.owned > 0 and not filtering.quantity[pet.owned] end
},
{
name = "pet spec",
enabled = function() return not BitwiseAndTable(filtering.specialization) end,
exclude = function(self, pet) return pet.maxStat > 0 and not filtering.specialization[pet.maxStat] end
},
-- {
-- name = "current zone",
-- initialize = function(self) self.currentZoneId = C_Map.GetBestMapForUnit("player") end,
-- enabled = function() return filtering.currentZone end,
-- exclude = function(self, pet)
-- local zones = ZoneFiltering:GetZonesBySpeciesID(pet.speciesID)
-- return (zones == nil or not zones[self.currentZoneId])
-- end
-- },
-- {
-- name = "unknown zone",
-- enabled = function() return not filtering.unknownZone end,
-- exclude = function(self, pet) return ZoneFiltering:GetZonesBySpeciesID(pet.speciesID) == nil end
-- },
{
name = "breed",
enabled = function() return not BitwiseAndTable(filtering.breed) end,
exclude = function(self, pet) return pet.breed > 0 and not filtering.breed[pet.breed] end
},
--[[
{
name = "level",
enabled = function() return not BitwiseAndTable(filtering.level) end,
exclude = function(self,pet)
return pet.level and
(not filtering.level[1] and pet.level == 1) or
(not filtering.level[2] and pet.level <= 10 and pet.level >= 2) or
(not filtering.level[3] and pet.level <= 20 and pet.level >= 11) or
(not filtering.level[4] and pet.level <= 24 and pet.level >= 20) or
(not filtering.level[5] and pet.level == 25)
end
},
]]
{
name = "ability",
abilityFilter = 0,
initialize = function(self)
self.abilityFilter = 0
for i=1,#filtering.abilityType do
if filtering.abilityType[i] then
self.abilityFilter = bit.bor(self.abilityFilter, 2^i);
end
end
end,
enabled = function()
return not BitwiseAndTable(filtering.abilityType)
end,
exclude = function(self, pet)
return pet.canBattle and bit.band(self.abilityFilter, pet.abilityFilter) == 0
end,
},
-- {
-- name = "zone selection",
-- enabled = function() return not ZoneFiltering:IsEveryZoneEnabled() end,
-- exclude = function(self, pet)
-- local zones = ZoneFiltering:GetZonesBySpeciesID(pet.speciesID)
-- if zones then
-- local filtered = false
-- for k,v in pairs(zones) do
-- filtered = filtered or ZoneFiltering:GetFiltered(k)
-- end
-- return not filtered
-- end
-- return false
-- end
-- },
{
name = "hidden species",
enabled = function() return not filtering.hiddenSpecies end,
exclude = function(self, pet)
return Sorting:IsSpeciesHidden(pet.speciesID)
end
},
}
local levelRanges = {{1,1}, {2,10}, {11,20}, {21,24}, {25,25}}
for i=1,#levelRanges do
local filter = {
name = "level "..levelRanges[i][1].."-"..levelRanges[i][2],
enabled = function() return not filtering.level[i] end,
exclude = function(self, pet)
return pet.level and pet.level >= levelRanges[i][1] and pet.level <= levelRanges[i][2]
end
}
table.insert(Sorting.filters, filter)
end
end
function Sorting:GetActiveFilters()
if not self.filters then InitializeFilters() end
local activeFilters = {}
for i=1, #self.filters do
if self.filters[i].initialize then
self.filters[i]:initialize()
end
if self.filters[i].enabled() then
--print(self.filters[i].name or "Error: no filter name")
table.insert(activeFilters, self.filters[i])
end
end
return activeFilters
end
end