Untitled diff

Created Diff never expires
--[[
--[[
ToDo:
ToDo:
- Move more Group Functionality to here
- Move more Group Functionality to here
* Autoscan
* Autoscan
* SIL_Group:GroupType();
* SIL_Group:GroupType();
- On UpdateGroup if there is no data do a rough scan
- On UpdateGroup if there is no data do a rough scan
- Group methods within this file
- Group methods within this file
- Better way to hooking tooltips
- Better way to hooking tooltips
-
-
]]
]]


local L = LibStub("AceLocale-3.0"):GetLocale("SimpleILevel", true);
local L = LibStub("AceLocale-3.0"):GetLocale("SimpleILevel", true);


-- Start SIL
-- Start SIL
SIL = LibStub("AceAddon-3.0"):NewAddon(L.core.name, "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0");
SIL = LibStub("AceAddon-3.0"):NewAddon(L.core.name, "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0");
SIL.category = GetAddOnMetadata("SimpleILevel", "X-Category");
SIL.category = GetAddOnMetadata("SimpleILevel", "X-Category");
SIL.version = GetAddOnMetadata("SimpleILevel", "Version");
SIL.version = GetAddOnMetadata("SimpleILevel", "Version");
SIL.versionMajor = 3; -- Used for cache DB versioning
SIL.versionMajor = 3; -- Used for cache DB versioning
SIL.versionRev = 'r251'; -- Used for version information
SIL.versionRev = 'r251'; -- Used for version information
SIL.action = {}; -- DB of unitGUID->function to run when a update comes through
SIL.action = {}; -- DB of unitGUID->function to run when a update comes through
SIL.hooks = {}; -- List of hooks in [type][] = function;
SIL.hooks = {}; -- List of hooks in [type][] = function;
SIL.autoscan = 0; -- time() value of last autoscan, must be more then 1sec
SIL.autoscan = 0; -- time() value of last autoscan, must be more then 1sec
SIL.lastScan = {}; -- target = time();
SIL.lastScan = {}; -- target = time();
SIL.grayScore = 7; -- Number of items to consider gray/aprox
SIL.grayScore = 7; -- Number of items to consider gray/aprox
SIL.ldbAuto = false; -- AceTimer for LDB
SIL.ldbAuto = false; -- AceTimer for LDB
SIL.menu = false; -- Menu frame
SIL.menu = false; -- Menu frame
SIL.menuItems = { -- Table for the dropdown menu
SIL.menuItems = { -- Table for the dropdown menu
top = {},
top = {},
middle = {},
middle = {},
bottom = {},
bottom = {},
};
};
SIL.modules = {}; -- Modules
SIL.modules = {}; -- Modules
SIL.group = {}; -- Group Members by guid
SIL.group = {}; -- Group Members by guid
--SIL.L = L; -- Non-local locals
--SIL.L = L; -- Non-local locals


-- Load Libs
-- Load Libs
SIL.aceConfig = LibStub:GetLibrary("AceConfig-3.0");
SIL.aceConfig = LibStub:GetLibrary("AceConfig-3.0");
SIL.aceConfigDialog = LibStub:GetLibrary("AceConfigDialog-3.0");
SIL.aceConfigDialog = LibStub:GetLibrary("AceConfigDialog-3.0");
SIL.inspect = LibStub:GetLibrary("LibInspect");
SIL.inspect = LibStub:GetLibrary("LibInspect");
SIL.ldb = LibStub:GetLibrary("LibDataBroker-1.1");
SIL.ldb = LibStub:GetLibrary("LibDataBroker-1.1");
SIL.ldbIcon = LibStub:GetLibrary("LibDBIcon-1.0");
SIL.ldbIcon = LibStub:GetLibrary("LibDBIcon-1.0");
SIL.callback = LibStub("CallbackHandler-1.0"):New(SIL);
SIL.callback = LibStub("CallbackHandler-1.0"):New(SIL);
SIL.itemUpgrade = LibStub("LibItemUpgradeInfo-1.0");
SIL.itemUpgrade = LibStub("LibItemUpgradeInfo-1.0");


-- OnLoad
-- OnLoad
function SIL:OnInitialize()
function SIL:OnInitialize()


