Files
amibis/Amibis/Amibis.lua
2026-06-04 00:04:49 +02:00

390 lines
11 KiB
Lua

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