-- Upvalues
local R = Rarity
-- Lua API
local table = table
-- WOW API
local C_Calendar = C_Calendar
local GetContainerNumSlots = _G.C_Container . GetContainerNumSlots
local GetContainerItemID = _G.C_Container . GetContainerItemID
local GetContainerItemInfo = _G.C_Container . GetContainerItemInfo
local GetNumSavedInstances = GetNumSavedInstances
local GetSavedInstanceInfo = GetSavedInstanceInfo
local GetNumRandomDungeons = GetNumRandomDungeons
local GetLFGRandomDungeonInfo = GetLFGRandomDungeonInfo
local GetLFGDungeonInfo = GetLFGDungeonInfo
local GetLFGDungeonRewards = GetLFGDungeonRewards
local GetStatistic = GetStatistic
local UnitName = UnitName
local UnitGUID = UnitGUID
local InCombatLockdown = InCombatLockdown
local GetAchievementNumCriteria = GetAchievementNumCriteria
-- Constants
local NUM_BAG_SLOTS = _G.NUM_BAG_SLOTS
local BOSS_DEAD = _G.BOSS_DEAD
-- Why is this so inconsistently named? Does it have a special meaning?
local rarity_stats = { }
-------------------------------------------------------------------------------------
-- Scan your bags to see if you are in possession of any of the items we want. This is used for BOSS and FISHING methods,
-- and also works as a second line of defense in case other methods fail to notice the item.
-------------------------------------------------------------------------------------
function R : ScanBags ( )
table.wipe ( Rarity.bagitems )
for i = 0 , NUM_BAG_SLOTS do
local numSlots = GetContainerNumSlots ( i )
if numSlots then
for ii = 1 , numSlots do
local id = GetContainerItemID ( i , ii )
if id then
local containerItemInfo = GetContainerItemInfo ( i , ii )
local qty = containerItemInfo.stackCount
if qty and qty > 0 then
if not Rarity.bagitems [ id ] then
Rarity.bagitems [ id ] = 0
end
Rarity.bagitems [ id ] = Rarity.bagitems [ id ] + qty
end
end
end
end
end
end
function R : ScanCalendar ( reason )
self : Debug ( " Scanning calendar ( " .. reason .. " ) " )
table.wipe ( Rarity.activeHolidayEvents )
local today = C_DateAndTime.GetCurrentCalendarTime ( )
local month , day , year = today.month , today.monthDay , today.year
local monthInfo = C_Calendar.GetMonthInfo ( ) -- This is the CALENDAR date (as selected)
local curMonth , curYear = monthInfo.month , monthInfo.year
local monthOffset = - 12 * ( curYear - year ) + month - curMonth
local numEvents = C_Calendar.GetNumDayEvents ( monthOffset , day )
local numLoaded = 0
for i = 1 , numEvents , 1 do
local calendarEvent = C_Calendar.GetDayEvent ( monthOffset , day , i )
assert ( calendarEvent.eventID , " Calendar event IDs should now be available in all WOW product lines " )
if calendarEvent.calendarType == " HOLIDAY " then
Rarity.activeHolidayEvents [ calendarEvent.eventID ] = calendarEvent
end
end
end
function R : ScanInstanceLocks ( reason )
self : Debug ( " Scanning instance locks ( " .. reason .. " ) " )
local scanTip = Rarity.GUI . scanTip
table.wipe ( Rarity.lockouts )
local savedInstances = GetNumSavedInstances ( )
for i = 1 , savedInstances do
local instanceName , instanceID , instanceReset , instanceDifficulty , locked , extended , instanceIDMostSig =
GetSavedInstanceInfo ( i )
-- Legacy code (deprecated)
if instanceReset > 0 then
scanTip : ClearLines ( )
scanTip : SetInstanceLockEncountersComplete ( i )
for line = 2 , scanTip : NumLines ( ) do
local txtRight = _G [ " __Rarity_ScanTipTextRight " .. line ] : GetText ( )
if txtRight then
if txtRight == BOSS_DEAD then
self.lockouts [ _G [ " __Rarity_ScanTipTextLeft " .. line ] : GetText ( ) ] = true
end
end
end
end
-- Detailed lockouts saving (stub - I'm leaving the legacy code above untouched, even if it's partly identical)
if instanceReset > 0 then -- Lockout isn't expired -> Scan it and store the defeated encounter names
scanTip : ClearLines ( )
scanTip : SetInstanceLockEncountersComplete ( i )
for line = 2 , scanTip : NumLines ( ) do
local txtRight = _G [ " __Rarity_ScanTipTextRight " .. line ] : GetText ( )
if txtRight then
if txtRight == BOSS_DEAD then
local encounterName = _G [ " __Rarity_ScanTipTextLeft " .. line ] : GetText ( )
self.lockouts [ encounterName ] = true
-- Create containers if this is the first lockout for a given instance
self.lockouts_detailed [ encounterName ] = self.lockouts_detailed [ encounterName ] or { }
self.lockouts_detailed [ encounterName ] [ instanceDifficulty ] = self.lockouts_detailed [ encounterName ] [ instanceDifficulty ]
or { }
-- Add this lockout to the container
self.lockouts_detailed [ encounterName ] [ instanceDifficulty ] = true
end
end
end
end
end
table.wipe ( Rarity.lockouts_holiday )
local num = GetNumRandomDungeons ( )
for i = 1 , num do
local dungeonID , name = GetLFGRandomDungeonInfo ( i )
local _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , desc , isHoliday = GetLFGDungeonInfo ( dungeonID )
if isHoliday and dungeonID ~= 828 then -- 828 = ??
local doneToday = GetLFGDungeonRewards ( dungeonID )
self.lockouts_holiday [ dungeonID ] = doneToday
end
end
-- This code lists every LFG dungeon ID in the game (up through 1000)
-- for instanceID = 0, 1000 do
-- local dungeonName, typeId, subtypeId, minLvl, maxLvl, recLvl, minRecLvl, maxRecLvl, expansionId, groupId, textureName, difficulty, maxPlayers, dungeonDesc, isHoliday = GetLFGDungeonInfo(instanceID)
-- if dungeonName then
-- self:Print("instanceID = " .. instanceID .. " Name = " .. dungeonName .. " typeID = " .. tostring(typeId) .. " minLvl = " .. minLvl .. " maxLvl = " .. maxLvl .. " recLvl = " .. recLvl .. " groupId = " .. tostring(groupId) .." maxPlayers = " .. tostring(maxPlayers))
-- end
-- end
end
-- TODO: Does this really belong here? I don't think so...
function R : BuildStatistics ( reason )
self.Profiling : StartTimer ( " Collections.BuildStatistics. " .. reason or " UnknownReason " )
self : Debug ( " Building statistics table ( " .. reason .. " ) " )
local tbl = { }
Rarity.lastStatCount = 0
for k , v in pairs ( R.stats_to_scan ) do
local s = GetStatistic ( k )
tbl [ k ] = ( tonumber ( s or " 0 " ) or 0 )
if not Rarity.db . profile.accountWideStatistics then
Rarity.db . profile.accountWideStatistics = { }
end
local charName = UnitName ( " player " )
local charGuid = UnitGUID ( " player " )
if charName and charGuid then
if not Rarity.db . profile.accountWideStatistics [ charGuid ] then
Rarity.db . profile.accountWideStatistics [ charGuid ] = { }
end
Rarity.db . profile.accountWideStatistics [ charGuid ] . playerName = charName
Rarity.db . profile.accountWideStatistics [ charGuid ] . server = GetRealmName ( ) or " "
if not Rarity.db . profile.accountWideStatistics [ charGuid ] . statistics then
Rarity.db . profile.accountWideStatistics [ charGuid ] . statistics = { }
end
Rarity.db . profile.accountWideStatistics [ charGuid ] . statistics [ k ] = ( tonumber ( s or " 0 " ) or 0 )
end
Rarity.lastStatCount = Rarity.lastStatCount + 1
end
self.Profiling : EndTimer ( " Collections.BuildStatistics " .. reason or " UnknownReason " )
return tbl
end
function R : ScanStatistics ( reason )
if InCombatLockdown ( ) then
return
end -- Don't do this during combat as it has a tendency to run too long
self.Profiling : StartTimer ( " Collections.ScanStatistics. " .. reason or " UnknownReason " )
if rarity_stats == nil or ( Rarity.lastStatCount or 0 ) <= 0 then
self : Debug ( " Building initial statistics table " )
rarity_stats = self : BuildStatistics ( reason )
end
local newStats = self : BuildStatistics ( reason )
for kk , vv in pairs ( Rarity.items_with_stats ) do
if type ( vv ) == " table " then
if
( vv.requiresHorde and R.Caching : IsHorde ( ) )
or ( vv.requiresAlliance and not R.Caching : IsHorde ( ) )
or ( not vv.requiresHorde and not vv.requiresAlliance )
then
if vv.statisticId and type ( vv.statisticId ) == " table " then
local count = 0
local totalCrossAccount = 0
for kkk , vvv in pairs ( vv.statisticId ) do
local newAmount = newStats [ vvv ] or 0
local oldAmount = rarity_stats [ vvv ] or 0
count = count + newAmount
-- Count up the total for this statistic across the entire account
if Rarity.db . profile.accountWideStatistics then
for playerGuid , playerData in pairs ( Rarity.db . profile.accountWideStatistics ) do
if playerData.statistics then
totalCrossAccount = totalCrossAccount
+ ( Rarity.db . profile.accountWideStatistics [ playerGuid ] . statistics [ vvv ] or 0 )
end
end
end
-- One of the statistics has gone up; add one attempt for this item
if newAmount > oldAmount then
R : Debug ( " Statistics indicate a new attempt for " .. vv.name )
vv.attempts = ( vv.attempts or 0 ) + 1
self : OutputAttempts ( vv , true )
end
end
-- We've never seen any attempts for this yet; update to this player's statistic total
if count > 0 and ( vv.attempts or 0 ) <= 0 then
-- We seem to have gathered more attempts on this character than accounted for yet; update to new total
vv.attempts = count
self : OutputAttempts ( vv , true )
elseif count > 0 and count > ( vv.attempts or 0 ) and vv.doNotUpdateToHighestStat ~= true then -- Some items don't want us doing this (generally when Blizzard has a statistic overcounting bug)
R : Debug (
" Statistics for " .. vv.name .. " are higher than current amount. Updating to " .. count
)
vv.attempts = count
self : OutputAttempts ( vv , true )
end
-- Cross-account statistic total is higher than the one we have; update to new total
if totalCrossAccount > ( vv.attempts or 0 ) and vv.doNotUpdateToHighestStat ~= true then
R : Debug (
" Account-wide statistics for "
.. vv.name
.. " are higher than current amount. Updating to "
.. totalCrossAccount
)
vv.attempts = totalCrossAccount
self : OutputAttempts ( vv , true )
end
end
end
end
end
-- Done with scan; update our saved table to the current scan
rarity_stats = newStats
if self.db . profile.debugMode then
R.stats = rarity_stats
end
self.Profiling : EndTimer ( " Collections.ScanStatistics " .. reason or " UnknownReason " )
end