-- Make sure everything is ok with the db
-- Make sure everything is ok with the db
if not SIL_CacheGUID or type(SIL_CacheGUID) ~= 'table' then SIL_CacheGUID = {}; end
if not SIL_CacheGUID or type(SIL_CacheGUID) ~= 'table' then SIL_CacheGUID = {}; end
-- Tell the player we are being loaded
-- Tell the player we are being loaded
self:Print(format(L.core.load, self.version));
self:Print(format(L.core.load, self.version));
self:ModulesProcess();
self:ModulesProcess();
-- Load settings
-- Load settings
self.db = LibStub("AceDB-3.0"):New("SIL_Settings", SIL_Defaults, true);
self.db = LibStub("AceDB-3.0"):New("SIL_Settings", SIL_Defaults, true);
self:UpdateSettings();
self:UpdateSettings();
-- Set Up LDB
-- Set Up LDB
local ldbObj = {
local ldbObj = {
type = "data source",
type = "data source",
icon = "Interface\\Icons\\inv_misc_armorkit_24",
icon = "Interface\\Icons\\inv_misc_armorkit_24",
label = L.core.name,
label = L.core.name,
text = 'n/a',
text = 'n/a',
category = self.category,
category = self.category,
version = self.version,
version = self.version,
OnClick = function(...) SIL:MenuOpen(...); end,
OnClick = function(...) SIL:MenuOpen(...); end,
OnTooltipShow = function(tt)
OnTooltipShow = function(tt)
if SIL:GetLDB() and SIL.ldb.text then
if SIL:GetLDB() and SIL.ldb.text then
tt:AddLine(SIL.ldb.text);
tt:AddLine(SIL.ldb.text);
end
end
tt:AddLine(L.core.minimapClick);
tt:AddLine(L.core.minimapClick);
tt:AddLine(L.core.minimapClickDrag);
tt:AddLine(L.core.minimapClickDrag);
end,
end,
};
};
-- Set back to a launcher if text is off
-- Set back to a launcher if text is off
if not self:GetLDB() then
if not self:GetLDB() then
ldbObj.type = 'launcher';
ldbObj.type = 'launcher';
ldbObj.text = nil;
ldbObj.text = nil;
end
end
-- Start LDB
-- Start LDB
self.ldb = self.ldb:NewDataObject(L.core.name, ldbObj);
self.ldb = self.ldb:NewDataObject(L.core.name, ldbObj);
self.ldbUpdated = 0;
self.ldbUpdated = 0;
self.ldbLable = '';
self.ldbLable = '';
-- Start the minimap icon
-- Start the minimap icon
self.ldbIcon:Register(L.core.name, self.ldb, self.db.global.minimap);
self.ldbIcon:Register(L.core.name, self.ldb, self.db.global.minimap);
-- Register Options
-- Register Options
SIL_Options.args.purge.desc = format(L.core.options.purgeDesc, self:GetPurge() / 24);
SIL_Options.args.purge.desc = format(L.core.options.purgeDesc, self:GetPurge() / 24);
self.aceConfig:RegisterOptionsTable(L.core.name, SIL_Options, {"sil", "silev", "simpleilevel"});
self.aceConfig:RegisterOptionsTable(L.core.name, SIL_Options, {"sil", "silev", "simpleilevel"});
self.aceConfigDialog:AddToBlizOptions(L.core.name);
self.aceConfigDialog:AddToBlizOptions(L.core.name);
-- Add Hooks
-- Add Hooks
self.inspect:AddHook(L.core.name, 'items', function(...) SIL:ProcessInspect(...); end);
self.inspect:AddHook(L.core.name, 'items', function(...) SIL:ProcessInspect(...); end);
GameTooltip:HookScript("OnTooltipSetUnit", function(...) SIL:TooltipHook(...); end);
GameTooltip:HookScript("OnTooltipSetUnit", function(...) SIL:TooltipHook(...); end);
self:Autoscan(self:GetAutoscan());
self:Autoscan(self:GetAutoscan());
-- Events
-- Events
self:RegisterEvent("PLAYER_TARGET_CHANGED", function() if CanInspect('target') then SIL:GetScoreTarget('target'); end end);
self:RegisterEvent("PLAYER_TARGET_CHANGED", function() if CanInspect('target') then SIL:GetScoreTarget('target'); end end);
self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED", function() SIL:StartScore('player'); end);
self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED", function() SIL:StartScore('player'); end);
self:RegisterEvent("PLAYER_ENTERING_WORLD", function() SIL:UpdateLDB(); end);
self:RegisterEvent("PLAYER_ENTERING_WORLD", function() SIL:UpdateLDB(); end);
self:RegisterEvent("GROUP_ROSTER_UPDATE", function() SIL:UpdateGroup() end);
self:RegisterEvent("GROUP_ROSTER_UPDATE", function() SIL:UpdateGroup() end);
self:RegisterEvent("UPDATE_MOUSEOVER_UNIT", function()
self:RegisterEvent("UPDATE_MOUSEOVER_UNIT", function()
if SIL:GetMouseOver() and CanInspect('mouseover') then
if SIL:GetMouseOver() and CanInspect('mouseover') then
SIL:Debug('mouseover', UnitName('mouseover'));
SIL:Debug('mouseover', UnitName('mouseover'));
SIL:GetScoreTarget('mouseover');
SIL:GetScoreTarget('mouseover');
end
end
SIL:ShowTooltip();
SIL:ShowTooltip();
end);
end);
-- Add to Paperdoll
-- Add to Paperdoll
if self:GetPaperdoll() then
if self:GetPaperdoll() then
self:RegisterPaperdoll();
self:RegisterPaperdoll();
end
end
-- GuildMemberInfo
-- GuildMemberInfo
if GMI then
if GMI then
GMI:Register("SimpleILevel", {
GMI:Register("SimpleILevel", {
lines = {
lines = {
SimpleILevel = {
SimpleILevel = {
label = L.core.name,
label = L.core.name,
default = 'n/a',
default = 'n/a',
callback = function(name) return SIL:GMICallback(name); end,
callback = function(name) return SIL:GMICallback(name); end,
},
},
},
},
});
});
end
end
-- Clear the cache
-- Clear the cache
self:AutoPurge(true);
self:AutoPurge(true);
-- Build the menu
-- Build the menu
self:MenuInitialize();
self:MenuInitialize();
-- Get working on a score for the player
-- Get working on a score for the player
self:StartScore('player');
self:StartScore('player');
self:LDBSetAuto();
self:LDBSetAuto();
self:UpdateLDB(); -- This may cause excesive loading time...
self:UpdateLDB(); -- This may cause excesive loading time...
-- Process modules
-- Process modules
self:ModulesLoad();
self:ModulesLoad();
-- Localization Notice
-- Localization Notice
if GetLocale() == 'itIT' or GetLocale() == 'esMX' or GetLocale() == 'esES' then
if GetLocale() == 'itIT' or GetLocale() == 'esMX' or GetLocale() == 'esES' then
self:Print("Help Localize Simple iLevel! http://j.mp/localSIL")
self:Print("Help Localize Simple iLevel! http://j.mp/localSIL")
end
end
end
end


-- Make sure the database is the latest version
-- Make sure the database is the latest version
function SIL:UpdateSettings()
function SIL:UpdateSettings()
if self.db.global.version == self.versionMajor then
if self.db.global.version == self.versionMajor then
-- Same version
-- Same version
elseif self.db.global.version > 2.4 and self.db.global.version < 2.5 then
elseif self.db.global.version > 2.4 and self.db.global.version < 2.5 then
for guid,info in pairs(SIL_CacheGUID) do
for guid,info in pairs(SIL_CacheGUID) do
SIL_CacheGUID[guid].guid = nil;
SIL_CacheGUID[guid].guid = nil;
end
end
elseif self.db.global.version < 2.4 then
elseif self.db.global.version < 2.4 then
for guid,info in pairs(SIL_CacheGUID) do
for guid,info in pairs(SIL_CacheGUID) do
SIL_CacheGUID[guid].total = nil;
SIL_CacheGUID[guid].total = nil;
SIL_CacheGUID[guid].tooltip = nil;
SIL_CacheGUID[guid].tooltip = nil;
SIL_CacheGUID[guid].level = 85; --ASSuME
SIL_CacheGUID[guid].level = 85; --ASSuME
--SIL_CacheGUID[guid].guid = guid;
--SIL_CacheGUID[guid].guid = guid;
end
end
end
end
-- Update version information
-- Update version information
self.db.global.version = self.versionMajor;
self.db.global.version = self.versionMajor;
end
end


