local REVISION = 3;
if (type(ExScanner) == "table") and (ExScanner.vers and ExScanner.vers >= REVISION) then
return;
end
-- Examiner Scanner Table
ExScanner = ExScanner or {};
ExScanner.vers = REVISION;
ExScanner.ItemLinkPattern = "^.+|H(item:[^|]+)|h%[.+$";
ExScanner.ItemUseToken = "^"..ITEM_SPELL_TRIGGER_ONUSE.." ";
ExScanner.SetNamePattern = "^(.+) %((%d)/(%d)%)$";
ExScanner.SetBonusTokenActive = "^"..ITEM_SET_BONUS:gsub("%%s","");
ExScanner.MagicSchools = { "FIRE", "NATURE", "ARCANE", "FROST", "SHADOW", "HOLY" };
ExScanner.Slots = {
"HeadSlot", "NeckSlot", "ShoulderSlot", "BackSlot", "ChestSlot", "ShirtSlot", "TabardSlot", "WristSlot",
"HandsSlot", "WaistSlot", "LegsSlot", "FeetSlot", "Finger0Slot", "Finger1Slot", "Trinket0Slot", "Trinket1Slot",
"MainHandSlot", "SecondaryHandSlot", "RangedSlot",
};
ExScanner.SlotIDs = {};
for _, slotName in ipairs(ExScanner.Slots) do
ExScanner.SlotIDs[slotName] = GetInventorySlotInfo(slotName);
end
ExScanner.StatRatingBaseTable = {
SPELLHASTE = 10,
SPELLHIT = 8,
SPELLCRIT = 14,
HASTE = 10,
HIT = 10,
CRIT = 14,
EXPERTISE = 2.5,
DEFENSE = 1.5,
DODGE = 13.8, -- Patch 3.2: Increased 15% from 12
PARRY = 13.8, -- Patch 3.2: Reduced 8% from 15
BLOCK = 5,
RESILIENCE = 28.75, -- Patch 3.2: Increased 15% from 25
ARMORPENETRATION = 4.69512176513672 / 1.25 * 1.12, -- Patch 3.1 Quote: "All classes now receive 25% more benefit from Armor Penetration Rating."
-- Patch 3.2.2 Quote: "The amount of armor penetration gained per point of this rating has been reduced by 12%."
};
-- FAN EDIT: PvP Item Sets + their stats
ExScanner.PvPItemSets = {
SPELLPOWER = {},
AP = {}
};
ExScanner.PvPItemSets["SPELLPOWER"]["Gladiator's Refuge"] = true; -- Druid Resto
ExScanner.PvPItemSets["SPELLPOWER"]["Gladiator's Wildhide"] = true; -- Druid Balance
ExScanner.PvPItemSets["SPELLPOWER"]["Gladiator's Regalia"] = true; -- Mage
ExScanner.PvPItemSets["SPELLPOWER"]["Gladiator's Redemption"] = true; -- Paladin Holy
ExScanner.PvPItemSets["SPELLPOWER"]["Gladiator's Investiture"] = true; -- Priest Heal
ExScanner.PvPItemSets["SPELLPOWER"]["Gladiator's Raiment"] = true; -- Priest Shadow
ExScanner.PvPItemSets["SPELLPOWER"]["Gladiator's Thunderfist"] = true; -- Shaman Ele
ExScanner.PvPItemSets["SPELLPOWER"]["Gladiator's Wartide"] = true; -- Shaman Resto
ExScanner.PvPItemSets["SPELLPOWER"]["Gladiator's Felshroud"] = true; -- Warlock
ExScanner.PvPItemSets["AP"]["Gladiator's Desecration"] = true; -- Death Knight
ExScanner.PvPItemSets["AP"]["Gladiator's Sanctuary"] = true; -- Druid Feral
ExScanner.PvPItemSets["AP"]["Gladiator's Pursuit"] = true; -- Hunter
ExScanner.PvPItemSets["AP"]["Gladiator's Vindication"] = true; -- Paladin Retri
ExScanner.PvPItemSets["AP"]["Gladiator's Vestments"] = true; -- Rogue
ExScanner.PvPItemSets["AP"]["Gladiator's Earthshaker"] = true; -- Shaman Enh
ExScanner.PvPItemSets["AP"]["Gladiator's Battlegear"] = true; -- Warrior
-- end FAN EDIT;
-- ItemSlotValues Tables
-- Legendary items uses the same values as epics.
-- Heirloom items uses the same values as rares, although this is not entirely correct, and is messed up anyway, since their itemlevel is one.
-- White and Grey items uses a factor of one, which is totally wrong, but I have no idea what a real number for those qualities would be.
ExScanner.RarityFactor = { [0] = 1, [1] = 1, [2] = 2, [3] = 1.8, [4] = 1.2, [5] = 1.2, [6] = 1, [7] = 1.8 };
ExScanner.RaritySubtract = { [0] = 0, [1] = 0, [2] = 8, [3] = 0.75, [4] = 26, [5] = 26, [6] = 0, [7] = 0.75 };
ExScanner.Tip = ExScanner.Tip or CreateFrame("GameTooltip","ExScannerTip",nil,"GameTooltipTemplate");
ExScanner.Tip:SetOwner(UIParent,"ANCHOR_NONE");
-- Used in ScanUnitItems
local scannedSetNames = {};
--------------------------------------------------------------------------------------------------------
-- Scan all items and set bonuses on given 'unit' (Make sure the tables are reset) --
--------------------------------------------------------------------------------------------------------
function ExScanner:ScanUnitItems(unit,statTable,setTable)
if (not unit) or (not UnitExists(unit)) then
return;
end
-- Check all item slots
for _, slotName in ipairs(self.Slots) do
-- Set New Item Tip
self.Tip:ClearLines();
self.Tip:SetInventoryItem(unit,GetInventorySlotInfo(slotName));
local lastSetName;
local lastBonusCount = 1;
-- Check Lines
for i = 2, self.Tip:NumLines() do
if (self:DoLineNeedScan(_G["ExScannerTipTextLeft"..i],true)) then
-- We use "setMax" to check if the Line was a SetNamePattern (WTB continue statement in Lua)
local setName, setCount, setMax;
-- Set Header (Only run this if we haven't found a set on this item yet)
if (not lastSetName) then
setName, setCount, setMax = self.text:match(self.SetNamePattern);
if (setMax) and (not setTable[setName]) then
setTable[setName] = { count = tonumber(setCount), max = tonumber(setMax) };
-- FAN EDIT: count PvP set stat bonuses
if ((ExScanner.PvPItemSets["AP"][setName]) and (tonumber(setCount) >= 2)) then
statTable["RESILIENCE"] = statTable["RESILIENCE"] + 100;
statTable["AP"] = statTable["AP"] + 50;
if (tonumber(setCount) >= 4) then
statTable["AP"] = statTable["AP"] + 150;
end
end
if ((ExScanner.PvPItemSets["SPELLPOWER"][setName]) and (tonumber(setCount) >= 2)) then
statTable["RESILIENCE"] = statTable["RESILIENCE"] + 100;
statTable["HEAL"] = statTable["HEAL"] + 29;
statTable["SPELLDMG"] = statTable["SPELLDMG"] + 29;
if (tonumber(setCount) >= 4) then
statTable["HEAL"] = statTable["HEAL"] + 88;
statTable["SPELLDMG"] = statTable["SPELLDMG"] + 88;
end
end
-- end FAN EDIT;
-- Mark this set as scanned, if any found
scannedSetNames[setName] = true;
lastSetName = setName;
--continue :(
end
end
-- Check Line for Patterns if this Line was not a SetNamePattern
if (not setMax) then
if (self.text:find(self.SetBonusTokenActive)) then
-- Skip set bonues we have already included
if (lastSetName) and (not scannedSetNames[lastSetName]) then
self:ScanLineForPatterns(self.text,statTable);
setTable[lastSetName]["setBonus"..lastBonusCount] = self.text;
lastBonusCount = (lastBonusCount + 1);
end
else
self:ScanLineForPatterns(self.text,statTable);
end
end
end
end
end
-- Cleanup
wipe(scannedSetNames);
end
--------------------------------------------------------------------------------------------------------
-- Scans a single item given by 'itemLink', stats are added to the 'statTable' variable --
--------------------------------------------------------------------------------------------------------
function ExScanner:ScanItemLink(itemLink,statTable)
if (itemLink) then
-- Set Link
self.Tip:ClearLines();
self.Tip:SetHyperlink(itemLink);
-- Check Lines
for i = 2, self.Tip:NumLines() do
if (self:DoLineNeedScan(_G["ExScannerTipTextLeft"..i],false)) then
self:ScanLineForPatterns(self.text,statTable);
end
end
end
end
--------------------------------------------------------------------------------------------------------
-- Checks if a Line Needs to be Scanned for Patterns --
--------------------------------------------------------------------------------------------------------
function ExScanner:DoLineNeedScan(tipLine,scanSetBonuses)
-- Init Line
local text = tipLine:GetText();
local color = text:match("^(|c%x%x%x%x%x%x%x%x)");
text = text:gsub("|c%x%x%x%x%x%x%x%x","");
self.text = text;
local r, g, b = tipLine:GetTextColor();
r, g, b = ceil(r * 255), ceil(g * 255), ceil(b * 255);
-- Always *Skip* Gray Lines
if (r == 128 and g == 128 and b == 128) or (color == "|cff808080") then
return;
-- Active Set Bonuses (Must be checked before green color check)
elseif (not scanSetBonuses and text:find(self.SetBonusTokenActive)) then
return;
-- Skip "Use:" lines, they are not a permanent stat, so don't include them
elseif (text:find(self.ItemUseToken)) then
return;
-- Always *Scan* Green Lines
elseif (r == 0 and g == 255 and b == 0) or (color == "|cff00ff00") then
return 1;
-- Should Match: Normal +Stat, Base Item Armor, Block Value on Shields
elseif (text:find("^[+-]?%d+ [^%d]")) then
return 1;
-- Set Names (Needed to Check Sets)
elseif (scanSetBonuses and text:find(self.SetNamePattern)) then
return 1;
end
return;
end
--------------------------------------------------------------------------------------------------------
-- Checks a Single Line for Patterns --
--------------------------------------------------------------------------------------------------------
function ExScanner:ScanLineForPatterns(text,statTable)
for _, pattern in ipairs(self.Patterns) do
local pos, _, value1, value2 = text:find(pattern.p);
if (pos) and (value1 or pattern.v) then
if (type(pattern.s) == "string") then
statTable[pattern.s] = (statTable[pattern.s] or 0) + (value1 or pattern.v);
elseif (type(pattern.s) == "table") then
for statIndex, statName in ipairs(pattern.s) do
if (type(pattern.v) == "table") then
statTable[statName] = (statTable[statName] or 0) + (pattern.v[statIndex]);
-- Az: This is a bit messy, only supports 2 now, needs to make it dynamic and support as many extra values as possible
elseif (statIndex == 2) and (value2) then
statTable[statName] = (statTable[statName] or 0) + (value2);
else
statTable[statName] = (statTable[statName] or 0) + (value1 or pattern.v);
end
end
end
end
end
end
--------------------------------------------------------------------------------------------------------
-- Convert Rating to Percent http://www.wowwiki.com/Combat_Rating_System --
--------------------------------------------------------------------------------------------------------
function ExScanner:GetRatingInPercent(stat,rating,level,class)
local base = self.StatRatingBaseTable[stat];
-- Check Valid Input
if (not base or not rating or not level) then
return;
end
-- Patch 3.1 Quote: "shamans, paladins, druids, and death knights now receive 30% more melee haste from Haste Rating."
if (class and stat == "HASTE") and (class == "PALADIN" or class == "SHAMAN" or class == "DEATHKNIGHT" or class == "DRUID") then
base = (base / 1.3);
end
-- Calc Depending on Level
if (level >= 70) then
return rating / base / (82 / 52 * (131 / 63) ^ ((level - 70) / 10));
elseif (level >= 60) then
return rating / base / (82 / (262 - 3 * level));
else
return rating / base / ((level > 10 and level - 8 or 2) / 52);
end
end
--------------------------------------------------------------------------------------------------------
-- Slot Value Calculation --
--------------------------------------------------------------------------------------------------------
function ExScanner:CalculateItemSlotValue(itemLink)
local _, _, itemRarity, itemLevel = GetItemInfo(itemLink);
return (itemLevel - self.RaritySubtract[itemRarity]) / self.RarityFactor[itemRarity];
end