Initial publication
This commit is contained in:
389
Amibis/Amibis.lua
Normal file
389
Amibis/Amibis.lua
Normal file
@@ -0,0 +1,389 @@
|
||||
local addonName, ns = ...
|
||||
|
||||
local Amibis = {}
|
||||
ns.Amibis = Amibis
|
||||
Amibis.version = "1.0.0"
|
||||
|
||||
local DEFAULT_AMIBIS_DB = {
|
||||
selectedPhase = "T5",
|
||||
}
|
||||
|
||||
local DEFAULT_AMIBIS_CHAR_DB = {
|
||||
frameX = nil,
|
||||
frameY = nil,
|
||||
framePoint = nil,
|
||||
frameRelPoint = nil,
|
||||
overrideSpec = nil,
|
||||
}
|
||||
|
||||
local function InitializeDB()
|
||||
if not AmibisDB then
|
||||
AmibisDB = CopyTable(DEFAULT_AMIBIS_DB)
|
||||
else
|
||||
for k, v in pairs(DEFAULT_AMIBIS_DB) do
|
||||
if AmibisDB[k] == nil then
|
||||
AmibisDB[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not AmibisCharDB then
|
||||
AmibisCharDB = CopyTable(DEFAULT_AMIBIS_CHAR_DB)
|
||||
else
|
||||
for k, v in pairs(DEFAULT_AMIBIS_CHAR_DB) do
|
||||
if AmibisCharDB[k] == nil then
|
||||
AmibisCharDB[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Amibis:GetPlayerClass()
|
||||
return select(2, UnitClass("player"))
|
||||
end
|
||||
|
||||
function Amibis:GetPlayerSpec()
|
||||
local class = self:GetPlayerClass()
|
||||
local specNames = {
|
||||
["PRIEST"] = { "Discipline", "Holy", "Shadow" },
|
||||
["MAGE"] = { "Arcane", "Fire", "Frost" },
|
||||
["WARLOCK"] = { "Affliction", "Demonology", "Destruction" },
|
||||
["DRUID"] = { "Balance", "Feral Combat", "Restoration" },
|
||||
["PALADIN"] = { "Holy", "Protection", "Retribution" },
|
||||
["SHAMAN"] = { "Elemental", "Enhancement", "Restoration" },
|
||||
["WARRIOR"] = { "Arms", "Fury", "Protection" },
|
||||
["ROGUE"] = { "Assassination", "Combat", "Subtlety" },
|
||||
["HUNTER"] = { "Beast Mastery", "Marksmanship", "Survival" },
|
||||
}
|
||||
|
||||
if not specNames[class] then
|
||||
return nil
|
||||
end
|
||||
|
||||
local maxPoints = 0
|
||||
local specIndex = 1
|
||||
|
||||
for i = 1, 3 do
|
||||
local r1, r2, r3, r4 = GetTalentTabInfo(i)
|
||||
local points = tonumber(r1) or tonumber(r2) or tonumber(r3) or tonumber(r4) or 0
|
||||
if points > maxPoints then
|
||||
maxPoints = points
|
||||
specIndex = i
|
||||
end
|
||||
end
|
||||
|
||||
return specNames[class][specIndex]
|
||||
end
|
||||
|
||||
function Amibis:GetEquippedItems()
|
||||
local items = {}
|
||||
local slotMap = {
|
||||
["Head"] = 1,
|
||||
["Neck"] = 2,
|
||||
["Shoulder"] = 3,
|
||||
["Back"] = 15,
|
||||
["Chest"] = 5,
|
||||
["Wrist"] = 9,
|
||||
["Hands"] = 10,
|
||||
["Waist"] = 6,
|
||||
["Legs"] = 7,
|
||||
["Feet"] = 8,
|
||||
["Finger0"] = 11,
|
||||
["Finger1"] = 12,
|
||||
["Trinket0"] = 13,
|
||||
["Trinket1"] = 14,
|
||||
["MainHand"] = 16,
|
||||
["SecondaryHand"] = 17,
|
||||
["Ranged"] = 18,
|
||||
}
|
||||
|
||||
for slotName, slotID in pairs(slotMap) do
|
||||
local link = GetInventoryItemLink("player", slotID)
|
||||
if link then
|
||||
local itemID = tonumber(link:match("item:(%d+)"))
|
||||
local name = GetItemInfo(itemID) or "Unknown"
|
||||
items[slotName] = {
|
||||
itemID = itemID,
|
||||
name = name,
|
||||
link = link,
|
||||
slotID = slotID,
|
||||
}
|
||||
else
|
||||
items[slotName] = nil
|
||||
end
|
||||
end
|
||||
|
||||
return items
|
||||
end
|
||||
|
||||
local STAT_MAP = {
|
||||
["ITEM_MOD_HEALING_DONE_SHORT"] = "healing",
|
||||
["ITEM_MOD_SPELL_HEALING_DONE_SHORT"] = "healing",
|
||||
["ITEM_MOD_HEALING_DONE"] = "healing",
|
||||
["ITEM_MOD_SPELL_HEALING_DONE"] = "healing",
|
||||
["ITEM_MOD_DAMAGE_DONE_SHORT"] = "spellDamage",
|
||||
["ITEM_MOD_SPELL_DAMAGE_DONE_SHORT"] = "spellDamage",
|
||||
["ITEM_MOD_DAMAGE_DONE"] = "spellDamage",
|
||||
["ITEM_MOD_SPELL_DAMAGE_DONE"] = "spellDamage",
|
||||
["ITEM_MOD_INTELLECT_SHORT"] = "intellect",
|
||||
["ITEM_MOD_SPIRIT_SHORT"] = "spirit",
|
||||
["ITEM_MOD_STAMINA_SHORT"] = "stamina",
|
||||
["ITEM_MOD_MANA_REGENERATION_SHORT"] = "mp5",
|
||||
["ITEM_MOD_POWER_REGEN0_SHORT"] = "mp5",
|
||||
["ITEM_MOD_HASTE_RATING_SHORT"] = "haste",
|
||||
["ITEM_MOD_SPELL_HASTE_RATING_SHORT"] = "haste",
|
||||
["ITEM_MOD_SPELL_CRIT_RATING_SHORT"] = "crit",
|
||||
["ITEM_MOD_CRIT_RATING_SHORT"] = "crit",
|
||||
["ITEM_MOD_SPELL_POWER_SHORT"] = "spellPower",
|
||||
["ITEM_MOD_SPELL_DMG_SHORT"] = "spellDamage",
|
||||
["ITEM_MOD_HEALING_SHORT"] = "healing",
|
||||
}
|
||||
|
||||
function Amibis:ScanItemStats(itemID)
|
||||
if not itemID then return nil end
|
||||
|
||||
local _, link = GetItemInfo(itemID)
|
||||
if not link then
|
||||
link = "item:" .. itemID .. ":0:0:0:0:0:0:0:0"
|
||||
end
|
||||
|
||||
local stats = GetItemStats(link)
|
||||
if not stats then return nil end
|
||||
|
||||
local result = {}
|
||||
for wowKey, ourKey in pairs(STAT_MAP) do
|
||||
if stats[wowKey] then
|
||||
result[ourKey] = (result[ourKey] or 0) + stats[wowKey]
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function Amibis:AggregateStats(items)
|
||||
local totals = {
|
||||
healing = 0,
|
||||
spellDamage = 0,
|
||||
intellect = 0,
|
||||
spirit = 0,
|
||||
stamina = 0,
|
||||
mp5 = 0,
|
||||
haste = 0,
|
||||
crit = 0,
|
||||
spellPower = 0,
|
||||
}
|
||||
|
||||
for slotName, item in pairs(items) do
|
||||
if item and item.itemID then
|
||||
local stats = self:ScanItemStats(item.itemID)
|
||||
if stats then
|
||||
for k, v in pairs(stats) do
|
||||
totals[k] = (totals[k] or 0) + v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return totals
|
||||
end
|
||||
|
||||
function Amibis:CompareGear()
|
||||
local class = self:GetPlayerClass()
|
||||
local spec = AmibisCharDB.overrideSpec or self:GetPlayerSpec()
|
||||
local phase = AmibisDB.selectedPhase or "T5"
|
||||
|
||||
local bisList = ns.Data.BISLists:GetBISList(class, spec, phase)
|
||||
if not bisList then
|
||||
return {
|
||||
class = class,
|
||||
spec = spec,
|
||||
phase = phase,
|
||||
hasBISList = false,
|
||||
slots = {},
|
||||
bisCount = 0,
|
||||
totalSlots = 0,
|
||||
biggestUpgrade = nil,
|
||||
}
|
||||
end
|
||||
|
||||
local equipped = self:GetEquippedItems()
|
||||
local slots = {}
|
||||
local bisCount = 0
|
||||
local totalSlots = 0
|
||||
local biggestUpgrade = nil
|
||||
|
||||
for slotName, bisItem in pairs(bisList) do
|
||||
totalSlots = totalSlots + 1
|
||||
local equippedItem = equipped[slotName]
|
||||
local isBIS = false
|
||||
|
||||
if equippedItem and equippedItem.itemID == bisItem.itemID then
|
||||
isBIS = true
|
||||
bisCount = bisCount + 1
|
||||
end
|
||||
|
||||
local itemLevelDiff = nil
|
||||
if equippedItem and not isBIS then
|
||||
local equippedILvl = GetItemInfo(equippedItem.itemID) and select(4, GetItemInfo(equippedItem.itemID))
|
||||
local bisILvl = GetItemInfo(bisItem.itemID) and select(4, GetItemInfo(bisItem.itemID))
|
||||
if equippedILvl and bisILvl then
|
||||
itemLevelDiff = bisILvl - equippedILvl
|
||||
end
|
||||
end
|
||||
|
||||
if not isBIS and equippedItem then
|
||||
if not biggestUpgrade or (itemLevelDiff and biggestUpgrade.itemLevelDiff and itemLevelDiff > biggestUpgrade.itemLevelDiff) then
|
||||
biggestUpgrade = {
|
||||
slot = slotName,
|
||||
equipped = equippedItem,
|
||||
bis = bisItem,
|
||||
itemLevelDiff = itemLevelDiff,
|
||||
}
|
||||
elseif not biggestUpgrade then
|
||||
biggestUpgrade = {
|
||||
slot = slotName,
|
||||
equipped = equippedItem,
|
||||
bis = bisItem,
|
||||
itemLevelDiff = itemLevelDiff,
|
||||
}
|
||||
end
|
||||
elseif not isBIS and not biggestUpgrade then
|
||||
biggestUpgrade = {
|
||||
slot = slotName,
|
||||
equipped = nil,
|
||||
bis = bisItem,
|
||||
itemLevelDiff = nil,
|
||||
}
|
||||
end
|
||||
|
||||
table.insert(slots, {
|
||||
slotName = slotName,
|
||||
equipped = equippedItem,
|
||||
bis = bisItem,
|
||||
isBIS = isBIS,
|
||||
itemLevelDiff = itemLevelDiff,
|
||||
})
|
||||
end
|
||||
|
||||
table.sort(slots, function(a, b)
|
||||
if a.isBIS ~= b.isBIS then
|
||||
return b.isBIS
|
||||
end
|
||||
return a.slotName < b.slotName
|
||||
end)
|
||||
|
||||
local equippedStats = self:AggregateStats(equipped)
|
||||
|
||||
for slotName, bisItem in pairs(bisList) do
|
||||
GetItemInfo(bisItem.itemID)
|
||||
end
|
||||
|
||||
local bisItems = {}
|
||||
for slotName, bisItem in pairs(bisList) do
|
||||
bisItems[slotName] = { itemID = bisItem.itemID }
|
||||
end
|
||||
local bisStats = self:AggregateStats(bisItems)
|
||||
|
||||
local statsComplete = true
|
||||
for slotName, bisItem in pairs(bisList) do
|
||||
local _, link = GetItemInfo(bisItem.itemID)
|
||||
if link then
|
||||
local s = GetItemStats(link)
|
||||
if not s or not next(s) then
|
||||
statsComplete = false
|
||||
break
|
||||
end
|
||||
else
|
||||
statsComplete = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
class = class,
|
||||
spec = spec,
|
||||
phase = phase,
|
||||
hasBISList = true,
|
||||
slots = slots,
|
||||
bisCount = bisCount,
|
||||
totalSlots = totalSlots,
|
||||
biggestUpgrade = biggestUpgrade,
|
||||
equippedStats = equippedStats,
|
||||
bisStats = bisStats,
|
||||
statsComplete = statsComplete,
|
||||
}
|
||||
end
|
||||
|
||||
function Amibis:SaveFramePosition(frame)
|
||||
local point, _, relPoint, x, y = frame:GetPoint()
|
||||
AmibisCharDB.framePoint = point
|
||||
AmibisCharDB.frameRelPoint = relPoint
|
||||
AmibisCharDB.frameX = x
|
||||
AmibisCharDB.frameY = y
|
||||
end
|
||||
|
||||
function Amibis:LoadFramePosition(frame)
|
||||
local point = AmibisCharDB.framePoint
|
||||
local relPoint = AmibisCharDB.frameRelPoint
|
||||
local x = AmibisCharDB.frameX
|
||||
local y = AmibisCharDB.frameY
|
||||
|
||||
if point and x and y then
|
||||
frame:ClearAllPoints()
|
||||
frame:SetPoint(point, UIParent, relPoint or point, x, y)
|
||||
else
|
||||
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function Amibis:InitializeUI()
|
||||
if ns.UI and ns.UI.Initialize then
|
||||
ns.UI.Initialize()
|
||||
end
|
||||
end
|
||||
|
||||
function Amibis:ToggleFrame()
|
||||
if ns.UI and ns.UI.ToggleFrame then
|
||||
ns.UI.ToggleFrame()
|
||||
end
|
||||
end
|
||||
|
||||
local eventFrame = CreateFrame("Frame")
|
||||
eventFrame:RegisterEvent("ADDON_LOADED")
|
||||
eventFrame:RegisterEvent("PLAYER_LOGIN")
|
||||
eventFrame:RegisterEvent("PLAYER_TALENT_UPDATE")
|
||||
|
||||
eventFrame:SetScript("OnEvent", function(self, event, ...)
|
||||
if event == "ADDON_LOADED" then
|
||||
local addon = ...
|
||||
if addon == addonName then
|
||||
InitializeDB()
|
||||
end
|
||||
elseif event == "PLAYER_LOGIN" then
|
||||
Amibis:InitializeUI()
|
||||
elseif event == "PLAYER_TALENT_UPDATE" then
|
||||
if ns.UI and ns.UI.RefreshUI then
|
||||
ns.UI.RefreshUI()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
SLASH_AMIBIS1 = "/amibis"
|
||||
SlashCmdList["AMIBIS"] = function(msg)
|
||||
local cmd = msg:trim():lower()
|
||||
if cmd == "" then
|
||||
Amibis:ToggleFrame()
|
||||
elseif cmd:find("^spec%s+") then
|
||||
local spec = cmd:match("^spec%s+(.+)")
|
||||
if spec and spec ~= "" then
|
||||
spec = spec:gsub("^%l", string.upper)
|
||||
AmibisCharDB.overrideSpec = spec
|
||||
print("Amibis: Spec override set to " .. spec .. ". Type /amibis spec clear to reset.")
|
||||
end
|
||||
elseif cmd == "spec clear" then
|
||||
AmibisCharDB.overrideSpec = nil
|
||||
print("Amibis: Spec override cleared.")
|
||||
else
|
||||
Amibis:ToggleFrame()
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user