function SIL:AutoPurge(silent)
function SIL:AutoPurge(silent)
if self:GetPurge() > 0 then
if self:GetPurge() > 0 then
local count = self:PurgeCache(self:GetPurge());
local count = self:PurgeCache(self:GetPurge());
if not silent then
if not silent then
self:Print(format(L.core.purgeNotification, count));
self:Print(format(L.core.purgeNotification, count));
end
end
return count;
return count;
else
else
if not silent then
if not silent then
self:Print(L.core.purgeNotificationFalse);
self:Print(L.core.purgeNotificationFalse);
end
end
return false;
return false;
end
end
end
end


function SIL:PurgeCache(hours)
function SIL:PurgeCache(hours)
if tonumber(hours) then
if tonumber(hours) then
local maxAge = time() - (tonumber(hours) * 3600);
local maxAge = time() - (tonumber(hours) * 3600);
local count = 0;
local count = 0;
for guid,info in pairs(SIL_CacheGUID) do
for guid,info in pairs(SIL_CacheGUID) do
if type(info.time) == "number" and info.time < maxAge then
if type(info.time) == "number" and info.time < maxAge then
SIL_CacheGUID[guid] = nil;
SIL_CacheGUID[guid] = nil;
count = 1 + count;
count = 1 + count;
self:RunHooks('purge', guid);
self:RunHooks('purge', guid);
end
end
end
end
return count;
return count;
else
else
return false;
return false;
end
end
end
end


function SIL:AddHook(hookType, callback)
function SIL:AddHook(hookType, callback)
local hookType = strlower(hookType);
local hookType = strlower(hookType);
if not self.hooks[hookType] then
if not self.hooks[hookType] then
self.hooks[hookType] = {};
self.hooks[hookType] = {};
end
end
table.insert(self.hooks[hookType], callback);
table.insert(self.hooks[hookType], callback);
end
end


function SIL:RunHooks(hookType, ...)
function SIL:RunHooks(hookType, ...)
local r = {};
local r = {};
if self.hooks[hookType] then
if self.hooks[hookType] then
for i,callback in pairs(self.hooks[hookType]) do
for i,callback in pairs(self.hooks[hookType]) do
local ret = callback(...);
local ret = callback(...);
if ret then
if ret then
table.insert(r, callback(...));
table.insert(r, callback(...));
end
end
end
end
if #r > 0 then
if #r > 0 then
return r;
return r;
else
else
return true;
return true;
end
end
else
else
return false;
return false;
end
end
end
end


--[[
--[[
Event Handlers
Event Handlers
]]
]]
function SIL:UNIT_INVENTORY_CHANGED(e, unitID)
function SIL:UNIT_INVENTORY_CHANGED(e, unitID)
--print('UNIT_INVENTORY_CHANGED');
--print('UNIT_INVENTORY_CHANGED');
if InCombatLockdown() then return end
if InCombatLockdown() then return end
if unitID and CanInspect(unitID) and not UnitIsUnit('player', unitID) and self.autoscan ~= time() then
if unitID and CanInspect(unitID) and not UnitIsUnit('player', unitID) and self.autoscan ~= time() then
self.autoscan = time();
self.autoscan = time();
self:StartScore(unitID);
self:StartScore(unitID);
end
end
end
end


-- Used to hook the tooltip to avoid the full tooltip function
-- Used to hook the tooltip to avoid the full tooltip function
function SIL:TooltipHook()
function SIL:TooltipHook()
local name, unit = GameTooltip:GetUnit();
local name, unit = GameTooltip:GetUnit();
local guid = false;
local guid = false;
if unit then
if unit then
guid = UnitGUID(unit);
guid = UnitGUID(unit);
elseif name then
elseif name then
guid = self:NameToGUID(name);
guid = self:NameToGUID(name);
end
end
if self:IsGUID(guid, 'Player') then
if self:IsGUID(guid, 'Player') then
self:ShowTooltip(guid);
self:ShowTooltip(guid);
end
end
end
end


function SIL:Autoscan(toggle)
function SIL:Autoscan(toggle)
if toggle then
if toggle then
self:RegisterEvent("UNIT_INVENTORY_CHANGED");
self:RegisterEvent("UNIT_INVENTORY_CHANGED");
else
else
self:UnregisterEvent("UNIT_INVENTORY_CHANGED");
self:UnregisterEvent("UNIT_INVENTORY_CHANGED");
end
end
self.db.global.autoscan = toggle;
self.db.global.autoscan = toggle;
end
end


--[[
--[[


Slash Handlers
Slash Handlers
]]
]]
-- Reset the settings
-- Reset the settings
function SIL:SlashReset()
function SIL:SlashReset()
self:Print(L.core.slashClear);
self:Print(L.core.slashClear);
self.db:RegisterDefaults(SIL_Defaults);
self.db:RegisterDefaults(SIL_Defaults);
self.db:ResetDB('Default');
self.db:ResetDB('Default');
self:SetMinimap(true);
self:SetMinimap(true);
-- Clear the cache
-- Clear the cache
SIL_CacheGUID = {};
SIL_CacheGUID = {};
self:GetScoreTarget('player', true);
self:GetScoreTarget('player', true);
-- Update version information
-- Update version information
self.db.global.version = self.versionMajor;
self.db.global.version = self.versionMajor;
self:RunHooks('clear');
self:RunHooks('clear');
end
end


