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.
756 lines
28 KiB
756 lines
28 KiB
local unpack, select, type, pairs, tinsert, max, floor, abs
|
|
= unpack, select, type, pairs, table.insert, math.max, math.floor, math.abs
|
|
|
|
local UnitFactionGroup, DressUpTexturePath, CreateFrame, GetItemIcon, GetSpecializationInfoByID, GetClassInfoByID, GetInventorySlotInfo, UnitStat, BreakUpLargeNumbers, UnitName
|
|
= UnitFactionGroup, DressUpTexturePath, CreateFrame, GetItemIcon, GetSpecializationInfoByID, GetClassInfoByID, GetInventorySlotInfo, UnitStat, BreakUpLargeNumbers, UnitName
|
|
local BestInSlot, L, AceGUI = unpack(select(2, ...))
|
|
local Preview = BestInSlot:NewModule("Preview Window")
|
|
local iconsize = 37
|
|
Preview.raceids = {
|
|
Human = 1,
|
|
Dwarf = 3,
|
|
Gnome = 7,
|
|
NightElf = 4,
|
|
Draenei = 11,
|
|
Worgen = 22,
|
|
Orc = 2,
|
|
Undead = 5,
|
|
Tauren = 6,
|
|
Troll = 8,
|
|
BloodElf = 10,
|
|
Goblin = 9,
|
|
Pandaren = 25,
|
|
}
|
|
Preview.classes = {}
|
|
Preview.attributes = PAPERDOLL_STATCATEGORIES[1].stats
|
|
local temp = PAPERDOLL_STATCATEGORIES.ENHANCEMENTS.stats
|
|
Preview.enhancements = {}
|
|
for i=1,#temp do
|
|
Preview.enhancements[i] = temp[i]
|
|
end
|
|
tinsert(Preview.enhancements, "ATTACK_AP")
|
|
tinsert(Preview.enhancements, "SPELLPOWER")
|
|
temp = nil
|
|
local noBenefit = {text = "STAT_NO_BENEFIT_TOOLTIP"}
|
|
Preview.classinfo = {
|
|
__default = {
|
|
basestat = {
|
|
CRITCHANCE = 5,
|
|
SPIRIT = 781,
|
|
},
|
|
stats = {
|
|
STRENGTH = {
|
|
noBenefit,
|
|
{text = "DEFAULT_STAT1_TOOLTIP"},
|
|
{text = "STAT_TOOLTIP_BONUS_AP_SP"}
|
|
},
|
|
AGILITY = {
|
|
noBenefit,
|
|
{text = "DEFAULT_STAT2_TOOLTIP"}
|
|
},
|
|
INTELLECT = {
|
|
noBenefit,
|
|
{text = "DEFAULT_STAT4_TOOLTIP"}
|
|
},
|
|
STAMINA = {
|
|
{text = "DEFAULT_STAT3_TOOLTIP", func = function(str, value) return _G[str]:format(BreakUpLargeNumbers(value * 60)) end}
|
|
},
|
|
CRITCHANCE = {
|
|
{text = "CR_CRIT_TOOLTIP"},
|
|
{text = "CR_CRIT_PARRY_RATING_TOOLTIP"}
|
|
},
|
|
HASTE = {
|
|
{text = "STAT_HASTE_BASE_TOOLTIP", func = function(str, value1, value2) return _G.STAT_HASTE_TOOLTIP.._G[str]:format(BreakUpLargeNumbers(value1), value2) end},
|
|
},
|
|
MASTERY = {
|
|
{text = "", func = function() return L["Mastery tooltips are not supported due to technical limitations"] end},
|
|
},
|
|
SPIRIT = {
|
|
noBenefit,
|
|
{text = "MANA_REGEN_FROM_SPIRIT", func = function(str, value) return _G[str]:format(BreakUpLargeNumbers(floor((961.93469238281 + 0.41220703160998 * value)*5))) end},
|
|
},
|
|
BONUS_ARMOR = {
|
|
noBenefit,
|
|
{text = "STAT_ARMOR_BONUS_ARMOR_BLADED_ARMOR_TOOLTIP"}
|
|
},
|
|
MULTISTRIKE = {
|
|
{text = "CR_MULTISTRIKE_TOOLTIP"},
|
|
},
|
|
LIFESTEAL = {
|
|
{text = "CR_LIFESTEAL_TOOLTIP"},
|
|
},
|
|
VERSATILITY = {
|
|
{text = "CR_VERSATILITY_TOOLTIP"},
|
|
},
|
|
AVOIDANCE = {
|
|
{text = "CR_AVOIDANCE_TOOLTIP"},
|
|
},
|
|
SPELLPOWER = {
|
|
{text = "STAT_SPELLPOWER_TOOLTIP"}
|
|
},
|
|
ATTACK_AP = {
|
|
{text = "ITEM_MOD_MELEE_ATTACK_POWER_SHORT"}
|
|
}
|
|
}
|
|
},
|
|
MAGE = {
|
|
modifiers = {INTELLECT = "*1.05"},
|
|
stats = {INTELLECT = 2}
|
|
},
|
|
[62] = { -- Mage: Arcane
|
|
basestat = {MASTERY = 550},
|
|
modifiers = {MASTERY = "* 1.05"}
|
|
},
|
|
[63] = {-- Mage: Fire
|
|
basestat = {CRITCHANCE = 15},
|
|
modifiers = {CRITCHANCE = "* 1.15"}
|
|
},
|
|
[64] = {-- Mage: Frost
|
|
basestat = {MULTISTRIKE = 8},
|
|
modifiers = {MULTISTRIKE = "* 1.05"}
|
|
},
|
|
--PALADIN = {},
|
|
[65] = { -- Paladin: Holy
|
|
modifiers = {INTELLECT = "* 1.05", CRITCHANCE = "*1.05"},
|
|
stats = {INTELLECT = 2, SPIRIT = 2}
|
|
},
|
|
[66] = { -- Paladin: Protection
|
|
modifiers = {HASTE = "* 1.3", STAMINA = "* 1.15", HASTE = "* 1.3"},
|
|
stats = {STRENGTH = 3, BONUS_ARMOR = 2, CRITCHANCE = 2}
|
|
},
|
|
[70] = { -- Paladin: Retribution
|
|
modifiers = {STRENGTH = "* 1.05", MASTERY = "* 1.05"},
|
|
stats = {STRENGTH = 3}
|
|
},
|
|
WARRIOR = {
|
|
stats = {STRENGTH = 2}
|
|
},
|
|
[71] = { -- Warrior: Arms
|
|
modifiers = {STRENGTH = "* 1.05", MASTERY = "* 1.05"}
|
|
},
|
|
[72] = { -- Warrior: Fury
|
|
modifiers = {STRENGTH = "* 1.05", CRITCHANCE = "* 1.05"}
|
|
},
|
|
[73] = { -- Warrior: Protection
|
|
modifiers = {STAMINA = "* 1.05 * 1.15"},
|
|
stats = {BONUS_ARMOR = 2, CRITCHANCE = 2}
|
|
},
|
|
--DRUID = {},
|
|
[102] = { -- Druid: Balance
|
|
modifiers = {INTELLECT = "* 1.05", MASTERY = "* 1.05"},
|
|
stats = {INTELLECT = 2}
|
|
},
|
|
[103] = { -- Druid: Feral
|
|
modifiers = {CRITCHANCE = "* 1.05", AGILITY = "* 1.05"},
|
|
stats = {AGILITY = 2}
|
|
},
|
|
[104] = { -- Druid: Guardian
|
|
modifiers = {STAMINA = "* 1.05 * 1.2", MASTERY = "* 1.05", ARMOR = "* 3.5"},
|
|
stats = {AGILITY = 2, BONUS_ARMOR = 2}
|
|
},
|
|
[105] = { -- Druid: Restoration
|
|
modifiers = {INTELLECT = "* 1.05", HASTE = "* 1.05"},
|
|
stats = {INTELLECT = 2, SPIRIT = 2}
|
|
},
|
|
DEATHKNIGHT = {
|
|
stats = {STRENGTH = 2}
|
|
},
|
|
[250] = { -- Death Knight: Blood
|
|
modifiers = {STAMINA = "* 1.05", TOTALSTAMINA = "* 1.2", ARMOR = "*1.3", MULTISTRIKE = "* 1.05"},
|
|
stats = {BONUS_ARMOR = 2},
|
|
basestat = {MULTISTRIKE = 10, HASTE = 10}
|
|
},
|
|
[251] = { -- Death Knight: Frost
|
|
modifiers = {STRENGTH = "* 1.05", HASTE = "* 1.2"},
|
|
basestat = {HASTE = 10}
|
|
},
|
|
[252] = { -- Death Knight: Unholy
|
|
modifiers = {STRENGTH = "* 1.05", MULTISTRIKE = "* 1.05"},
|
|
basestat = {HASTE = 20}
|
|
},
|
|
HUNTER = {
|
|
modifiers = {AGILITY = "*1.05"},
|
|
stats = {AGILITY = 2}
|
|
},
|
|
[253] = { -- Hunter: Beast Mastery
|
|
modifiers = {MASTERY = "* 1.05"}
|
|
},
|
|
[254] = { -- Hunter: Marksmanship
|
|
modifiers = {CRITCHANCE = "* 1.05"}
|
|
},
|
|
[255] = { -- Hunter: Survival
|
|
modifiers = {MULTISTRIKE = "* 1.05", MULTISTRIKEEFFECT = "* 1.2"}
|
|
},
|
|
PRIEST = {
|
|
modifiers = {INTELLECT = "* 1.05"},
|
|
stats = {INTELLECT = 2}
|
|
},
|
|
[256] = { -- Priest: Discipline
|
|
modifiers = {CRITCHANCE = "* 1.05"},
|
|
stats = {SPIRIT = 2}
|
|
},
|
|
[257] = { -- Priest: Holy
|
|
modifiers = {MULTISTRIKE = "* 1.05"},
|
|
stats = {SPIRIT = 2}
|
|
},
|
|
[258] = { -- Priest: Shadow
|
|
modifiers = {HASTE = "* 1.05"}
|
|
},
|
|
ROGUE = {
|
|
modifiers = {AGILITY = "*1.05"},
|
|
stats = {AGILITY = 2}
|
|
},
|
|
[259] = { -- Rogue: Assassination
|
|
modifiers = {MASTERY = "* 1.05"}
|
|
},
|
|
[260] = { -- Rogue: Combat
|
|
modifiers = {HASTE = "* 1.05"},
|
|
},
|
|
[261] = { -- Rogue: Subtlety
|
|
modifiers = {TOTALAGILITY = "* 1.15", MULTISTRIKE = "* 1.05"},
|
|
},
|
|
--SHAMAN = {},
|
|
[262] = { -- Shaman: Elemental
|
|
basestat = {MULTISTRIKE = 20},
|
|
modifiers = {MULTISTRIKE = "* 1.05", MULTISTRIKEEFFECT = "* 1.35"},
|
|
stats = {INTELLECT = 2, BONUS_ARMOR = 2}
|
|
},
|
|
[263] = { -- Shaman: Enhancement
|
|
stats = {AGILITY = 2},
|
|
modifiers = {HASTE = "* 1.05", AGILITY = "* 1.05"}
|
|
},
|
|
[264] = { -- Shaman: Restoration
|
|
stats = {INTELLECT = 2, SPIRIT = 2},
|
|
modifiers = {INTELLECT = "* 1.05", MASTERY = "* 1.05"}
|
|
},
|
|
WARLOCK = {
|
|
modifiers = {INTELLECT = "*1.05"},
|
|
stats = {INTELLECT = 2}
|
|
},
|
|
[265] = { -- Warlock: Affliction
|
|
modifiers = {HASTE = "* 1.05"}
|
|
},
|
|
[266] = { -- Warlock: Demonology
|
|
modifiers = {MASTERY = "* 1.05"}
|
|
},
|
|
[267] = {modifiers = { -- Warlock: Destruction
|
|
CRITCHANCE = "* 1.15"}
|
|
},
|
|
--MONK = {},
|
|
[268] = { -- Monk: Brewmaster
|
|
modifiers = {ARMOR = "* 1.75", TOTALSTAMINA = "* 1.25", STAMINA = "* 1.05", CRITCHANCE = "* 1.05"},
|
|
stats = {AGILITY = 2, BONUS_ARMOR = 2}
|
|
},
|
|
[269] = { -- Monk: Windwalker
|
|
modifiers = {MULTISTRIKE = "* 1.05", AGILITY = "* 1.05"},
|
|
stats = {AGILITY = 2}
|
|
},
|
|
[270] = { -- Monk: Mistweaver
|
|
modifiers = {MULTISTRIKE = "* 1.05", INTELLECT = "* 1.05"},
|
|
stats = {INTELLECT = 2, SPIRIT = 2}
|
|
},
|
|
}
|
|
|
|
local function requestCharInfo(data, channel, source)
|
|
Preview:SendAddonMessage("charinforeply", Preview:GetPlayerInfo(), "WHISPER", source)
|
|
end
|
|
|
|
local function charInfoReply(data, channel, source)
|
|
|
|
end
|
|
|
|
local function defaultFormat(str, ...)
|
|
return str:format(...)
|
|
end
|
|
|
|
function Preview:GetTooltipForSpec(attrType, class, spec, ...)
|
|
local tooltips = self.classinfo.__default.stats[attrType]
|
|
if not tooltips then error("Tried to get tooltip for unknown type!") end
|
|
local spectooltips = self.classinfo[spec] and self.classinfo[spec].stats and self.classinfo[spec].stats[attrType]
|
|
local classtooltips = self.classinfo[class] and self.classinfo[class].stats and self.classinfo[class].stats[attrType]
|
|
local returnString
|
|
if spectooltips then if type(spectooltips) == "function" then return spectooltips(...) else returnString = tooltips[spectooltips] end
|
|
elseif classtooltips then if type(classtooltips) == "function" then return classtooltips(...) else returnString = tooltips[classtooltips] end
|
|
else returnString = tooltips[1] end
|
|
if type(attrType) == "function" then return attrTywpe(...) end
|
|
if returnString.func then
|
|
return returnString.func(returnString.text, ...)
|
|
else
|
|
return defaultFormat(_G[returnString.text], ...)
|
|
end
|
|
end
|
|
|
|
function Preview:GetBaseStatForSpec(stat, class, spec)
|
|
for _,v in pairs({class, spec}) do
|
|
if self.classinfo[v] and self.classinfo[v].basestat and self.classinfo[v].basestat[stat] then return self.classinfo[v].basestat[stat] end
|
|
end
|
|
return self.classinfo.__default.basestat[stat] or 0
|
|
end
|
|
|
|
function Preview:OnInitialize()
|
|
BestInSlot.Preview = Preview
|
|
self:RegisterCommFunction("requestcharinfo", requestCharInfo)
|
|
self:RegisterCommFunction("charinforeply", charInfoReply)
|
|
self.slots = CopyTable(self.slots)
|
|
tinsert(self.slots, 6, "ShirtSlot")
|
|
tinsert(self.slots, 7, "TabardSlot")
|
|
for i=1,MAX_CLASSES do
|
|
local name = select(2, GetClassInfoByID(i))
|
|
self.classes[name] = i
|
|
end
|
|
local d = date("*t")
|
|
self.aprilfools = d.day == 1 and d.month == 4
|
|
end
|
|
|
|
--[[
|
|
function Preview:OnEnable()
|
|
local unitinfo = self:GetPlayerInfo()
|
|
unitinfo.spec = self:GetSelected(self.SPECIALIZATION)
|
|
self:Show(self:GetBestInSlotItems(60001, 2, unitinfo.spec), 2, unitinfo)
|
|
end
|
|
]]
|
|
|
|
local function iconOnEnter(widget)
|
|
local link = widget:GetUserData("itemlink")
|
|
local id = widget:GetUserData("id")
|
|
if link then
|
|
GameTooltip:SetOwner(widget.frame)
|
|
GameTooltip:SetAnchorType(id and id <= 8 and "ANCHOR_LEFT" or "ANCHOR_RIGHT")
|
|
GameTooltip:SetHyperlink(link, Preview.class, Preview.spec)
|
|
GameTooltip:Show()
|
|
end
|
|
end
|
|
|
|
local function iconOnLeave(widget)
|
|
if GameTooltip:IsShown() then
|
|
GameTooltip:Hide()
|
|
end
|
|
end
|
|
|
|
function Preview:GetClassForSpec(specid)
|
|
local className = select(7, GetSpecializationInfoByID(specid))
|
|
return (self.classes[className] or self.classes[select(3, UnitClass("player"))]), className
|
|
end
|
|
|
|
function Preview:CreateSlotIcon(id)
|
|
local slotid, texture = GetInventorySlotInfo(self.slots[id])
|
|
local icon = self:QuickCreate("Icon", {SetImage=texture, SetImageSize={iconsize, iconsize}, SetWidth=iconsize, SetHeight=iconsize})
|
|
icon:SetUserData("id", id)
|
|
icon:SetCallback("OnEnter", iconOnEnter)
|
|
icon:SetCallback("OnLeave", iconOnLeave)
|
|
self.icons[slotid] = icon
|
|
return icon
|
|
end
|
|
|
|
function Preview:GetScanTooltip()
|
|
if self.scantooltip then return self.scantooltip end
|
|
if BestInSlotPreviewScanTooltip then
|
|
self.scantooltip = BestInSlotPreviewScanTooltip
|
|
return BestInSlotPreviewScanTooltip
|
|
end
|
|
local tooltip = CreateFrame("GameTooltip", "BestInSlotPreviewScanTooltip", nil, "GameTooltipTemplate")
|
|
self.scantooltip = tooltip
|
|
return tooltip
|
|
end
|
|
|
|
function Preview:SetCharacter(bislist, difficulty, charname, charspec, charsex, charrace, slots)
|
|
local playermodel = self.playermodel
|
|
for i in pairs(bislist) do
|
|
local item = bislist[i]
|
|
if type(bislist[i]) == "number" then
|
|
item = self:GetItem(bislist[i], difficulty)
|
|
elseif type(bislist[i]) == "table" and bislist[i].item then
|
|
item = self:GetItem(bislist[i].item, difficulty)
|
|
end
|
|
if item then
|
|
local slotid, slotid2 = slots and slots[i]
|
|
if not slotid then
|
|
slotid, slotid2 = self:GetItemSlotID(item.equipSlot, charspec)
|
|
end
|
|
if slotid then
|
|
local icon = self.icons[slotid]
|
|
local udt = icon:GetUserDataTable()
|
|
if udt.itemlink and slotid2 then
|
|
icon = self.icons[slotid2]
|
|
udt = icon:GetUserDataTable()
|
|
end
|
|
icon:SetImage(GetItemIcon(item.itemid))
|
|
udt.itemlink = item.link
|
|
end
|
|
playermodel:TryOn(item.link)
|
|
end
|
|
end
|
|
end
|
|
|
|
function Preview:Show(bislist, difficulty, charparams, slots)
|
|
local charname = charparams and charparams.name or UNKNOWN
|
|
local charrace = charparams and charparams.race or (UnitFactionGroup("player") == "Alliance" and "Human" or "Orc")
|
|
local charsex = charparams and charparams.sex or 0
|
|
local charspec = charparams and charparams.spec or self:GetSelected(self.SPECIALIZATION)
|
|
self.spec = charspec
|
|
self.classid, self.classname = self:GetClassForSpec(charspec)
|
|
if self.previewframe then
|
|
self:SetCharacter(bislist, difficulty, charparams, charname, charspec, charsex, charrace, slots)
|
|
return
|
|
end
|
|
local frame = AceGUI:Create("Window")
|
|
frame.frame:SetFrameStrata("DIALOG")
|
|
frame:SetHeight(400)
|
|
frame:SetWidth(538)
|
|
frame:SetTitle("BestInSlot "..PREVIEW)
|
|
frame:EnableResize(false)
|
|
frame:SetCallback("OnClose", function() Preview:ClosePreview() end)
|
|
self.previewframe = frame
|
|
frame:PauseLayout()
|
|
local previewPanel = AceGUI:Create("SimpleGroup")
|
|
previewPanel:SetWidth(338)
|
|
previewPanel:SetHeight(400)
|
|
previewPanel:PauseLayout()
|
|
previewPanel:SetPoint("TOPLEFT", frame.frame, "TOPLEFT", 10, -25)
|
|
previewPanel:SetPoint("BOTTOMLEFT", frame.frame, "BOTTOMLEFT", 10, 10)
|
|
frame:AddChild(previewPanel)
|
|
self.icons = {}
|
|
for i=1,#self.slots do
|
|
local icon = self:CreateSlotIcon(i)
|
|
if i < 17 then
|
|
local point = i < 9 and "TOPLEFT" or "TOPRIGHT"
|
|
local yOffset = - (i < 9 and i - 1 or i - 9) * (iconsize + 3)
|
|
local xOffset = i < 9 and 0 or -10
|
|
icon:SetPoint(point, previewPanel.frame, point, xOffset, yOffset)
|
|
else
|
|
icon:SetPoint("BOTTOM", previewPanel.frame, "BOTTOM", i == 17 and -iconsize / 2 or iconsize / 2 ,-5)
|
|
end
|
|
previewPanel:AddChild(icon)
|
|
end
|
|
local panel = AceGUI:Create("SimpleGroup")
|
|
panel.frame:SetFrameStrata("BACKGROUND")
|
|
self.oldbackdrop = panel.frame:GetBackdrop()
|
|
self.panel = panel
|
|
panel.frame:SetBackdrop({
|
|
bgFile = DressUpTexturePath(charrace).."1",
|
|
tile = false,
|
|
})
|
|
panel:SetPoint("TOPLEFT", self.icons[1].frame, "TOPRIGHT")
|
|
panel:SetPoint("BOTTOMRIGHT", self.icons[14].frame, "BOTTOMLEFT")
|
|
previewPanel:AddChild(panel)
|
|
local playermodel = self:CreatePlayerModel(panel.frame, charrace, charsex)
|
|
playermodel:SetPoint("BOTTOM", panel.frame)
|
|
self:SetCharacter(bislist, difficulty, charparams, charname, charspec, charsex, charrace, slots)
|
|
local statFrame = AceGUI:Create("ScrollFrame")
|
|
statFrame:SetPoint("TOPLEFT", self.icons[10].frame, "TOPRIGHT", 5, -5)
|
|
statFrame:SetPoint("BOTTOMRIGHT", frame.frame, -7, 10)
|
|
frame:AddChild(statFrame)
|
|
self:FillStatPanel(statFrame, bislist, difficulty, self.classname, charspec)
|
|
end
|
|
|
|
local function onMouseUp(self, button)
|
|
if ( button == "RightButton" and self.panning ) then
|
|
Model_StopPanning(self);
|
|
elseif ( self.mouseDown ) then
|
|
self.onMouseUpFunc(self, button);
|
|
end
|
|
end
|
|
|
|
local function onMouseDown(self, button)
|
|
if ( button == "RightButton" and not self.mouseDown ) then
|
|
Model_StartPanning(self);
|
|
else
|
|
Model_OnMouseDown(self, button);
|
|
end
|
|
end
|
|
|
|
local function onMouseWheel(self, delta)
|
|
Model_OnMouseWheel(self, delta);
|
|
end
|
|
|
|
local function onReleaseGroup(widg)
|
|
widg.frame:SetScript("OnEnter", nil) --Remove the hooked script
|
|
widg.frame:SetScript("OnLeave", nil)
|
|
widg.frame.ace = nil
|
|
widg.value.label:SetJustifyH("LEFT") --reset justify H
|
|
widg.value = nil
|
|
widg.descr = nil
|
|
end
|
|
|
|
local function onEnterStatGroup(frame)
|
|
GameTooltip:ClearLines()
|
|
GameTooltip:SetOwner(frame)
|
|
GameTooltip:SetAnchorType("ANCHOR_RIGHT")
|
|
GameTooltip:AddLine(frame.ace.tooltip, nil, nil, nil, true)
|
|
GameTooltip:AddLine(frame.ace.tooltip2, nil, nil, nil, true)
|
|
GameTooltip:Show()
|
|
GameTooltip:SetWidth(250)
|
|
end
|
|
|
|
local function onLeaveStatGroup(frame)
|
|
GameTooltip:Hide()
|
|
end
|
|
|
|
local function errorHandler(error)
|
|
Preview.console:AddError("Error caught", error)
|
|
end
|
|
|
|
function Preview:ApplyStatModifier(statName, class, spec, value)
|
|
local modifiers = {self.classinfo[spec] and self.classinfo[spec].modifiers, self.classinfo[class] and self.classinfo[class].modifiers}
|
|
if #modifiers == 0 then return value end
|
|
for _, modifier in pairs(modifiers) do
|
|
if modifier[statName] then
|
|
local f, err = loadstring("return "..value..modifier[statName])
|
|
if err then self.console:AddError("Failed to add modifier.", statName, class, spec, value, err)
|
|
else
|
|
local success, result = xpcall(f, errorHandler)
|
|
if success then value = result
|
|
else self.console:AddError("Failed to add modifier.") end
|
|
end
|
|
end
|
|
end
|
|
return value
|
|
end
|
|
|
|
function Preview:FillStatPanel(panel, bislist, difficulty, class, spec)
|
|
panel:SetLayout("Flow")
|
|
self:QuickCreate("Heading", {SetText=STAT_CATEGORY_ATTRIBUTES, SetFullWidth=true}, panel)
|
|
local bonusStats = self:GetTotalStats(bislist, difficulty, class, spec)
|
|
for i=1,#self.attributes do
|
|
local locName = self.attributes[i]
|
|
local attrId = _G["LE_UNIT_STAT_"..locName]
|
|
local attrName = _G["SPELL_STAT"..attrId.."_NAME"]
|
|
local group = self:QuickCreate("SimpleGroup", {SetWidth=200, PauseLayout=true}, panel)
|
|
local stat, effectiveStat, posBuff, negBuff = UnitStat("player", attrId)
|
|
local baseStat = stat - posBuff + negBuff
|
|
local bonusStat = bonusStats[attrName] or 0
|
|
bonusStat = floor(self:ApplyStatModifier(locName, class, spec, bonusStat))
|
|
local totalStat = floor(self:ApplyStatModifier("TOTAL"..locName, class, spec, baseStat + bonusStat))
|
|
group.frame:SetScript("OnEnter", onEnterStatGroup)
|
|
group.frame:SetScript("OnLeave", onLeaveStatGroup)
|
|
group:SetCallback("OnRelease", onReleaseGroup)
|
|
group.frame.ace = group
|
|
group.descr = self:QuickCreate("Label", {SetWidth=150, SetText=attrName}, group, "TOPLEFT")
|
|
group.value = self:QuickCreate("Label", {SetWidth=50, SetText=BreakUpLargeNumbers(totalStat)}, group, "TOPRIGHT")
|
|
if bonusStat > 0 then
|
|
group.value:SetColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b)
|
|
end
|
|
group.value.label:SetJustifyH("RIGHT")
|
|
group.tooltip, group.tooltip2 = self:GetTooltipForStat(attrId, attrName, locName, baseStat, bonusStat, totalStat, class, spec)
|
|
group:SetHeight(max(group.value.frame:GetHeight(), group.descr.frame:GetHeight()))
|
|
end
|
|
self:QuickCreate("Heading", {SetText=STAT_CATEGORY_ENHANCEMENTS, SetFullWidth=true}, panel)
|
|
for i=1,#self.enhancements do
|
|
local group = self:QuickCreate("SimpleGroup", {SetWidth=200, PauseLayout=true}, panel)
|
|
local locName = self.enhancements[i]
|
|
local enhanceName = _G["STAT_"..locName]
|
|
if not enhanceName then
|
|
if locName == "CRITCHANCE" then enhanceName = STAT_CRITICAL_STRIKE
|
|
elseif locName == "SPIRIT" then enhanceName = SPELL_STAT5_NAME
|
|
elseif locName == "ATTACK_AP" then enhanceName = ATTACK_POWER_TOOLTIP end
|
|
end
|
|
local baseStat;
|
|
if locName == "BONUS_ARMOR" then baseStat = self:ApplyStatModifier("ARMOR", class, spec, bonusStats.ARMOR or 0)
|
|
else baseStat = self:GetBaseStatForSpec(locName, class, spec) end
|
|
local bonusStat = bonusStats[enhanceName] or 0
|
|
bonusStat = floor(self:ApplyStatModifier(locName, class, spec, bonusStat))
|
|
local totalStat = baseStat + bonusStat
|
|
group.frame:SetScript("OnEnter", onEnterStatGroup)
|
|
group.frame:SetScript("OnLeave", onLeaveStatGroup)
|
|
group:SetCallback("OnRelease", onReleaseGroup)
|
|
group.frame.ace = group
|
|
group.descr = self:QuickCreate("Label", {SetWidth=150, SetText=enhanceName}, group, "TOPLEFT")
|
|
group.value = self:QuickCreate("Label", {SetWidth=50}, group, "TOPRIGHT")
|
|
group.value.label:SetJustifyH("RIGHT")
|
|
group:SetHeight(max(group.value.frame:GetHeight(), group.descr.frame:GetHeight()))
|
|
group.tooltip, group.tooltip2 = self:GetTooltipForEnhancement(enhanceName, locName, baseStat, bonusStat, class, spec, group.value)
|
|
end
|
|
local label = self:QuickCreate("Label", {SetFullWidth=true, SetText=self.colorHighlight.."BETA NOTICE: Stats are in beta and calculation might differ slightly. Please report huge differences."}, panel)
|
|
end
|
|
|
|
function Preview:GetTooltipForEnhancement(name, locName, baseStat, bonusStat, class, spec, valueWidget)
|
|
local header
|
|
local content
|
|
if locName == "SPIRIT" then
|
|
header = self:GetTooltipHeader(name, baseStat, bonusStat)
|
|
content = self:GetTooltipForSpec(locName, class, spec, baseStat + bonusStat)
|
|
valueWidget:SetText(BreakUpLargeNumbers(baseStat + bonusStat))
|
|
elseif locName == "BONUS_ARMOR" then
|
|
header = self:GetTooltipHeader(name, 0, bonusStat) --use 0 here, because baseStat contains the armor value of gear
|
|
content = self:GetTooltipForSpec(locName, class, spec, PaperDollFrame_GetArmorReduction(baseStat + bonusStat, 100), bonusStat)
|
|
valueWidget:SetText(BreakUpLargeNumbers(bonusStat))
|
|
elseif locName == "CRITCHANCE" then
|
|
local effectiveStat = 0.009090908809347 * bonusStat
|
|
header = self:GetTooltipHeader(name, baseStat, effectiveStat, true)
|
|
content = self:GetTooltipForSpec(locName, class, spec, bonusStat, effectiveStat, effectiveStat)
|
|
valueWidget:SetText(("%.2F%%"):format(baseStat + effectiveStat))
|
|
elseif locName == "HASTE" then
|
|
local effectiveStat = bonusStat / 90
|
|
header = self:GetTooltipHeader(name, baseStat, effectiveStat, true)
|
|
content = self:GetTooltipForSpec(locName, class, spec, bonusStat, effectiveStat)
|
|
valueWidget:SetText(("%.2F%%"):format(baseStat + effectiveStat))
|
|
elseif locName == "MASTERY" then
|
|
header = self:GetTooltipHeader(name, baseStat, bonusStat)
|
|
content = self:GetTooltipForSpec(locName, class, spec, baseStat + bonusStat)
|
|
valueWidget:SetText(BreakUpLargeNumbers(baseStat + bonusStat))
|
|
elseif locName == "MULTISTRIKE" then
|
|
local effectiveStat = bonusStat / 66
|
|
local multistrikeEffect = self:ApplyStatModifier("MULTISTRIKEEFFECT", class, spec, 30)
|
|
local totalEffect = effectiveStat + baseStat
|
|
|
|
header = self:GetTooltipHeader(name, baseStat, effectiveStat, true)
|
|
content = self:GetTooltipForSpec(locName, class, spec, totalEffect, multistrikeEffect, BreakUpLargeNumbers(bonusStat), effectiveStat)
|
|
valueWidget:SetText(("%.2F%%"):format(totalEffect))
|
|
elseif locName == "VERSATILITY" then
|
|
local effectiveStat = bonusStat / 130
|
|
local totalStat = baseStat + effectiveStat
|
|
header = self:GetTooltipHeader(name, baseStat, effectiveStat, true)
|
|
content = self:GetTooltipForSpec(locName, class, spec, totalStat, totalStat / 2, BreakUpLargeNumbers(bonusStat), effectiveStat, effectiveStat / 2)
|
|
valueWidget:SetText(("%.2F%%"):format(totalStat))
|
|
elseif locName == "LIFESTEAL" or locName == "AVOIDANCE" then
|
|
header = self:GetTooltipHeader(name, 0, 0)
|
|
content = self:GetTooltipForSpec(locName, class, spec, 0, 0, 0)
|
|
valueWidget:SetText(("%.2F%%"):format(0))
|
|
elseif locName == "ATTACK_AP" or locName == "SPELLPOWER" then
|
|
header = self:GetTooltipHeader(name, bonusStat, 0)
|
|
content = self:GetTooltipForSpec(locName, class, spec, bonusStat)
|
|
valueWidget:SetText(BreakUpLargeNumbers(bonusStat))
|
|
end
|
|
return header or "NYI", content or "NYI"
|
|
end
|
|
|
|
local function BreakUpLargeNumbersWithPercentage(value)
|
|
return BreakUpLargeNumbers(value) .. "%"
|
|
end
|
|
|
|
function Preview:GetTooltipHeader(name, baseStat, bonusStat, isPercentage, totalStat)
|
|
local tooltip = HIGHLIGHT_FONT_COLOR_CODE..PAPERDOLLFRAME_TOOLTIP_FORMAT:format(name).." "
|
|
totalStat = totalStat or baseStat + bonusStat
|
|
local formatFunc = isPercentage and BreakUpLargeNumbersWithPercentage or BreakUpLargeNumbers
|
|
bonusStat = formatFunc(bonusStat)
|
|
if bonusStat == "0" then
|
|
tooltip = tooltip .. formatFunc(baseStat) .. FONT_COLOR_CODE_CLOSE
|
|
elseif isPercentage then
|
|
tooltip = tooltip .. formatFunc(totalStat) .. FONT_COLOR_CODE_CLOSE
|
|
else
|
|
tooltip = tooltip .. formatFunc(totalStat) .. " ( " .. (baseStat > 0 and formatFunc(baseStat) or "") .. FONT_COLOR_CODE_CLOSE .. GREEN_FONT_COLOR_CODE .. "+" .. bonusStat .. FONT_COLOR_CODE_CLOSE .. HIGHLIGHT_FONT_COLOR_CODE .. ")"
|
|
end
|
|
return tooltip
|
|
end
|
|
|
|
function Preview:GetTooltipForStat(statId, statName, locName, baseStat, bonusStat, totalStat, class, spec)
|
|
return self:GetTooltipHeader(statName, baseStat, bonusStat, false, totalStat), self:GetTooltipForSpec(locName, class, spec, totalStat)
|
|
end
|
|
|
|
local function isColorDisabledColor(r,g,b)
|
|
r = (floor(r * 10))
|
|
g = (floor(g * 10))
|
|
b = (floor(b * 10))
|
|
return abs(r - GRAY_FONT_COLOR.r * 10) <= 5 and abs(g - GRAY_FONT_COLOR.g * 10) <= 5 and abs(b - GRAY_FONT_COLOR.b * 10) <= 1
|
|
end
|
|
|
|
local searchPattern1 = "+(%d+) (.+)"
|
|
local searchPattern2 = "+(%d+),(%d%d%d) (.+)"
|
|
local searchArmorPattern = ARMOR_TEMPLATE:format("(%d+)")
|
|
local function readLine(line, arr)
|
|
local text = line:GetText()
|
|
if not text then return end
|
|
if text:find(DISABLED_FONT_COLOR_CODE) then return end
|
|
local thousands, amount, statName = text:match(searchPattern2)
|
|
if not thousands then
|
|
amount, statName = text:match(searchPattern1)
|
|
if not amount then
|
|
amount = text:match(searchArmorPattern)
|
|
if not amount then
|
|
return
|
|
else
|
|
statName = "ARMOR"
|
|
end
|
|
end
|
|
else
|
|
amount = amount + thousands * 1000
|
|
end
|
|
local r,g,b = line:GetTextColor()
|
|
if isColorDisabledColor(r,g,b) then
|
|
return
|
|
end
|
|
arr[statName] = (arr[statName] or 0) + amount
|
|
end
|
|
|
|
function Preview:GetTotalStats(bislist, difficulty, class, spec)
|
|
local totalStats = {}
|
|
local tooltip = self:GetScanTooltip()
|
|
--[[Normal functionality
|
|
for i in pairs(bislist) do
|
|
local item = self:GetItem(bislist[i].item, difficulty)
|
|
if item then
|
|
tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
|
tooltip:ClearLines()
|
|
tooltip:SetHyperlink(item.itemstr, class, spec)
|
|
tooltip:Show()
|
|
local line = _G["BestInSlotPreviewScanTooltipTextLeft1"]
|
|
local i = 1
|
|
while line do
|
|
readLine(line, totalStats)
|
|
i = i + 1
|
|
line = _G["BestInSlotPreviewScanTooltipTextLeft"..i]
|
|
end
|
|
tooltip:Hide()
|
|
end
|
|
end --]]
|
|
--DEBUG WITH CURRENT GEAR
|
|
for j=1,19 do
|
|
local link = GetInventoryItemLink("player", j)
|
|
if link then
|
|
tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
|
tooltip:ClearLines()
|
|
tooltip:SetHyperlink(link, class, spec)
|
|
tooltip:Show()
|
|
local line = _G["BestInSlotPreviewScanTooltipTextLeft1"]
|
|
local i = 1
|
|
while line do
|
|
readLine(line, totalStats)
|
|
i = i + 1
|
|
line = _G["BestInSlotPreviewScanTooltipTextLeft"..i]
|
|
end
|
|
tooltip:Hide()
|
|
end
|
|
end--]]
|
|
return totalStats
|
|
end
|
|
|
|
function Preview:CreatePlayerModel(parent, race, sex)
|
|
local playermodel = self.playermodel
|
|
if not playermodel then
|
|
playermodel = CreateFrame("DressUpModel", "BestInSlotPlayerModel", UIParent)
|
|
playermodel:SetHeight(self.panel.frame:GetHeight())
|
|
playermodel:SetFrameStrata("FULLSCREEN")
|
|
playermodel:SetWidth(244)
|
|
playermodel:SetScript("OnLoad", Model_OnLoad)
|
|
playermodel:SetScript("OnEvent", Model_OnEvent)
|
|
playermodel:SetScript("OnUpdate", Model_OnUpdate)
|
|
playermodel:SetScript("OnMouseUp", onMouseUp)
|
|
playermodel:SetScript("OnMouseDown", onMouseDown)
|
|
playermodel:SetScript("OnMouseWheel", onMouseWheel)
|
|
Model_OnLoad(playermodel)
|
|
self.playermodel = playermodel
|
|
end
|
|
playermodel:Show()
|
|
playermodel:SetUnit("PLAYER")
|
|
if self.aprilfools then
|
|
playermodel:SetCreature(1211)
|
|
else
|
|
playermodel:SetCustomRace(self.raceids[race], sex)
|
|
end
|
|
playermodel:Undress()
|
|
|
|
return playermodel
|
|
end
|
|
|
|
function Preview:ClosePreview()
|
|
local frame = self.previewframe
|
|
self.panel.frame:SetBackdrop(self.oldbackdrop)
|
|
frame:Release()
|
|
self.previewframe = nil
|
|
self.panel = nil
|
|
self.oldbackdrop = nil
|
|
self.icons = nil
|
|
self.spec = nil
|
|
self.class = nil
|
|
self.playermodel:Hide()
|
|
end
|
|
|