function SIL:SlashGet(name)
function SIL:SlashGet(name)
-- Get score by name
-- Get score by name
if name and not (name == '' or name == 'target') then
if name and not (name == '' or name == 'target') then
local score, age, items = self:GetScoreName(name);
local score, age, items = self:GetScoreName(name);
if score then
if score then
local name = self:Cache(self:NameToGUID(name), 'name')
local name = self:Cache(self:NameToGUID(name), 'name')
self:Print(format(L.core.slashGetScore, name, self:FormatScore(score, items), self:AgeToText(age)));
self:Print(format(L.core.slashGetScore, name, self:FormatScore(score, items), self:AgeToText(age)));
-- Nothing :(
-- Nothing :(
else
else
self:Print(format(L.core.slashGetScoreFalse, name));
self:Print(format(L.core.slashGetScoreFalse, name));
end
end
-- no name but we can inspect the current target
-- no name but we can inspect the current target
elseif CanInspect('target') then
elseif CanInspect('target') then
self:SlashTarget();
self:SlashTarget();
-- why do you ask so much of me but make no sence
-- why do you ask so much of me but make no sence
else
else
self:Print(L.core.slashTargetScoreFalse);
self:Print(L.core.slashTargetScoreFalse);
end
end
end
end


function SIL:SlashTarget()
function SIL:SlashTarget()
self:StartScore('target', function(...) SIL:SlashTargetPrint(...); end);
self:StartScore('target', function(...) SIL:SlashTargetPrint(...); end);
end
end


function SIL:SlashTargetPrint(guid, score, items, age)
function SIL:SlashTargetPrint(guid, score, items, age)
if guid and score then
if guid and score then
local name = self:GUIDtoName(guid);
local name = self:GUIDtoName(guid);
if name then
if name then
self:Print(format(L.core.slashTargetScore, name, self:FormatScore(score, items)));
self:Print(format(L.core.slashTargetScore, name, self:FormatScore(score, items)));
else
else
self:Debug("No name for guid", guid, "score", score, items, age);
self:Debug("No name for guid", guid, "score", score, items, age);
end
end
else
else
self:Print(L.core.slashTargetScoreFalse);
self:Print(L.core.slashTargetScoreFalse);
end
end
end
end


--[[
--[[


Basic Functions
Basic Functions


]]
]]
function SIL:GUIDtoName(guid)
function SIL:GUIDtoName(guid)
if guid and self:IsGUID(guid, 'Player') and self:Cache(guid) then
if guid and self:IsGUID(guid, 'Player') and self:Cache(guid) then
return self:Cache(guid, 'name'), self:Cache(guid, 'realm');
return self:Cache(guid, 'name'), self:Cache(guid, 'realm');
else
else
return false;
return false;
end
end
end
end


function SIL:NameToGUID(name, realm)
function SIL:NameToGUID(name, realm)
if not name then return false end
if not name then return false end
-- Try and get the realm from the name-realm
-- Try and get the realm from the name-realm
if not realm then
if not realm then
name, realm = strsplit('-', name, 2);
name, realm = strsplit('-', name, 2);
end
end
-- If no realm then set it to current realm
-- If no realm then set it to current realm
if not realm or realm == '' then
if not realm or realm == '' then
realm = GetRealmName();
realm = GetRealmName();
end
end
if name then
if name then
name = strlower(name);
name = strlower(name);
local likely = false;
local likely = false;
for guid,info in pairs(SIL_CacheGUID) do
for guid,info in pairs(SIL_CacheGUID) do
if strlower(info.name) == name and info.realm == realm then
if strlower(info.name) == name and info.realm == realm then
return guid;
return guid;
elseif strlower(info.name) == name then
elseif strlower(info.name) == name then
likely = guid;
likely = guid;
end
end
end
end
if likely then
if likely then
return likely;
return likely;
end
end
end
end
return false;
return false;
end
end


-- Get a GUID from just about anything
-- Get a GUID from just about anything
function SIL:GetGUID(target)
function SIL:GetGUID(target)
if target then
if target then
if tonumber(target) then
if tonumber(target) then
return target;
return target;
elseif UnitGUID(target) then
elseif UnitGUID(target) then
return UnitGUID(target);
return UnitGUID(target);
else
else
return SIL:NameToGUID(target);
return SIL:NameToGUID(target);
end
end
else
else
return false;
return false;
end
end
end
end


-- Clear score
-- Clear score
function SIL:ClearScore(target)
function SIL:ClearScore(target)
local guid = self:GetGUID(target);
local guid = self:GetGUID(target);
if SIL_CacheGUID[guid] then
if SIL_CacheGUID[guid] then
SIL_CacheGUID[guid].score = false;
SIL_CacheGUID[guid].score = false;
SIL_CacheGUID[guid].items = false;
SIL_CacheGUID[guid].items = false;
SIL_CacheGUID[guid].time = false;
SIL_CacheGUID[guid].time = false;
self:RunHooks('purge', guid);
self:RunHooks('purge', guid);
return true;
return true;
else
else
return false;
return false;
end
end
end;
end;


function SIL:AgeToText(age, color)
function SIL:AgeToText(age, color)
if type(color) == 'nil' then color = true; end
if type(color) == 'nil' then color = true; end
local hex = "00ff00";
local hex = "00ff00";
if type(age) == 'number' then
if type(age) == 'number' then
if age > 86400 then
if age > 86400 then
age = self:Round(age / 86400, 2);
age = self:Round(age / 86400, 2);
str = L.core.ageDays;
str = L.core.ageDays;
hex = "ff0000";
hex = "ff0000";
elseif age > 3600 then
elseif age > 3600 then
age = self:Round(age / 3600, 1);
age = self:Round(age / 3600, 1);
str = L.core.ageHours;
str = L.core.ageHours;
hex = "33ccff";
hex = "33ccff";
elseif age > 60 then
elseif age > 60 then
age = self:Round(age / 60, 1);
age = self:Round(age / 60, 1);
str = L.core.ageMinutes;
str = L.core.ageMinutes;
hex = "00ff00";
hex = "00ff00";
else
else
age = age;
age = age;
str = L.core.ageSeconds;
str = L.core.ageSeconds;
hex = "00ff00";
hex = "00ff00";
end
end
if color and self:GetColorScore() then
if color and self:GetColorScore() then
return format(str, '|cFF'..hex..age..'|r');
return format(str, '|cFF'..hex..age..'|r');
else
else
return format(str, age);
return format(str, age);
end
end
else
else
return 'n/a';
return 'n/a';
end
end
end
end


-- print a message to channel or whisper player/channel
-- print a message to channel or whisper player/channel
function SIL:PrintTo(message, channel, to)
function SIL:PrintTo(message, channel, to)
if channel == "print" or channel == "SYSTEM" then
if channel == "print" or channel == "SYSTEM" then
self:Print(message);
self:Print(message);
elseif channel == "WHISPER" then
elseif channel == "WHISPER" then
SendChatMessage(message, 'WHISPER', nil, to);
SendChatMessage(message, 'WHISPER', nil, to);
elseif channel == "CHANNEL" then
elseif channel == "CHANNEL" then
SendChatMessage(message, 'CHANNEL', nil, to);
SendChatMessage(message, 'CHANNEL', nil, to);
elseif channel then
elseif channel then
SendChatMessage(message, channel);
SendChatMessage(message, channel);
else
else
self:Print(message);
self:Print(message);
end
end
end
end


function SIL:Debug(...)
function SIL:Debug(...)
if SIL.db.char.debug then
if SIL.db.char.debug then
print('|cFFFF0000SIL Debug:|r ', ...);
print('|cFFFF0000SIL Debug:|r ', ...);
end
end
end
end


--[[
--[[


Core Functionality
Core Functionality
]]
]]
-- Get someones score
-- Get someones score
function SIL:GetScore(guid, attemptUpdate, target, callback)
function SIL:GetScore(guid, attemptUpdate, target, callback)
if not self:IsGUID(guid, 'Player') then return false; end
if not self:IsGUID(guid, 'Player') then return false; end
if self:Cache(guid) and self:Cache(guid, 'score') then
if self:Cache(guid) and self:Cache(guid, 'score') then
local score = self:Cache(guid, 'score');
local score = self:Cache(guid, 'score');
local age = self:Cache(guid, 'age') or time();
local age = self:Cache(guid, 'age') or time();
local items = self:Cache(guid, 'items');
local items = self:Cache(guid, 'items');
local startScore = nil;
local startScore = nil;
-- If a target was passed and we are over age
-- If a target was passed and we are over age
if target and (attemptUpdate or self:GetAge() < age) and self.autoscan ~= time() then
if target and (attemptUpdate or self:GetAge() < age) and self.autoscan ~= time() then
startScore = self:StartScore(target, callback);
startScore = self:StartScore(target, callback);
end
end
return score, age, items, startScore;
return score, age, items, startScore;
else
else
-- If a target was passed
-- If a target was passed
if target then
if target then
self:StartScore(target);
self:StartScore(target);
end
end
return false;
return false;
end
end
end
end


-- Wrapers for get score, more specialized code may come
-- Wrapers for get score, more specialized code may come
function SIL:GetScoreName(name, realm)
function SIL:GetScoreName(name, realm)
local guid = self:NameToGUID(name, realm);
local guid = self:NameToGUID(name, realm);
return self:GetScore(guid);
return self:GetScore(guid);
end
end


function SIL:GetScoreTarget(target, force, callback)
function SIL:GetScoreTarget(target, force, callback)
local guid = UnitGUID(target);
local guid = UnitGUID(target);
return self:GetScore(guid, force, target, callback);
return self:GetScore(guid, force, target, callback);
end
end


function SIL:GetScoreGUID(guid)
function SIL:GetScoreGUID(guid)
return self:GetScore(guid);
return self:GetScore(guid);
end
end


-- Request items to update a score
-- Request items to update a score
function SIL:StartScore(target, callback)
function SIL:StartScore(target, callback)
if InCombatLockdown() or not CanInspect(target) then
if InCombatLockdown() or not CanInspect(target) then
if callback then callback(false, target); end
if callback then callback(false, target); end
return false;
return false;
end
end
self.autoscan = time();
self.autoscan = time();
local guid = self:AddPlayer(target);
local guid = self:AddPlayer(target);
if not self.lastScan[target] or self.lastScan[target] ~= time() then
if not self.lastScan[target] or self.lastScan[target] ~= time() then
if guid then
if guid then
self.action[guid] = callback;
self.action[guid] = callback;
self.lastScan[target] = time();
self.lastScan[target] = time();
local canInspect = self.inspect:RequestItems(target, true);
local canInspect = self.inspect:RequestItems(target, true);
if not canInspect and callback then
if not canInspect and callback then
callback(false, target);
callback(false, target);
else
else
return true;
return true;
end
end
end
end
end
end
if callback then callback(false, target); end
if callback then callback(false, target); end
return false;
return false;
end
end


function SIL:ProcessInspect(guid, data, age)
function SIL:ProcessInspect(guid, data, age)
if guid and self:Cache(guid) and type(data) == 'table' and type(data.items) == 'table' then
if guid and self:Cache(guid) and type(data) == 'table' and type(data.items) == 'table' then
local totalScore, totalItems = self:GearSum(data.items, self:Cache(guid, 'level'));
local totalScore, totalItems = self:GearSum(data.items, self:Cache(guid, 'level'));
if totalItems and 0 < totalItems then
if totalItems and 0 < totalItems then
-- Update the DB
-- Update the DB
local score = totalScore / totalItems;
local score = totalScore / totalItems;
self:SetScore(guid, score, totalItems, age)
self:SetScore(guid, score, totalItems, age)
-- Update LDB
-- Update LDB
if self:GetLDB() and guid == UnitGUID('player') then
if self:GetLDB() and guid == UnitGUID('player') then
self:UpdateLDB(true);
self:UpdateLDB(true);
else
else
self:UpdateLDB(false);
self:UpdateLDB(false);
end
end
-- Run Hooks
-- Run Hooks
self:RunHooks('inspect', guid, score, totalItems, age, data.items);
self:RunHooks('inspect', guid, score, totalItems, age, data.items);
-- Run any callbacks for this event
-- Run any callbacks for this event
if self.action[guid] then
if self.action[guid] then
self.action[guid](guid, score, totalItems, age, data.items, self:Cache(guid, 'target'));
self.action[guid](guid, score, totalItems, age, data.items, self:Cache(guid, 'target'));
self.action[guid] = false;
self.action[guid] = false;
end
end
-- Update the Tooltip
-- Update the Tooltip
self:ShowTooltip();
self:ShowTooltip();
return true;
return true;
end
end
end
end
end
end


function SIL:GearSum(items, level)
function SIL:GearSum(items, level)
if items and level and type(items) == 'table' then
if items and level and type(items) == 'table' then
local totalItems = 0;
local totalItems = 0;
local totalScore = 0;
local totalScore = 0;
local mainhandArtifactIlvlCache = 0;
local offhandAtifactIlvlCache=0;
for i,itemLink in pairs(items) do
for i,itemLink in pairs(items) do
if itemLink and not ( i == INVSLOT_BODY or i == INVSLOT_RANGED or i == INVSLOT_TABARD ) then
if itemLink and not ( i == INVSLOT_BODY or i == INVSLOT_RANGED or i == INVSLOT_TABARD ) then
-- local name, link, itemRarity , itemLevel = GetItemInfo(itemLink);
local name, link, itemRarity , _ = GetItemInfo(itemLink);
local itemLevel = self.itemUpgrade:GetUpgradedItemLevel(itemLink);
local itemLevel = self.itemUpgrade:GetUpgradedItemLevel(itemLink);


--- print(i, itemLevel, itemLink);
-- print(i, itemLevel, itemLink, itemRarity);
if itemLevel then
if itemLevel then
-- Fix for OH Artifact (always calculated as 750 ilvl)
-- Fix for heirlooms
if itemRarity == 6 then
if itemRarity == 7 then
--Cache MH Artifact ilvl if higher
itemLevel = self:Heirloom(level, itemLink);
if i == INVSLOT_MAINHAND then
end
mainhandArtifactIlvlCache = itemLevel;
end
--Cache OH Artifact ilvl if higher
if i == INVSLOT_OFFHAND then
offhandAtifactIlvlCache = itemLevel
end
end
totalItems = totalItems + 1;
totalItems = totalItems + 1;
totalScore = totalScore + itemLevel;
totalScore = totalScore + itemLevel;
end
end
end
end
end
end
-- Fix for MH Artifact
if mainhandArtifactIlvlCache > offhandAtifactIlvlCache and totalItems == 16 then
totalScore = totalScore - offhandAtifactIlvlCache + mainhandArtifactIlvlCache;
end
-- Fix for OH Artifact
if mainhandArtifactIlvlCache < offhandAtifactIlvlCache and totalItems == 16 then
totalScore = totalScore + offhandAtifactIlvlCache - mainhandArtifactIlvlCache;
end
--Fix for 2H Artifact
if totalItems == 15 then
totalScore = totalScore + mainhandArtifactIlvlCache;
totalItems = totalItems + 1;
end
return totalScore, totalItems;
return totalScore, totalItems;
else
else
return false;
return false;
end
end
end
end


-- Thanks to Ro of Hyjal-US http://us.battle.net/wow/en/forum/topic/7199032730#9
-- Thanks to Ro of Hyjal-US http://us.battle.net/wow/en/forum/topic/7199032730#9
function SIL:GetActualItemLevelOld(link)
function SIL:GetActualItemLevelOld(link)
-- Updated for 5.4.8
-- Updated for 5.4.8
local levelAdjust={ -- 11th item:id field and level adjustment
local levelAdjust={ -- 11th item:id field and level adjustment
["0"]=0,["1"]=8,["373"]=4,["374"]=8,["375"]=4,["376"]=4,
["0"]=0,["1"]=8,["373"]=4,["374"]=8,["375"]=4,["376"]=4,
["377"]=4,["379"]=4,["380"]=4,["445"]=0,["446"]=4,["447"]=8,
["377"]=4,["379"]=4,["380"]=4,["445"]=0,["446"]=4,["447"]=8,
["451"]=0,["452"]=8,["453"]=0,["454"]=4,["455"]=8,["456"]=0,
["451"]=0,["452"]=8,["453"]=0,["454"]=4,["455"]=8,["456"]=0,
["457"]=8,["458"]=0,["459"]=4,["460"]=8,["461"]=12,["462"]=16,
["457"]=8,["458"]=0,["459"]=4,["460"]=8,["461"]=12,["462"]=16,
["465"]=0,["466"]=4,["467"]=8,["469"]=4,["470"]=8,["471"]=12,
["465"]=0,["466"]=4,["467"]=8,["469"]=4,["470"]=8,["471"]=12,
["472"]=16,["491"]=0,["492"]=4,["493"]=8,["494"]=4,["495"]=8,
["472"]=16,["491"]=0,["492"]=4,["493"]=8,["494"]=4,["495"]=8,
["496"]=8,["497"]=12,["498"]=16,["504"]=12,["505"]=16,["506"]=20,
["496"]=8,["497"]=12,["498"]=16,["504"]=12,["505"]=16,["506"]=20,
["507"]=24,
["507"]=24,
}
}
local baseLevel = select(4,GetItemInfo(link))
local baseLevel = select(4,GetItemInfo(link))
local upgrade = link:match(":(%d+)\124h%[")
local upgrade = link:match(":(%d+)\124h%[")
if baseLevel and upgrade and levelAdjust[upgrade] then
if baseLevel and upgrade and levelAdjust[upgrade] then
local newLevel = baseLevel + levelAdjust[upgrade];
local newLevel = baseLevel + levelAdjust[upgrade];
return newLevel
return newLevel
else
else
return baseLevel
return baseLevel
end
end
end
end


-- /run for i=1,25 do t='raid'..i; if UnitExists(t) then print(i, UnitName(t), CanInspect(t), SIL:RoughScore(t)); end end
-- /run for i=1,25 do t='raid'..i; if UnitExists(t) then print(i, UnitName(t), CanInspect(t), SIL:RoughScore(t)); end end
function SIL:RoughScore(target)
function SIL:RoughScore(target)
if not target then return false; end
if not target then return false; end
if not CanInspect(target) then return false; end
if not CanInspect(target) then return false; end
-- Get stuff in order
-- Get stuff in order
local guid = self:AddPlayer(target)
local guid = self:AddPlayer(target)
self.inspect:AddCharacter(target);
self.inspect:AddCharacter(target);
NotifyInspect(target);
NotifyInspect(target);
-- Get items and sum
-- Get items and sum
local items = self.inspect:GetItems(target);
local items = self.inspect:GetItems(target);
local totalScore, totalItems = self:GearSum(items, UnitLevel(target));
local totalScore, totalItems = self:GearSum(items, UnitLevel(target));
if totalItems and totalItems > 0 then
if totalItems and totalItems > 0 then
local score = totalScore / totalItems;
local score = totalScore / totalItems;
-- self:Debug('SIL:RoughScore', UnitName(target), score, totalItems);
-- self:Debug('SIL:RoughScore', UnitName(target), score, totalItems);
-- Set a score even tho its crap
-- Set a score even tho its crap
if guid and self:Cache(guid) and (not self:Cache(guid, 'score') or self:Cache(guid, 'items') < totalItems) then
if guid and self:Cache(guid) and (not self:Cache(guid, 'score') or self:Cache(guid, 'items') < totalItems) then
self:SetScore(guid, score, 1, self:GetAge() + 1);
self:SetScore(guid, score, 1, self:GetAge() + 1);
end
end
return score, 1, self:GetAge() + 1;
return score, 1, self:GetAge() + 1;
else
else
return false;
return false;
end
end
end
end


-- Start or update the DB for a player
-- Start or update the DB for a player
function SIL:AddPlayer(target)
function SIL:AddPlayer(target)
local guid = UnitGUID(target);
local guid = UnitGUID(target);
if guid then
if guid then
local name, realm = UnitName(target);
local name, realm = UnitName(target);
local className, class = UnitClass(target);
local className, class = UnitClass(target);
local level = UnitLevel(target);
local level = UnitLevel(target);
if not realm then
if not realm then
realm = GetRealmName();
realm = GetRealmName();
end
end
if name and realm and class and level then
if name and realm and class and level then
-- Start a table for them
-- Start a table for them
if not SIL_CacheGUID[guid] then
if not SIL_CacheGUID[guid] then
SIL_CacheGUID[guid] = {};
SIL_CacheGUID[guid] = {};
end
end
SIL_CacheGUID[guid].name = name;
SIL_CacheGUID[guid].name = name;
SIL_CacheGUID[guid].realm = realm;
SIL_CacheGUID[guid].realm = realm;
SIL_CacheGUID[guid].class = class;
SIL_CacheGUID[guid].class = class;
SIL_CacheGUID[guid].level = level;
SIL_CacheGUID[guid].level = level;
SIL_CacheGUID[guid].target = target;
SIL_CacheGUID[guid].target = target;
if not SIL_CacheGUID[guid].score or SIL_CacheGUID[guid].score == 0 then
if not SIL_CacheGUID[guid].score or SIL_CacheGUID[guid].score == 0 then
SIL_CacheGUID[guid].score = false;
SIL_CacheGUID[guid].score = false;
SIL_CacheGUID[guid].items = false;
SIL_CacheGUID[guid].items = false;
SIL_CacheGUID[guid].time = false;
SIL_CacheGUID[guid].time = false;
end
end
return guid;
return guid;
else
else
return false;
return false;
end
end
else
else
return false;
return false;
end
end
end
end


function SIL:SetScore(guid, score, items, age)
function SIL:SetScore(guid, score, items, age)
local t = age;
local t = age;
if age and type(age) == 'number' and age < 86400 then
if age and type(age) == 'number' and age < 86400 then
t = time() - age;
t = time() - age;
end
end
SIL_CacheGUID[guid].score = score;
SIL_CacheGUID[guid].score = score;
SIL_CacheGUID[guid].items = items;
SIL_CacheGUID[guid].items = items;
SIL_CacheGUID[guid].time = t;
SIL_CacheGUID[guid].time = t;
self:Debug("SetScore", self:GUIDtoName(guid), self:FormatScore(score, items), items, age)
self:Debug("SetScore", self:GUIDtoName(guid), self:FormatScore(score, items), items, age)
end
end


-- Get a relative iLevel on Heirlooms
-- Get a relative iLevel on Heirlooms
function SIL:Heirloom(level, itemLink)
function SIL:Heirloom(level, itemLink)
--[[
--[[
Here is how I came to the level 81-85 bracket
Here is how I came to the level 81-85 bracket
200 = level of 80 instance gear
200 = level of 80 instance gear
333 = level of 85 instance gear
333 = level of 85 instance gear
333 - 200 = 133 iLevels / 5 levels = 26.6 iLevel per level
333 - 200 = 133 iLevels / 5 levels = 26.6 iLevel per level
so then that means for a level 83
so then that means for a level 83
83 - 80 = 3 * 26.6 = 79.8 + 200 = 279.8 iLevel
83 - 80 = 3 * 26.6 = 79.8 + 200 = 279.8 iLevel
]]
]]
-- Check for Wrath Heirlooms that max at 80
-- Check for Wrath Heirlooms that max at 80
if level > 80 then
if level > 80 then
local _, _, _, _, itemId = string.find(itemLink, "|?c?f?f?(%x*)|?H?([^:]*):?(%d+):?(%d*):?(%d*):?(%d*):?(%d*):?(%d*):?(%-?%d*):?(%-?%d*):?(%d*):?(%d*)|?h?%[?([^%[%]]*)%]?|?h?|?r?");
local _, _, _, _, itemId = string.find(itemLink, "|?c?f?f?(%x*)|?H?([^:]*):?(%d+):?(%d*):?(%d*):?(%d*):?(%d*):?(%d*):?(%-?%d*):?(%-?%d*):?(%d*):?(%d*)|?h?%[?([^%[%]]*)%]?|?h?|?r?");
itemId = tonumber(itemId);
itemId = tonumber(itemId);
-- Downgrade it to 80 if found
-- Downgrade it to 80 if found
for k,iid in pairs(SIL_Heirlooms[80]) do
for k,iid in pairs(SIL_Heirlooms[80]) do
if iid == itemId then
if iid == itemId then
level = 80;
level = 80;
end
end
end
end
-- There are currently no 1-90 Heirlooms
-- There are currently no 1-90 Heirlooms
if level > 85 then
if level > 85 then
level = 85
level = 85
end
end
end
end
if level > 80 then
if level > 80 then
return (( level - 80) * 26.6) + 200;
return (( level - 80) * 26.6) + 200;
elseif level > 70 then
elseif level > 70 then
return (( level - 70) * 10) + 100;
return (( level - 70) * 10) + 100;
elseif level > 60 then
elseif level > 60 then
return (( level - 60) * 4) + 60;
return (( level - 60) * 4) + 60;
else
else
return level;
return level;
end
end
end
end


-- Format the score for color and round it to xxx.x
-- Format the score for color and round it to xxx.x
function SIL:FormatScore(score, items, color)
function SIL:FormatScore(score, items, color)
if not items then items = self.grayScore + 1; end
if not items then items = self.grayScore + 1; end
if type(color) == 'nil' then color = true; end
if type(color) == 'nil' then color = true; end
if score < 0 then score = 0; end -- Ticket #29, thanks Torsin
if score < 0 then score = 0; end -- Ticket #29, thanks Torsin
if tonumber(score) and tonumber(items) then
if tonumber(score) and tonumber(items) then
local scoreR
local scoreR
if self:GetRoundScore() then
if self:GetRoundScore() then
scoreR = self:Round(tonumber(score), 0);
scoreR = self:Round(tonumber(score), 0);
else
else
scoreR = self:Round(tonumber(score), 1);
scoreR = self:Round(tonumber(score), 1);
end
end
if color then
if color then
local hexColor = self:ColorScore(score, items);
local hexColor = self:ColorScore(score, items);
return '|cFF'..hexColor..scoreR..'|r';
return '|cFF'..hexColor..scoreR..'|r';
else
else
return scoreR;
return scoreR;
end
end
else
else
return 'n/a';
return 'n/a';
end
end
end
end


-- Return the hex, r, g, b of a score
-- Return the hex, r, g, b of a score
function SIL:ColorScore(score, items)
function SIL:ColorScore(score, items)
-- There are some missing items so gray
-- There are some missing items so gray
if items and items <= self.grayScore then
if items and items <= self.grayScore then
return self:RGBtoHex(0.5,0.5,0.5), 0.5,0.5,0.5;
return self:RGBtoHex(0.5,0.5,0.5), 0.5,0.5,0.5;
end
end
if not self:GetColorScore() then
if not self:GetColorScore() then
return self:RGBtoHex(1,1,1), 1,1,1;
return self:RGBtoHex(1,1,1), 1,1,1;
end
end
-- Default to white
-- Default to white
local r,g,b = 1,1,1;
local r,g,b = 1,1,1;
local found = false;
local found = false;
for i,maxScore in pairs(SIL_ColorIndex) do
for i,maxScore in pairs(SIL_ColorIndex) do
if score < maxScore and not found then
if score < maxScore and not found then
local colors = SIL_Colors[maxScore];
local colors = SIL_Colors[maxScore];
local baseColors = SIL_Colors[colors.p];
local baseColors = SIL_Colors[colors.p];
local steps = maxScore - colors.p;
local steps = maxScore - colors.p;
local scoreDiff = score - colors.p;
local scoreDiff = score - colors.p;
local diffR = (baseColors.r - colors.r) / 255;
local diffR = (baseColors.r - colors.r) / 255;
local diffG = (baseColors.g - colors.g) / 255;
local diffG = (baseColors.g - colors.g) / 255;
local diffB = (baseColors.b - colors.b) / 255;
local diffB = (baseColors.b - colors.b) / 255;
local diffStepR = diffR / steps;
local diffStepR = diffR / steps;
local diffStepG = diffG / steps;
local diffStepG = diffG / steps;
local diffStepB = diffB / steps;
local diffStepB = diffB / steps;
local scoreDiffR = scoreDiff * diffStepR;
local scoreDiffR = scoreDiff * diffStepR;
local scoreDiffG = scoreDiff * diffStepG;
local scoreDiffG = scoreDiff * diffStepG;
local scoreDiffB = scoreDiff * diffStepB;
local scoreDiffB = scoreDiff * diffStepB;
r = (baseColors.r / 255) - scoreDiffR;
r = (baseColors.r / 255) - scoreDiffR;
g = (baseColors.g / 255) - scoreDiffG;
g = (baseColors.g / 255) - scoreDiffG;
b = (baseColors.b / 255) - scoreDiffB;
b = (baseColors.b / 255) - scoreDiffB;
found = true;
found = true;
end
end
end
end
-- Nothing was found so max
-- Nothing was found so max
if not found then
if not found then
r = SIL_Colors[1000].r;
r = SIL_Colors[1000].r;
g = SIL_Colors[1000].g;
g = SIL_Colors[1000].g;
b = SIL_Colors[1000].b;
b = SIL_Colors[1000].b;
end
end
local hex = self:RGBtoHex(r,g,b);
local hex = self:RGBtoHex(r,g,b);
return hex, r, g, b;
return hex, r, g, b;
end
end


function SIL:ShowTooltip(guid)
function SIL:ShowTooltip(guid)
if InCombatLockdown() and not self:GetTTCombat() then return end
if InCombatLockdown() and not self:GetTTC
if not guid then
guid = UnitGUID("mouseover");
end
local score, age, items = self:GetScoreGUID(guid);
if score then
-- Build the tooltip text
local textLeft = '|cFF216bff'..L.core.ttLeft..'|r ';
local textRight = self:FormatScore(score, items, true);
local textAdvanced = format(L.core.ttAdvanced, self:AgeToText(age, true));
self:AddTooltipText(textLeft, textRight, textAdvanced);
-- Run Hooks
self:RunHooks('tooltip', guid);
return true;
else
return false;
end
end

-- Add lines to the tooltip, testLeft must be the same
function SIL:AddTooltipText(textLeft, textRight, textAdvanced, textAdvancedRight)
-- Loop tooltip text to check if its alredy there
local ttLines = GameTooltip:NumLines();
local ttUpdated = f