diff --git a/Addon.lua b/Addon.lua
index f4ad493..c19a001 100644
--- a/Addon.lua
+++ b/Addon.lua
@@ -11,6 +11,14 @@ local ns = select(2, ...)
local ShowUIPanel = LibStub('LibShowUIPanel-1.0').ShowUIPanel
+---@class UI
+---@field BaseItem UI.BaseItem
+---@field GearItem UI.GearItem
+---@field GearFrame UI.GearFrame
+---@field GemItem UI.GemItem
+---@field EnchantItem UI.EnchantItem
+---@field InspectFrame UI.InspectFrame
+---@field InspectGearFrame UI.InspectGearFrame
ns.UI = {}
ns.L = LibStub('AceLocale-3.0'):GetLocale('tdInspect')
diff --git a/Api.lua b/Api.lua
index e3958f5..38c622f 100644
--- a/Api.lua
+++ b/Api.lua
@@ -150,3 +150,26 @@ function ns.ResolveTalent(class, data)
local talent = ns.Talent:New(class, data)
return talent:ToString()
end
+
+local function FlagTest(value, flag)
+ return bit.band(value, bit.lshift(1, flag)) > 0
+end
+
+function ns.GetItemEnchantInfo(link)
+ if not link then
+ return
+ end
+ local enchantId = tonumber(link:match('item:%d+:(%d*)'))
+ if enchantId then
+ local itemId, _, _, _, _, classId, subClassId = GetItemInfoInstant(link)
+ local invType = C_Item.GetItemInventoryTypeByID(itemId)
+
+ for _, v in ipairs(ns.ItemEnchants) do
+ if v.enchantId == enchantId and v.classId == classId and
+ (not v.subClassMask or FlagTest(v.subClassMask, subClassId)) and
+ (not v.invTypeMask or FlagTest(v.invTypeMask, invType)) then
+ return v
+ end
+ end
+ end
+end
diff --git a/Core/Inspect.lua b/Core/Inspect.lua
index 4d02953..8d07a39 100644
--- a/Core/Inspect.lua
+++ b/Core/Inspect.lua
@@ -132,6 +132,14 @@ function Inspect:SetUnit(unit, name)
end
end
+function Inspect:GetUnitName()
+ if self.unit then
+ return ns.UnitName(self.unit)
+ else
+ return Ambiguate(self.unitName, 'none')
+ end
+end
+
function Inspect:Clear()
ClearInspectPlayer()
self.unitName = nil
@@ -177,6 +185,73 @@ function Inspect:IsItemEquipped(itemId)
end
end
+local function GetSlotItemLevel(slot)
+ local itemId = Inspect:GetItemLink(slot)
+ if not itemId then
+ return 0
+ end
+
+ local itemLevel = select(4, GetItemInfo(itemId))
+ if itemLevel then
+ return itemLevel
+ end
+end
+
+local function GetMainhandItemLevel(slot)
+ local itemId = Inspect:GetItemLink(slot)
+ if not itemId then
+ return 0
+ end
+ local itemLevel, _, _, _, _, itemEquipLoc = select(4, GetItemInfo(itemId))
+ if itemEquipLoc == 'INVTYPE_2HWEAPON' then
+ return itemLevel * 2
+ end
+ return itemLevel
+end
+
+local function GetRangedItemLevel(slot)
+ if UnitClassBase('player') ~= 'HUNTER' then
+ return 0, true
+ end
+ return GetSlotItemLevel(slot)
+end
+
+local SLOTS = {
+ [INVSLOT_HEAD] = GetSlotItemLevel,
+ [INVSLOT_NECK] = GetSlotItemLevel,
+ [INVSLOT_SHOULDER] = GetSlotItemLevel,
+ [INVSLOT_CHEST] = GetSlotItemLevel,
+ [INVSLOT_WAIST] = GetSlotItemLevel,
+ [INVSLOT_LEGS] = GetSlotItemLevel,
+ [INVSLOT_FEET] = GetSlotItemLevel,
+ [INVSLOT_WRIST] = GetSlotItemLevel,
+ [INVSLOT_HAND] = GetSlotItemLevel,
+ [INVSLOT_FINGER1] = GetSlotItemLevel,
+ [INVSLOT_FINGER2] = GetSlotItemLevel,
+ [INVSLOT_TRINKET1] = GetSlotItemLevel,
+ [INVSLOT_TRINKET2] = GetSlotItemLevel,
+ [INVSLOT_BACK] = GetSlotItemLevel,
+ [INVSLOT_MAINHAND] = GetMainhandItemLevel,
+ [INVSLOT_OFFHAND] = GetSlotItemLevel,
+ [INVSLOT_RANGED] = GetRangedItemLevel,
+}
+
+function Inspect:GetItemLevel()
+ local total, count = 0, 0
+
+ for slot, f in pairs(SLOTS) do
+ local itemLevel, ignore = f(slot)
+ if not itemLevel then
+ return
+ end
+ if not ignore then
+ count = count + 1
+ total = total + itemLevel
+ end
+ end
+ return total / count
+end
+
-- @build>2@
local GEM_COLORS = {
[Enum.ItemGemSubclass.Red] = {Enum.ItemGemSubclass.Red},
@@ -226,40 +301,23 @@ end
-- @end-build>2@
function Inspect:GetEquippedSetItems(id)
- local count = 0
local items = {}
- local overrideNames = {}
- local slotItems = ns.ItemSets[id].slots
-
+ local count = 0
for slot = 1, 18 do
local link = self:GetItemLink(slot)
if link then
local name, _, _, _, _, _, _, _, equipLoc, _, _, _, _, _, _, setId = GetItemInfo(link)
if name and setId and setId == id then
- local baseName
local itemId = ns.ItemLinkToId(link)
-
if equipLoc == 'INVTYPE_ROBE' then
equipLoc = 'INVTYPE_CHEST'
end
-
- local isBaseItem = slotItems[equipLoc][itemId]
- if not isBaseItem then
- local baseItemId = next(slotItems[equipLoc])
- baseName = GetItemInfo(baseItemId)
- if baseName then
- overrideNames[baseName] = name
- end
- items[name] = (items[name] or 0) + 1
- end
-
+ items[equipLoc] = itemId
count = count + 1
- baseName = baseName or name
- items[baseName] = (items[baseName] or 0) + 1
end
end
end
- return count, items, overrideNames
+ return count, items
end
function Inspect:GetUnitClassFileName()
@@ -302,6 +360,17 @@ function Inspect:GetUnitLevel()
end
end
+function Inspect:GetDataSource()
+ if self.db.proto then
+ if self.db.proto.tdInspect then
+ return 'tdInspect'
+ elseif self.db.proto.TalentEmu then
+ return 'TalentEmu'
+ end
+ end
+ return 'Blizzard'
+end
+
function Inspect:GetNumTalentGroups()
return self.db.numGroups or 0
end
@@ -399,11 +468,11 @@ function Inspect:Query(unit, name)
if queryEquip or queryTalent or queryGlyph or queryRune then
local co = coroutine.create(function()
- local me = self:IsCharacterHasProto('tdInspect')
- local ala = self:IsCharacterHasProto('TalentEmu')
+ local unitName = self.unitName
+ local me = self:IsCharacterHasProto(unitName, 'tdInspect')
+ local ala = self:IsCharacterHasProto(unitName, 'TalentEmu')
-
- self:ClearCharacterProto(self.unitName, 'tdInspect')
+ self:ClearCharacterProto(unitName, 'tdInspect')
self:SendCommMessage(PROTO_PREFIX, Serializer:Serialize('Q', queryTalent, queryEquip, PROTO_VERSION,
queryGlyph, queryRune), 'WHISPER', self.unitName)
@@ -411,11 +480,11 @@ function Inspect:Query(unit, name)
sleep(1)
end
- if self:IsCharacterHasProto('tdInspect') then
+ if self:IsCharacterHasProto(unitName, 'tdInspect') then
return
end
- self:ClearCharacterProto(self.unitName, 'TalentEmu')
+ self:ClearCharacterProto(unitName, 'TalentEmu')
self:SendCommMessage(ALA_PREFIX, ns.Ala:PackQuery(queryEquip, queryTalent, queryGlyph, queryRune),
'WHISPER', self.unitName)
@@ -423,7 +492,7 @@ function Inspect:Query(unit, name)
sleep(1)
end
- if self:IsCharacterHasProto('TalentEmu') then
+ if self:IsCharacterHasProto(unitName, 'TalentEmu') then
return
end
@@ -510,6 +579,12 @@ end
function Inspect:UpdateCharacter(sender, data)
local name = ns.GetFullName(sender)
+
+ if self:IsCharacterHasProto(name, 'tdInspect') and self.userCache[name] and self.userCache[name].timestamp and
+ time() - self.userCache[name].timestamp < 5 then
+ return
+ end
+
local db = self:BuildCharacterDb(name)
if data.class then
diff --git a/Data/DataLoader.lua b/Data/DataLoader.lua
index 02a3299..fff6565 100644
--- a/Data/DataLoader.lua
+++ b/Data/DataLoader.lua
@@ -11,6 +11,7 @@ ns.ItemSets = {}
ns.Glyphes = {}
ns.SpellGlyphes = {}
ns.GlyphSlots = {}
+ns.ItemEnchants = {}
local strsplittable = strsplittable or function(delimiter, str, pieces)
return {strsplit(delimiter, str, pieces)}
@@ -131,9 +132,7 @@ function ns.ItemSetMake()
end
local function SetItemSetSlotItem(slot, itemId)
- slot = SLOTS[slot]
- CURRENT.slots[slot] = CURRENT.slots[slot] or {}
- CURRENT.slots[slot][itemId] = true
+ tinsert(CURRENT.slots, {slot = SLOTS[slot], itemId = itemId})
end
setfenv(2, { --
@@ -162,3 +161,20 @@ function ns.GlyphMake()
setfenv(2, {D = Data, S = Slot})
end
+
+function ns.ItemEnchantMake()
+ ns.ItemEnchantMake = nil
+
+ local Data = function(enchantId, spellId, itemId, classId, subClassMask, invTypeMask)
+ tinsert(ns.ItemEnchants, {
+ enchantId = enchantId,
+ spellId = spellId,
+ itemId = itemId,
+ classId = classId,
+ subClassMask = subClassMask,
+ invTypeMask = invTypeMask,
+ })
+ end
+
+ setfenv(2, {D = Data})
+end
diff --git a/Data/Wrath/ItemEnchant.lua b/Data/Wrath/ItemEnchant.lua
new file mode 100644
index 0000000..026e75f
--- /dev/null
+++ b/Data/Wrath/ItemEnchant.lua
@@ -0,0 +1,482 @@
+select(2,...).ItemEnchantMake()
+local n=nil
+D(15,2831,2304,4,30,1050016)
+D(16,2832,2313,4,30,1050016)
+D(17,2833,4265,4,30,1050016)
+D(30,3974,4405,2,262156,n)
+D(32,3975,4406,2,262156,n)
+D(33,3976,4407,2,262156,n)
+D(36,6296,5421,2,189939,n)
+D(43,7216,6042,4,96,n)
+D(34,7218,6043,2,354,n)
+D(37,7220,6041,2,173555,n)
+D(41,7418,38679,4,31,512)
+D(41,7420,38766,4,31,1048608)
+D(44,7426,38767,4,31,1048608)
+D(924,7428,38768,4,31,512)
+D(24,7443,38769,4,31,1048608)
+D(65,7454,38770,4,31,65536)
+D(66,7457,38771,4,31,512)
+D(241,7745,38772,2,1378,n)
+D(242,7748,38773,4,31,1048608)
+D(243,7766,38774,4,31,512)
+D(783,7771,38775,4,31,65536)
+D(246,7776,38776,4,31,1048608)
+D(247,7779,38777,4,31,512)
+D(248,7782,38778,4,31,512)
+D(249,7786,38779,2,189939,n)
+D(250,7788,38780,2,189939,n)
+D(723,7793,38781,2,1378,n)
+D(254,7857,38782,4,31,1048608)
+D(255,7859,38783,4,31,512)
+D(256,7861,38784,4,31,65536)
+D(66,7863,38785,4,31,256)
+D(247,7867,38786,4,31,256)
+D(463,9781,7967,4,96,n)
+D(464,9783,7969,4,n,256)
+D(18,10344,8173,4,30,1050016)
+D(663,12459,10546,2,262156,n)
+D(664,12460,10548,2,262156,n)
+D(66,13378,38787,4,64,n)
+D(255,13380,38788,2,1378,n)
+D(247,13419,38789,4,30,65536)
+D(744,13421,38790,4,n,65536)
+D(848,13464,38791,4,64,n)
+D(255,13485,38792,4,64,n)
+D(724,13501,38793,4,31,512)
+D(241,13503,38794,2,189939,n)
+D(804,13522,38795,4,31,65536)
+D(943,13529,38796,2,1378,n)
+D(823,13536,38797,4,31,512)
+D(63,13538,38798,4,31,1048608)
+D(843,13607,38799,4,31,1048608)
+D(844,13612,38800,4,31,1024)
+D(845,13617,38801,4,31,1024)
+D(2603,13620,38802,4,31,1024)
+D(723,13622,38803,4,31,512)
+D(847,13626,38804,4,31,1048608)
+D(724,13631,38805,4,64,n)
+D(848,13635,38806,4,30,65536)
+D(849,13637,38807,4,31,256)
+D(850,13640,38808,4,30,1048608)
+D(851,13642,38809,4,30,512)
+D(724,13644,38810,4,30,256)
+D(925,13646,38811,4,30,512)
+D(852,13648,38812,4,30,512)
+D(853,13653,38813,2,189939,n)
+D(854,13655,38814,2,189939,n)
+D(2463,13657,38815,4,30,65536)
+D(851,13659,38816,4,64,n)
+D(856,13661,38817,4,30,512)
+D(857,13663,38818,4,30,1048608)
+D(255,13687,38819,4,30,256)
+D(863,13689,38820,4,64,n)
+D(943,13693,38821,2,189939,n)
+D(1897,13695,38822,2,1378,n)
+D(865,13698,38823,4,31,1024)
+D(866,13700,38824,4,31,1048608)
+D(884,13746,38825,4,30,65536)
+D(903,13794,38826,4,30,65536)
+D(904,13815,38827,4,31,1024)
+D(852,13817,38828,4,64,n)
+D(905,13822,38829,4,30,512)
+D(852,13836,38830,4,30,256)
+D(906,13841,38831,4,31,1024)
+D(907,13846,38832,4,30,512)
+D(908,13858,38833,4,31,1048608)
+D(909,13868,38834,4,31,1024)
+D(849,13882,38835,4,30,65536)
+D(856,13887,38836,4,31,1024)
+D(911,13890,38837,4,30,256)
+D(803,13898,38838,2,189939,n)
+D(907,13905,38839,4,64,n)
+D(912,13915,38840,2,189939,n)
+D(913,13917,38841,4,31,1048608)
+D(923,13931,38842,4,30,512)
+D(926,13933,38843,4,64,n)
+D(904,13935,38844,4,30,256)
+D(963,13937,38845,2,1378,n)
+D(927,13939,38846,4,30,512)
+D(928,13941,38847,4,31,1048608)
+D(805,13943,38848,2,189939,n)
+D(929,13945,38849,4,30,512)
+D(930,13947,38850,4,31,1024)
+D(931,13948,38851,4,31,1024)
+D(1483,15340,11622,4,31,130)
+D(1503,15389,11642,4,31,130)
+D(1504,15391,11643,4,31,130)
+D(1505,15394,11644,4,31,130)
+D(1506,15397,11645,4,31,130)
+D(1507,15400,11646,4,31,130)
+D(1508,15402,11647,4,31,130)
+D(1509,15404,11648,4,31,130)
+D(1510,15406,11649,4,31,130)
+D(1704,16623,12645,4,96,n)
+D(1843,19057,15564,4,30,1050016)
+D(1883,20008,38852,4,30,512)
+D(1884,20009,38853,4,30,512)
+D(1885,20010,38854,4,30,512)
+D(1886,20011,38855,4,30,512)
+D(1887,20012,38856,4,31,1024)
+D(927,20013,38857,4,31,1024)
+D(1888,20014,38858,4,30,65536)
+D(1889,20015,38859,4,30,65536)
+D(1890,20016,38860,4,64,n)
+D(929,20017,38861,4,64,n)
+D(929,20020,38862,4,30,256)
+D(1887,20023,38863,4,30,256)
+D(851,20024,38864,4,30,256)
+D(1891,20025,38865,4,31,1048608)
+D(1892,20026,38866,4,31,1048608)
+D(1893,20028,38867,4,31,1048608)
+D(1894,20029,38868,2,189939,n)
+D(1896,20030,38869,2,1378,n)
+D(1897,20031,38870,2,189939,n)
+D(1898,20032,38871,2,189939,n)
+D(1899,20033,38872,2,189939,n)
+D(1900,20034,38873,2,189939,n)
+D(1903,20035,38874,2,1378,n)
+D(1904,20036,38875,2,1378,n)
+D(2443,21931,38876,2,196083,n)
+D(2483,22593,18169,4,30,8)
+D(2484,22594,18170,4,30,8)
+D(2487,22596,18173,4,30,8)
+D(2486,22597,18172,4,30,8)
+D(2485,22598,18171,4,30,8)
+D(2488,22599,18182,4,30,8)
+D(2503,22725,18251,4,30,1050016)
+D(2504,22749,38877,2,58867,n)
+D(2505,22750,38878,2,58867,n)
+D(2523,22779,18283,2,262156,n)
+D(2543,22840,18329,4,31,130)
+D(2544,22844,18330,4,31,130)
+D(2545,22846,18331,4,31,130)
+D(2563,23799,38879,2,58867,n)
+D(2564,23800,38880,2,58867,n)
+D(2565,23801,38881,4,30,512)
+D(2650,23802,38882,4,30,512)
+D(2567,23803,38883,2,58867,n)
+D(2568,23804,38884,2,58867,n)
+D(2583,24149,19782,4,31,130)
+D(2584,24160,19783,4,31,130)
+D(3755,24161,19784,4,31,130)
+D(3754,24162,19785,4,31,130)
+D(2587,24163,19786,4,31,130)
+D(2588,24164,19787,4,31,130)
+D(2589,24165,19788,4,31,130)
+D(2590,24167,19789,4,31,130)
+D(2591,24168,19790,4,31,130)
+D(846,24302,19971,2,1048576,n)
+D(2604,24420,20078,4,30,8)
+D(2605,24421,20076,4,30,8)
+D(2606,24422,20077,4,30,8)
+D(2613,25072,38885,4,31,1024)
+D(2614,25073,38886,4,31,1024)
+D(2615,25074,38887,4,31,1024)
+D(2616,25078,38888,4,31,1024)
+D(2617,25079,38889,4,31,1024)
+D(2564,25080,38890,4,31,1024)
+D(2619,25081,38891,4,31,65536)
+D(2620,25082,38892,4,31,65536)
+D(910,25083,38893,4,31,65536)
+D(2621,25084,38894,4,31,65536)
+D(2622,25086,38895,4,31,65536)
+D(2646,27837,38896,2,1378,n)
+D(2647,27899,35420,4,30,512)
+D(1891,27905,35426,4,30,512)
+D(2648,27906,35422,4,30,512)
+D(2650,27911,35427,4,30,512)
+D(2679,27913,35424,4,30,512)
+D(2649,27914,35421,4,30,512)
+D(2650,27917,35425,4,30,512)
+D(2929,27920,35447,4,n,2048)
+D(2928,27924,35445,4,n,2048)
+D(2930,27926,35444,4,n,2048)
+D(2931,27927,35446,4,n,2048)
+D(2653,27944,38904,4,64,n)
+D(2654,27945,35448,4,64,n)
+D(2655,27946,35451,4,64,n)
+D(1888,27947,35450,4,64,n)
+D(2656,27948,35419,4,30,256)
+D(2649,27950,35417,4,30,256)
+D(2657,27951,35400,4,30,256)
+D(2658,27954,35418,4,30,256)
+D(2659,27957,35428,4,31,1048608)
+D(3233,27958,38912,4,31,1048608)
+D(2661,27960,35429,4,31,1048608)
+D(2662,27961,35437,4,30,65536)
+D(2664,27962,35435,4,30,65536)
+D(1898,27964,38916,2,189939,n)
+D(963,27967,35457,2,189939,n)
+D(2666,27968,35455,2,58867,n)
+D(2667,27971,35397,2,132450,n)
+D(2668,27972,35459,2,189939,n)
+D(2669,27975,35456,2,173555,n)
+D(2670,27977,35396,2,132450,n)
+D(2671,27981,35462,2,189939,n)
+D(2672,27982,35460,2,189939,n)
+D(2673,27984,35458,2,189939,n)
+D(2674,28003,35461,2,189939,n)
+D(2675,28004,35452,2,189939,n)
+D(2681,28161,22635,4,31,130)
+D(2682,28163,22636,4,31,130)
+D(2683,28165,22638,4,31,130)
+D(2714,29454,23530,4,96,n)
+D(2721,29467,23545,4,30,8)
+D(2715,29475,23547,4,30,8)
+D(2716,29480,23549,4,30,8)
+D(2717,29483,23548,4,30,8)
+D(2722,30250,23764,2,262156,n)
+D(2723,30252,23765,2,262156,n)
+D(2523,30255,n,2,262156,n)
+D(2724,30258,n,2,262156,n)
+D(2724,30260,23766,2,262156,n)
+D(2745,31369,24275,4,31,128)
+D(2746,31370,24276,4,31,128)
+D(2747,31371,24273,4,31,128)
+D(2748,31372,24274,4,31,128)
+D(2792,32397,25650,4,30,1050016)
+D(2793,32398,25651,4,30,1050016)
+D(2794,32399,25652,4,30,1050016)
+D(1144,33990,35431,4,31,1048608)
+D(3150,33991,38929,4,31,1048608)
+D(2933,33992,35430,4,31,1048608)
+D(2934,33993,35439,4,31,1024)
+D(2935,33994,35443,4,31,1024)
+D(684,33995,35442,4,31,1024)
+D(1594,33996,35438,4,31,1024)
+D(2937,33997,35441,4,31,1024)
+D(2322,33999,35440,4,31,1024)
+D(369,34001,35423,4,30,512)
+D(1593,34002,38938,4,30,512)
+D(2938,34003,35436,4,30,65536)
+D(368,34004,35432,4,30,65536)
+D(1257,34005,35433,4,30,65536)
+D(1441,34006,35434,4,30,65536)
+D(2939,34007,35399,4,30,256)
+D(2940,34008,35398,4,30,256)
+D(1071,34009,35449,4,64,n)
+D(3846,34010,35454,2,189939,n)
+D(2977,35355,28882,4,31,8)
+D(2978,35402,28889,4,31,8)
+D(2979,35403,28878,4,31,8)
+D(2980,35404,28887,4,31,8)
+D(2981,35405,28881,4,31,8)
+D(2982,35406,28886,4,31,8)
+D(2983,35407,28885,4,31,8)
+D(2984,35415,29483,4,30,1050016)
+D(2985,35416,29485,4,30,1050016)
+D(2986,35417,28888,4,31,8)
+D(2987,35418,29486,4,30,1050016)
+D(2988,35419,29487,4,30,1050016)
+D(2989,35420,29488,4,30,1050016)
+D(2990,35432,28908,4,31,8)
+D(2991,35433,28911,4,31,8)
+D(2992,35434,28904,4,31,8)
+D(2993,35435,28912,4,31,8)
+D(2994,35436,28903,4,31,8)
+D(2995,35437,28909,4,31,8)
+D(2996,35438,28907,4,31,8)
+D(2997,35439,28910,4,31,8)
+D(2998,35441,29187,4,30,8)
+D(2999,35443,29186,4,31,2)
+D(3001,35445,29189,4,31,2)
+D(3002,35447,29191,4,31,2)
+D(3003,35452,29192,4,31,2)
+D(3004,35453,29193,4,31,2)
+D(3005,35454,29194,4,31,2)
+D(3006,35455,29195,4,31,2)
+D(3007,35456,29196,4,31,2)
+D(3008,35457,29198,4,31,2)
+D(3009,35458,29199,4,31,2)
+D(3010,35488,29533,4,31,128)
+D(3011,35489,29534,4,31,128)
+D(3012,35490,29535,4,31,128)
+D(3013,35495,29536,4,31,128)
+D(3095,37889,30845,4,31,2)
+D(3096,37891,30846,4,31,2)
+D(3222,42620,35453,2,189939,n)
+D(3223,42687,33185,2,173555,n)
+D(3225,42974,38948,2,189939,n)
+D(3228,44119,n,4,30,512)
+D(3229,44383,38949,4,64,n)
+D(3230,44483,38950,4,30,65536)
+D(3231,44484,38951,4,30,1024)
+D(3234,44488,38953,4,31,1024)
+D(1952,44489,38954,4,64,n)
+D(3236,44492,38955,4,30,1048608)
+D(1400,44494,38956,4,30,65536)
+D(983,44500,38959,4,30,65536)
+D(3238,44506,38960,4,30,1024)
+D(1147,44508,38961,4,30,256)
+D(2381,44509,38962,4,30,1048608)
+D(3844,44510,38963,2,177651,n)
+D(3829,44513,38964,4,30,1024)
+D(3239,44524,38965,2,177651,n)
+D(1075,44528,38966,4,30,256)
+D(3222,44529,38967,4,30,1024)
+D(1119,44555,38968,4,30,512)
+D(1354,44556,38969,4,30,65536)
+D(3845,44575,44815,4,30,512)
+D(3241,44576,38972,2,173555,n)
+D(3243,44582,38973,4,30,65536)
+D(3244,44584,38974,4,30,256)
+D(3245,44588,38975,4,30,1048608)
+D(983,44589,38976,4,30,256)
+D(1446,44590,38977,4,30,65536)
+D(1951,44591,38978,4,30,65536)
+D(3246,44592,38979,4,30,1024)
+D(1147,44593,38980,4,30,512)
+D(3247,44595,38981,2,132450,n)
+D(1262,44596,38982,4,30,65536)
+D(3231,44598,38984,4,30,512)
+D(3249,44612,38985,4,30,1024)
+D(2661,44616,38987,4,30,512)
+D(3251,44621,38988,2,173555,n)
+D(3252,44623,38989,4,30,1048608)
+D(3253,44625,38990,4,31,1024)
+D(3830,44629,38991,2,177651,n)
+D(3828,44630,38992,2,132450,n)
+D(3256,44631,38993,4,30,65536)
+D(1103,44633,38995,2,177651,n)
+D(2326,44635,38997,4,30,512)
+D(3840,44636,n,4,n,2048)
+D(3839,44645,n,4,n,2048)
+D(3260,44769,34207,4,30,1024)
+D(2841,44968,34330,4,30,1050026)
+D(3269,45697,34836,2,1048576,n)
+D(3273,46578,38998,2,189939,n)
+D(1951,46594,38999,4,31,1048608)
+D(2648,47051,39000,4,31,65536)
+D(3294,47672,39001,4,30,65536)
+D(1119,47715,n,4,30,512)
+D(1953,47766,39002,4,31,1048608)
+D(3831,47898,39003,4,30,65536)
+D(3296,47899,39004,4,30,65536)
+D(3297,47900,39005,4,30,1048608)
+D(3232,47901,39006,4,30,256)
+D(3297,48036,n,4,30,1048608)
+D(3319,50465,n,2,41105,n)
+D(3325,50901,38371,4,31,128)
+D(3326,50902,38372,4,31,128)
+D(3327,50903,n,4,31,128)
+D(3328,50904,n,4,31,128)
+D(3329,50906,38375,4,30,1050026)
+D(3330,50909,38376,4,30,1050026)
+D(3331,50911,38377,4,31,128)
+D(3332,50913,38378,4,31,128)
+D(3290,52639,39300,4,n,65536)
+D(3365,53323,n,2,1378,n)
+D(3366,53331,n,2,189939,n)
+D(3369,53341,n,2,189939,n)
+D(3367,53342,n,2,1378,n)
+D(3370,53343,n,2,189939,n)
+D(3368,53344,n,2,189939,n)
+D(3594,54446,n,2,32913,n)
+D(3595,54447,n,2,32913,n)
+D(3599,54736,40776,4,30,64)
+D(3601,54793,40800,4,30,64)
+D(3603,54998,41091,4,30,1024)
+D(3604,54999,n,4,30,1024)
+D(3605,55002,41111,4,30,65536)
+D(3606,55016,41118,4,30,256)
+D(3607,55076,41146,2,262156,n)
+D(3608,55135,41167,2,262156,n)
+D(3718,55630,41601,4,31,128)
+D(3719,55631,41602,4,31,128)
+D(3720,55632,41603,4,31,128)
+D(3721,55634,41604,4,31,128)
+D(3722,55642,n,4,30,65536)
+D(3728,55769,n,4,30,65536)
+D(3730,55777,n,4,30,65536)
+D(3731,55836,41976,2,173555,n)
+D(3873,56034,n,4,31,128)
+D(3872,56039,n,4,31,128)
+D(3748,56353,42500,4,96,n)
+D(3756,57683,43097,4,30,512)
+D(3757,57690,n,4,30,512)
+D(3758,57691,n,4,30,512)
+D(3759,57692,n,4,30,512)
+D(3760,57694,n,4,30,512)
+D(3761,57696,n,4,30,512)
+D(3762,57699,n,4,30,512)
+D(3763,57701,n,4,30,512)
+D(3775,58126,43302,4,31,8)
+D(3776,58128,43303,4,31,8)
+D(3777,58129,43304,4,31,8)
+D(3788,59619,44497,2,177651,n)
+D(3789,59621,44493,2,173555,n)
+D(3790,59625,43987,2,173555,n)
+D(3791,59636,n,4,n,2048)
+D(3793,59771,44067,4,31,8)
+D(3794,59773,44068,4,31,8)
+D(3795,59777,44069,4,31,2)
+D(3796,59778,n,4,31,2)
+D(3797,59784,44075,4,31,2)
+D(3806,59927,44129,4,31,8)
+D(3807,59928,44130,4,31,8)
+D(3875,59929,44131,4,31,8)
+D(3876,59932,44132,4,31,8)
+D(3808,59934,44133,4,31,8)
+D(3809,59936,44134,4,31,8)
+D(3810,59937,44135,4,31,8)
+D(3811,59941,44136,4,31,8)
+D(3812,59944,44137,4,31,2)
+D(3813,59945,44138,4,31,2)
+D(3814,59946,44139,4,31,2)
+D(3815,59947,44140,4,31,2)
+D(3816,59948,44141,4,31,2)
+D(3817,59954,44149,4,31,2)
+D(3818,59955,44150,4,31,2)
+D(3819,59960,44152,4,31,2)
+D(3820,59970,44159,4,31,2)
+D(3822,60581,38373,4,31,128)
+D(3823,60582,38374,4,31,128)
+D(3327,60583,n,4,30,128)
+D(3328,60584,n,4,30,128)
+D(3824,60606,44449,4,30,256)
+D(3825,60609,44456,4,30,65536)
+D(1600,60616,38971,4,30,512)
+D(1606,60621,44453,2,189939,n)
+D(3826,60623,38986,4,30,256)
+D(1128,60653,44455,4,64,n)
+D(1099,60663,44457,4,30,65536)
+D(1603,60668,44458,4,30,1024)
+D(3827,60691,44463,2,136546,n)
+D(3832,60692,44465,4,30,1048608)
+D(3833,60707,44466,2,189939,n)
+D(3834,60714,44467,2,177651,n)
+D(1597,60763,44469,4,30,256)
+D(2332,60767,44470,4,30,512)
+D(3835,61117,n,4,31,8)
+D(3836,61118,n,4,31,8)
+D(3837,61119,n,4,31,8)
+D(3838,61120,n,4,31,8)
+D(3842,61271,44701,4,31,2)
+D(3843,61468,44739,2,262156,n)
+D(3847,62158,n,2,1378,n)
+D(3849,62201,44936,4,64,n)
+D(3850,62256,44947,4,30,512)
+D(3851,62257,44946,2,189939,n)
+D(3852,62384,44957,4,31,8)
+D(3853,62447,44963,4,31,128)
+D(3854,62948,45056,2,1024,n)
+D(3855,62959,45060,2,1024,n)
+D(3858,63746,45628,4,30,256)
+D(3859,63765,n,4,30,65536)
+D(3860,63770,n,4,30,1024)
+D(3869,64441,46026,2,189939,n)
+D(3870,64579,46098,2,189939,n)
+D(3878,67839,n,4,n,2)
+D(3883,70164,n,2,32913,n)
+D(846,71692,50816,4,31,1024)
+D(1593,359639,187737,4,30,512)
+D(910,359640,187738,4,30,65536)
+D(2564,359641,187739,4,30,1024)
+D(2567,359642,187740,2,58867,n)
+D(3229,359685,187783,4,64,n)
+D(2621,359847,187800,4,30,65536)
+D(2613,359858,187801,4,31,1024)
+D(926,359895,187814,4,64,n)
+D(2620,359949,187807,4,30,65536)
+D(2619,359950,187815,4,30,65536)
diff --git a/Libs/LibClass-2.0 b/Libs/LibClass-2.0
index 9ec3b05..f81283c 160000
--- a/Libs/LibClass-2.0
+++ b/Libs/LibClass-2.0
@@ -1 +1 @@
-Subproject commit 9ec3b057ef3449ef6c8c21ab7f32c4566c91d0bf
+Subproject commit f81283c198706752b9eebda4f08bb5b2f7394ab5
diff --git a/Load.xml b/Load.xml
index ac3ea57..95d3dca 100644
--- a/Load.xml
+++ b/Load.xml
@@ -14,6 +14,7 @@
+
@@ -26,10 +27,9 @@
+
-
-
@@ -37,5 +37,10 @@
+
+
+
+
+
diff --git a/Localization/enUS.lua b/Localization/enUS.lua
index 398e9ab..f5c5bbd 100644
--- a/Localization/enUS.lua
+++ b/Localization/enUS.lua
@@ -13,6 +13,7 @@ L["Show Model"] = true
-- @import@
L['Show Model'] = true
L['Last update:'] = true
+L['Data source:'] = true
L['Inspect target'] = true
L['Inspect mouseover'] = true
-- @locale-fill@
diff --git a/Localization/zhCN.lua b/Localization/zhCN.lua
index ad668be..4697c1e 100644
--- a/Localization/zhCN.lua
+++ b/Localization/zhCN.lua
@@ -8,7 +8,7 @@ L['Show Model'] = '显示模型'
L['Last update:'] = '最后更新:'
L['Inspect target'] = '观察目标'
L['Inspect mouseover'] = '观察鼠标悬停目标'
-
+L['Data source:'] = '数据来源:'
-- @locale-fill@
-- @end-import@
diff --git a/Scripts/TalentsGen.ts b/Scripts/TalentsGen.ts
index d156321..9292691 100644
--- a/Scripts/TalentsGen.ts
+++ b/Scripts/TalentsGen.ts
@@ -88,9 +88,7 @@ class App {
col: Number.parseInt(x.ColumnIndex),
tabId: Number.parseInt(x.TabID),
spells: (x.SpellRank as string[]).map((x) => Number.parseInt(x)).filter((x) => x),
- reqs: x.PrereqTalent
- .map((x) => Number.parseInt(x))
- .filter((x) => x),
+ reqs: (x.PrereqTalent as string[]).map((x) => Number.parseInt(x)).filter((x) => x),
}));
}
diff --git a/Scripts/util.ts b/Scripts/util.ts
index ca45219..9b3211d 100644
--- a/Scripts/util.ts
+++ b/Scripts/util.ts
@@ -5,6 +5,7 @@
* @Date : 2022/9/26 18:55:36
*/
import { format } from 'https://deno.land/x/format/mod.ts';
+import { Semaphore } from "https://deno.land/x/async@v2.1.0/semaphore.ts";
export enum ProjectId {
Vanilla,
@@ -27,6 +28,11 @@ const PROJECTS = new Map([
[ProjectId.Cata, { product: 'wow_classic', version_pattern: /^4\..+/ }],
]);
+export function mapLimit(array: T[], limit: number, fn: (value: T, index: number, array: T[]) => U) {
+ const sem = new Semaphore(limit);
+ return array.map((...args) => sem.lock(() => fn(...args)));
+}
+
export class WowToolsClient {
private pro: ProjectData;
diff --git a/Tooltip/FixItemSet.lua b/Tooltip/FixItemSet.lua
index 2f75bc7..9243328 100644
--- a/Tooltip/FixItemSet.lua
+++ b/Tooltip/FixItemSet.lua
@@ -29,13 +29,14 @@ function ns.FixItemSets(tip, id)
return
end
- local equippedCount, itemNames, overrideNames = ns.Inspect:GetEquippedSetItems(setId)
+ local equippedCount, equippedSetItems = ns.Inspect:GetEquippedSetItems(setId)
local setNameLinePattern = '^(' .. setName .. '.+)(%d+)/(%d+)(.+)$'
local setLine
local firstBonusLine
- local inSetLine = true
local bonus = ns.ItemSets[setId].bouns
+ local slots = ns.ItemSets[setId].slots
+ local setLineFinished = false
for i = 2, tip:NumLines() do
local textLeft = tip:GetFontStringLeft(i)
@@ -47,26 +48,31 @@ function ns.FixItemSets(tip, id)
setLine = i
textLeft:SetText(prefix .. equippedCount .. '/' .. maxCount .. suffix)
end
- elseif inSetLine then
+ elseif setLine and not setLineFinished then
local line = text:trim()
+ local setSlotIndex = i - setLine
+ local slotItem = slots[setSlotIndex]
- if line == '' then
- inSetLine = false
+ if not slotItem or line == '' then
+ setLineFinished = true
else
- local n = itemNames[line]
- if n and n > 0 then
- local overrideName = overrideNames[line]
- if overrideName and line ~= overrideName then
- textLeft:SetText(text:sub(1, #text - #line) .. overrideName)
- end
+ local item = equippedSetItems[slotItem.slot]
+ local hasItem = item
+ if not item then
+ item = slotItem.itemId
+ end
- textLeft:SetTextColor(1, 1, 0.6)
- itemNames[line] = n > 1 and n - 1 or nil
- else
- textLeft:SetTextColor(0.5, 0.5, 0.5)
+ local name = GetItemInfo(item)
+ if name then
+ textLeft:SetText(' ' .. name)
+ if hasItem then
+ textLeft:SetTextColor(1, 1, 0.6)
+ else
+ textLeft:SetTextColor(0.5, 0.5, 0.5)
+ end
end
end
- else
+ elseif setLineFinished then
local summary, count = MatchBonus(text)
if summary then
if not firstBonusLine then
diff --git a/UI/ElvUI.lua b/UI/ElvUI.lua
index 5157ee1..12ff708 100644
--- a/UI/ElvUI.lua
+++ b/UI/ElvUI.lua
@@ -25,7 +25,6 @@ hooksecurefunc(ns.Addon, 'SetupUI', function(self)
self.InspectFrame.TalentFrame.TalentFrame:StripTextures()
self.InspectFrame.TalentFrame.TalentFrame:CreateBackdrop('Default')
- self.InspectFrame.PaperDoll.EquipFrame:CreateBackdrop('Default')
self.InspectFrame.PaperDoll.ModelFrame:CreateBackdrop('Default')
for i, tab in ipairs(self.InspectFrame.TalentFrame.Tabs) do
diff --git a/UI/EnchantItem.lua b/UI/EnchantItem.lua
new file mode 100644
index 0000000..a67d974
--- /dev/null
+++ b/UI/EnchantItem.lua
@@ -0,0 +1,64 @@
+-- EnchantItem.lua
+-- @Author : Dencer (tdaddon@163.com)
+-- @Link : https://dengsir.github.io
+-- @Date : 8/23/2024, 12:00:23 PM
+--
+---@type ns
+local ns = select(2, ...)
+
+---@class UI.EnchantItem : UI.SocketItem
+local EnchantItem = ns.Addon:NewClass('UI.EnchantItem', ns.UI.SocketItem)
+
+function EnchantItem:Constructor()
+ self:SetScript('OnEnter', self.OnEnter)
+ self:SetScript('OnLeave', GameTooltip_Hide)
+ self:SetScript('OnHide', self.Free)
+end
+
+function EnchantItem:OnFree()
+ self.item = nil
+ self.spell = nil
+end
+
+function EnchantItem:Alloc(parent)
+ local obj = tremove(self.pool)
+ if not obj then
+ obj = self:New(parent)
+ else
+ obj:SetParent(parent)
+ end
+ obj:Show()
+ return obj
+end
+
+function EnchantItem:OnEnter()
+ if self.item then
+ GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
+ GameTooltip:SetItemByID(self.item)
+ GameTooltip:Show()
+ elseif self.spell then
+ GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
+ GameTooltip:SetSpellByID(self.spell)
+ GameTooltip:Show()
+ end
+end
+
+function EnchantItem:SetItem(item)
+ self.item = item
+ self.spell = nil
+ self:Update()
+end
+
+function EnchantItem:SetSpell(spell)
+ self.spell = spell
+ self.item = nil
+ self:Update()
+end
+
+function EnchantItem:Update()
+ if self.item then
+ self.Icon:SetTexture(GetItemIcon(self.item))
+ elseif self.spell then
+ self.Icon:SetTexture(select(3, GetSpellInfo(self.spell)))
+ end
+end
diff --git a/UI/EquipItem.lua b/UI/EquipItem.lua
index 91cbd4f..56748fb 100644
--- a/UI/EquipItem.lua
+++ b/UI/EquipItem.lua
@@ -41,12 +41,11 @@ function EquipItem:Constructor(_, id, slotName, hasBg)
Name:SetPoint('RIGHT')
self.Name = Name
- -- @build<2@
- local RuneIcon = self:CreateTexture(nil, 'OVERLAY')
- RuneIcon:SetSize(17, 17)
- RuneIcon:SetPoint('RIGHT')
- self.RuneIcon = RuneIcon
- -- @end-build<2@
+ local Enchant = CreateFrame('Frame', nil, self)
+ Enchant:SetPoint('TOPRIGHT')
+ Enchant:SetHeight(17)
+ Enchant:SetWidth(17)
+ self.Enchant = Enchant
local ht = self:CreateTexture(nil, 'HIGHLIGHT')
ht:SetAllPoints(true)
@@ -61,51 +60,114 @@ function EquipItem:Constructor(_, id, slotName, hasBg)
self:SetScript('OnLeave', GameTooltip_Hide)
self:SetScript('OnEnter', self.OnEnter)
self.UpdateTooltip = self.OnEnter
+
+ self.enchantCount = 0
+ self.enchants = {}
+end
+
+function EquipItem:AllocEnchant()
+ self.enchantCount = self.enchantCount + 1
+
+ for _, v in ipairs(self.enchants) do
+ if not v:IsVisible() then
+ v:Show()
+ return v
+ end
+ end
+
+ local Enchant = self.Enchant:CreateTexture(nil, 'ARTWORK')
+ Enchant:SetSize(17, 17)
+ if #self.enchants == 0 then
+ Enchant:SetPoint('TOPRIGHT')
+ else
+ Enchant:SetPoint('TOPRIGHT', self.enchants[#self.enchants], 'TOPLEFT', 0, 0)
+ end
+
+ tinsert(self.enchants, Enchant)
+ return Enchant
+end
+
+function EquipItem:FreeAllEnchants()
+ self.enchantCount = 0
+ for _, tex in ipairs(self.enchants) do
+ tex.itemId = nil
+ tex.spellId = nil
+ tex:Hide()
+ end
end
function EquipItem:OnHide()
self:UnregisterAllEvents()
+ self:FreeAllEnchants()
end
function EquipItem:OnEnter()
local item = Inspect:GetItemLink(self:GetID())
if item then
- -- @build<2@
- if self.RuneIcon:IsVisible() and self.RuneIcon:IsMouseOver() then
- local rune = Inspect:GetItemRune(self:GetID())
- if rune then
+
+ for _, tex in ipairs(self.enchants) do
+ if tex:IsVisible() and tex:IsMouseOver() then
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
- GameTooltip:SetSpellByID(rune.spellId)
+ if tex.spellId then
+ GameTooltip:SetSpellByID(tex.spellId)
+ else
+ GameTooltip:SetItemByID(tex.itemId)
+ end
+ return
end
- else
- -- @end-build<2@
- GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
- GameTooltip:SetHyperlink(item)
- ns.FixInspectItemTooltip(GameTooltip, self:GetID(), item)
- -- @build<2@
end
- -- @end-build<2@
+
+ GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
+ GameTooltip:SetHyperlink(item)
+ ns.FixInspectItemTooltip(GameTooltip, self:GetID(), item)
end
end
function EquipItem:Update()
- self.itemId = nil
+ self:FreeAllEnchants()
- local id = self:GetID()
+ self.Name:SetText('')
+ self.ItemLevel:SetText('')
+ self.Slot:SetTextColor(0.6, 0.6, 0.6)
- -- @build<2@
- local rune = Inspect:GetItemRune(id)
- if rune then
- local icon = rune.icon or select(3, GetSpellInfo(rune.spellId))
- self.RuneIcon:SetTexture(icon)
- self.RuneIcon:Show()
- else
- self.RuneIcon:Hide()
- end
- -- @end-build<2@
+ local id = self:GetID()
local item = Inspect:GetItemLink(id)
if item then
+ -- @build<2@
+ local rune = Inspect:GetItemRune(id)
+ if rune then
+ local icon = rune.icon or select(3, GetSpellInfo(rune.spellId))
+ local tex = self:AllocEnchant()
+ tex.spellId = rune.spellId
+ tex:SetTexture(icon)
+ end
+ -- @end-build<2@
+
+ local enchantInfo = ns.GetItemEnchantInfo(item)
+ if enchantInfo then
+ local tex = self:AllocEnchant()
+ if enchantInfo.itemId then
+ tex.itemId = enchantInfo.itemId
+ tex:SetTexture(GetItemIcon(enchantInfo.itemId))
+ elseif enchantInfo.spellId then
+ tex.spellId = enchantInfo.spellId
+ tex:SetTexture(select(3, GetSpellInfo(enchantInfo.spellId)))
+ end
+ end
+
+ for i = 1, 3 do
+ local _, gemLink = GetItemGem(item, i)
+ if gemLink then
+ local tex = self:AllocEnchant()
+ tex.itemId = ns.ItemLinkToId(gemLink)
+ tex:SetTexture(GetItemIcon(gemLink))
+ end
+ end
+
+ self.Enchant:SetWidth(max(0.1, 17 * self.enchantCount))
+ self.Name:SetPoint('RIGHT', self.Enchant, 'LEFT', -2, 0)
+
local name, link, quality, itemLevel = GetItemInfo(item)
if name then
local r, g, b = GetItemQualityColor(quality)
@@ -118,10 +180,7 @@ function EquipItem:Update()
return
else
self:WaitItem(item)
+ return
end
end
-
- self.Name:SetText('')
- self.ItemLevel:SetText('')
- self.Slot:SetTextColor(0.6, 0.6, 0.6)
end
diff --git a/UI/GearFrame.lua b/UI/GearFrame.lua
new file mode 100644
index 0000000..71af5af
--- /dev/null
+++ b/UI/GearFrame.lua
@@ -0,0 +1,115 @@
+-- GearFrame.lua
+-- @Author : Dencer (tdaddon@163.com)
+-- @Link : https://dengsir.github.io
+-- @Date : 8/23/2024, 11:22:53 AM
+--
+---@class ns
+local ns = select(2, ...)
+
+local EQUIP_SLOTS = {
+ {id = 1, name = HEADSLOT}, --
+ {id = 2, name = NECKSLOT}, --
+ {id = 3, name = SHOULDERSLOT}, --
+ {id = 15, name = BACKSLOT}, --
+ {id = 5, name = CHESTSLOT}, --
+ {id = 9, name = WRISTSLOT}, --
+ {id = 10, name = HANDSSLOT}, --
+ {id = 6, name = WAISTSLOT}, --
+ {id = 7, name = LEGSSLOT}, --
+ {id = 8, name = FEETSLOT}, --
+ {id = 11, name = FINGER0SLOT}, --
+ {id = 12, name = FINGER1SLOT}, --
+ {id = 13, name = TRINKET0SLOT}, --
+ {id = 14, name = TRINKET1SLOT}, --
+ {id = 16, name = MAINHANDSLOT}, --
+ {id = 17, name = SECONDARYHANDSLOT}, --
+ {id = 18, name = RANGEDSLOT}, --
+}
+
+local SPACING_V = 3
+local SPACING_H = 5
+local PADDING = 10
+
+---@class UI.GearFrame : Frame, BackdropTemplate, AceEvent-3.0
+local GearFrame = ns.Addon:NewClass('UI.GearFrame', 'Frame')
+
+function GearFrame:Create(parent)
+ return self:Bind(CreateFrame('Frame', nil, parent, 'BackdropTemplate'))
+end
+
+function GearFrame:Constructor()
+ self:SetHeight(424)
+ self:SetBackdrop{
+ bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
+ edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
+ tile = true,
+ tileSize = 8,
+ edgeSize = 16,
+ insets = {left = 4, right = 4, top = 4, bottom = 4},
+ }
+ self:SetBackdropColor(0, 0, 0, 0.95)
+
+ local SlotColumn = CreateFrame('Frame', nil, self)
+ SlotColumn:SetPoint('TOPLEFT', PADDING, 0)
+ SlotColumn:SetHeight(1)
+ self.SlotColumn = SlotColumn
+
+ local LevelColumn = CreateFrame('Frame', nil, self)
+ LevelColumn:SetPoint('TOPLEFT', SlotColumn, 'TOPRIGHT', SPACING_H, 0)
+ LevelColumn:SetHeight(1)
+ self.LevelColumn = LevelColumn
+
+ local Title = self:CreateFontString(nil, 'ARTWORK', 'GameFontNormalLargeOutline')
+ Title:SetPoint('TOPLEFT', 66, -18)
+ self.Title = Title
+
+ local ItemLevel = self:CreateFontString(nil, 'ARTWORK', 'ChatFontNormal')
+ ItemLevel:SetPoint('TOPLEFT', 66, -42)
+ ItemLevel:SetFont(ItemLevel:GetFont(), 12, 'THINOUTLINE')
+ ItemLevel:SetTextColor(NORMAL_FONT_COLOR:GetRGB())
+ self.ItemLevel = ItemLevel
+
+ self.gears = {}
+ self.columnWidths = {}
+
+ for i, v in ipairs(EQUIP_SLOTS) do
+ local item = ns.UI.GearItem:New(self, v.id, v.name)
+ local y = -(i - 1) * (item:GetHeight() + SPACING_V) - 80
+ item:SetPoint('TOPLEFT', PADDING, y)
+ self.gears[v.id] = item
+ end
+end
+
+function GearFrame:ApplyColumnWidth(key, width)
+ self.columnWidths[key] = max(self.columnWidths[key] or 0, width)
+ self:RequestUpdateSize()
+end
+
+function GearFrame:RequestUpdateSize()
+ self:SetScript('OnUpdate', self.OnUpdate)
+end
+
+function GearFrame:OnUpdate()
+ self:SetScript('OnUpdate', nil)
+ self:UpdateSize()
+end
+
+function GearFrame:UpdateSize()
+ local width = 0
+ for key, v in pairs(self.columnWidths) do
+ width = width + v + SPACING_H
+
+ if self[key] then
+ self[key]:SetWidth(v)
+ end
+ end
+ self:SetWidth(width - SPACING_V + PADDING * 2)
+end
+
+function GearFrame:StartLayout()
+ wipe(self.columnWidths)
+end
+
+function GearFrame:EndLayout()
+ self:RequestUpdateSize()
+end
diff --git a/UI/GearItem.lua b/UI/GearItem.lua
new file mode 100644
index 0000000..c31577e
--- /dev/null
+++ b/UI/GearItem.lua
@@ -0,0 +1,159 @@
+-- GearItem.lua
+-- @Author : Dencer (tdaddon@163.com)
+-- @Link : https://dengsir.github.io
+-- @Date : 8/23/2024, 11:14:48 AM
+--
+---@type ns
+local ns = select(2, ...)
+
+---@class UI.GearItem : UI.BaseItem
+local GearItem = ns.Addon:NewClass('UI.GearItem', ns.UI.BaseItem)
+
+local SPACING = 3
+
+---@param parent UI.GearFrame
+---@param id number
+---@param slotName string
+function GearItem:Constructor(parent, id, slotName)
+ self.parent = parent
+ self:SetID(id)
+ self:SetSize(1, 17)
+
+ ---@type Frame|BackdropTemplate
+ local Slot = CreateFrame('Frame', nil, self, 'BackdropTemplate')
+ Slot:SetPoint('TOPLEFT')
+ Slot:SetPoint('BOTTOMLEFT')
+ Slot:SetPoint('RIGHT', parent.SlotColumn, 'RIGHT')
+ Slot:SetBackdrop{
+ bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
+ edgeFile = [[Interface\Buttons\WHITE8X8]],
+ tile = true,
+ tileSize = 8,
+ edgeSize = 1,
+ insets = {left = 1, right = 1, top = 1, bottom = 1},
+ }
+ Slot:SetBackdropBorderColor(0, 0.9, 0.9, 0.2)
+ Slot:SetBackdropColor(0, 0.9, 0.9, 0.2)
+
+ local SlotText = Slot:CreateFontString(nil, 'ARTWORK')
+ SlotText:SetPoint('CENTER')
+ SlotText:SetFont(GameFontNormal:GetFont(), 11, 'OUTLINE')
+ SlotText:SetText(slotName)
+
+ local ItemLevel = self:CreateFontString(nil, 'ARTWORK', 'GameFontHighlight')
+ ItemLevel:SetFont(TextStatusBarText:GetFont(), 13)
+ ItemLevel:SetPoint('TOPLEFT', Slot, 'TOPRIGHT', 3, 0)
+ ItemLevel:SetPoint('BOTTOMLEFT', Slot, 'BOTTOMRIGHT', 3, 0)
+ ItemLevel:SetPoint('RIGHT', parent.LevelColumn, 'RIGHT')
+
+ local Name = self:CreateFontString(nil, 'ARTWORK', 'GameFontNormal')
+ Name:SetFont(ChatFontNormal:GetFont(), 13)
+ Name:SetPoint('TOPLEFT', ItemLevel, 'TOPRIGHT', 3, 0)
+ Name:SetPoint('BOTTOMLEFT', ItemLevel, 'BOTTOMRIGHT', 3, 0)
+ Name:SetJustifyH('LEFT')
+
+ self.Slot = Slot
+ self.SlotText = SlotText
+ self.ItemLevel = ItemLevel
+ self.Name = Name
+
+ self:SetScript('OnEnter', self.OnEnter)
+ self:SetScript('OnLeave', self.OnLeave)
+ self:SetScript('OnHide', self.OnHide)
+end
+
+function GearItem:SetItem(item, inspect)
+ self.inspect = inspect
+ self.item = item
+ self:Hide()
+ self:Update()
+ self:Show()
+end
+
+function GearItem:OnEnter()
+ local r, g, b = self.Slot:GetBackdropColor()
+ self.Slot:SetBackdropColor(r, g, b, 0.7)
+
+ if self.item then
+ GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
+ GameTooltip:SetHyperlink(self.item)
+ if self.inspect then
+ ns.FixInspectItemTooltip(GameTooltip, self:GetID(), self.item)
+ end
+ GameTooltip:Show()
+ end
+end
+
+function GearItem:OnLeave()
+ local r, g, b = self.Slot:GetBackdropColor()
+ self.Slot:SetBackdropColor(r, g, b, 0.2)
+ GameTooltip:Hide()
+end
+
+function GearItem:OnHide()
+end
+
+function GearItem:Update()
+ self.Name:SetText('')
+ self.ItemLevel:SetText('')
+ self.SlotText:SetTextColor(0.6, 0.6, 0.6)
+ self.Slot:SetBackdropBorderColor(0.6, 0.6, 0.6, 0.2)
+ self.Slot:SetBackdropColor(0.6, 0.6, 0.6, 0.2)
+
+ if not self.item then
+ return
+ end
+
+ local socketWidth = SPACING
+
+ local name, link, quality, itemLevel = GetItemInfo(self.item)
+ if name then
+ local enchant = ns.GetItemEnchantInfo(self.item)
+ if enchant then
+ local tex = ns.UI.EnchantItem:Alloc(self)
+ if enchant.itemId then
+ tex:SetItem(enchant.itemId)
+ elseif enchant.spellId then
+ tex:SetSpell(enchant.spellId)
+ end
+ tex:SetPoint('LEFT', self.Name, 'RIGHT', socketWidth, 0)
+
+ socketWidth = socketWidth + tex:GetWidth()
+ end
+
+ for i = 1, 3 do
+ local _, gemLink = GetItemGem(self.item, i)
+ if gemLink then
+
+ socketWidth = socketWidth + SPACING
+
+ local tex = ns.UI.GemItem:Alloc(self)
+ tex:SetItem(gemLink)
+ tex:SetPoint('LEFT', self.Name, 'RIGHT', socketWidth, 0)
+
+ socketWidth = socketWidth + tex:GetWidth()
+ end
+ end
+
+ local r, g, b = GetItemQualityColor(quality)
+
+ self.Name:SetText(link)
+ self.SlotText:SetTextColor(r, g, b)
+ self.Slot:SetBackdropBorderColor(r, g, b, 0.2)
+ self.Slot:SetBackdropColor(r, g, b, 0.2)
+ self.ItemLevel:SetText(itemLevel)
+ else
+ self:WaitItem(self.item)
+
+ end
+
+ local slotWidth = self.SlotText:GetStringWidth() + 10
+ local levelWidth = self.ItemLevel:GetStringWidth()
+ local nameWidth = self.Name:GetStringWidth()
+
+ self.parent:ApplyColumnWidth('SlotColumn', slotWidth)
+ self.parent:ApplyColumnWidth('LevelColumn', levelWidth)
+ self.parent:ApplyColumnWidth('Name', nameWidth + socketWidth)
+
+ self:SetPoint('RIGHT', self.parent.LevelColumn, 'RIGHT', nameWidth + 5, 0)
+end
diff --git a/UI/GemItem.lua b/UI/GemItem.lua
new file mode 100644
index 0000000..87ced56
--- /dev/null
+++ b/UI/GemItem.lua
@@ -0,0 +1,44 @@
+-- GemItem.lua
+-- @Author : Dencer (tdaddon@163.com)
+-- @Link : https://dengsir.github.io
+-- @Date : 8/23/2024, 11:48:29 AM
+--
+---@type ns
+local ns = select(2, ...)
+
+---@class UI.GemItem : UI.SocketItem
+local GemItem = ns.Addon:NewClass('UI.GemItem', ns.UI.SocketItem)
+
+function GemItem:Constructor()
+ self:SetScript('OnEnter', self.OnEnter)
+ self:SetScript('OnLeave', GameTooltip_Hide)
+ self:SetScript('OnHide', self.Free)
+end
+
+function GemItem:OnEnter()
+ if self.item then
+ GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
+ GameTooltip:SetHyperlink(self.item)
+ GameTooltip:Show()
+ end
+end
+
+function GemItem:SetItem(item)
+ self.item = item
+ self.Icon:SetTexture(GetItemIcon(item))
+end
+
+function GemItem:OnFree()
+ self.item = nil
+end
+
+function GemItem:Alloc(parent)
+ local obj = tremove(self.pool)
+ if not obj then
+ obj = self:New(parent)
+ else
+ obj:SetParent(parent)
+ end
+ obj:Show()
+ return obj
+end
diff --git a/UI/InspectGearFrame.lua b/UI/InspectGearFrame.lua
new file mode 100644
index 0000000..494be50
--- /dev/null
+++ b/UI/InspectGearFrame.lua
@@ -0,0 +1,56 @@
+-- InspectGearFrame.lua
+-- @Author : Dencer (tdaddon@163.com)
+-- @Link : https://dengsir.github.io
+-- @Date : 8/23/2024, 12:33:12 PM
+--
+---@type ns
+local ns = select(2, ...)
+
+local L = ns.L
+local Inspect = ns.Inspect
+
+---@class UI.InspectGearFrame : UI.GearFrame
+local InspectGearFrame = ns.Addon:NewClass('UI.InspectGearFrame', ns.UI.GearFrame)
+
+function InspectGearFrame:Constructor()
+ self:SetScript('OnShow', self.OnShow)
+ self:SetScript('OnHide', self.UnregisterAllMessages)
+
+ -- @debug@
+ local DataSource = self:CreateFontString(nil, 'ARTWORK', 'GameFontNormalSmall')
+ DataSource:SetPoint('BOTTOMLEFT', self, 'TOPLEFT', 10, 0)
+ DataSource:SetFont(DataSource:GetFont(), 12, 'OUTLINE')
+ self.DataSource = DataSource
+ -- @end-debug@
+end
+
+function InspectGearFrame:OnShow()
+ self:RegisterMessage('INSPECT_READY', 'Update')
+ self:Update()
+end
+
+function InspectGearFrame:Update()
+ self:StartLayout()
+
+ for id, gear in pairs(self.gears) do
+ gear:SetItem(Inspect:GetItemLink(id), true)
+ end
+
+ local classFileName = Inspect:GetUnitClassFileName()
+ local classColor = RAID_CLASS_COLORS[classFileName]
+
+ self.ItemLevel:SetFormattedText('%s %.1f', L['iLvl:'], Inspect:GetItemLevel() or 0)
+ self.Title:SetTextColor(classColor.r, classColor.g, classColor.b)
+ self.Title:SetText(Ambiguate(Inspect:GetUnitName(), 'none'))
+
+ self:SetBackdropBorderColor(classColor.r, classColor.g, classColor.b)
+
+ -- @debug@
+ local dataSource = Inspect:GetDataSource()
+ local lastUpdate = Inspect:GetLastUpdate()
+ self.DataSource:SetFormattedText('%s|cffffffff%s|r %s|cffffffff%s|r', L['Data source:'], dataSource,
+ L['Last update:'], FriendsFrame_GetLastOnline(lastUpdate))
+ -- @end-debug@
+
+ self:EndLayout()
+end
diff --git a/UI/ModelFrame.lua b/UI/ModelFrame.lua
index 800b282..49bf854 100644
--- a/UI/ModelFrame.lua
+++ b/UI/ModelFrame.lua
@@ -11,9 +11,9 @@ local UnitFactionGroup = UnitFactionGroup
local Inspect = ns.Inspect
local factionLogoTextures = {
- ['Alliance'] = 'Interface\\Timer\\Alliance-Logo',
- ['Horde'] = 'Interface\\Timer\\Horde-Logo',
- ['Neutral'] = 'Interface\\Timer\\Panda-Logo',
+ Alliance = [[Interface\Timer\Alliance-Logo]],
+ Horde = [[Interface\Timer\Horde-Logo]],
+ Neutral = [[Interface\Timer\Panda-Logo]],
}
---@class UI.ModelFrame: Object, Frame, AceEvent-3.0
@@ -28,7 +28,6 @@ function ModelFrame:Constructor()
self.Modal:SetParent(self)
self.Faction:SetParent(self)
- self:Hide()
self:SetScript('OnShow', self.OnShow)
end
diff --git a/UI/PaperDoll.lua b/UI/PaperDoll.lua
index 6d18aa3..0d3da49 100644
--- a/UI/PaperDoll.lua
+++ b/UI/PaperDoll.lua
@@ -60,28 +60,6 @@ function PaperDoll:Constructor()
t5:SetPoint('TOPLEFT', t4, 'TOPRIGHT')
end
- ---@type CheckButton
- local ToggleButton = CreateFrame('CheckButton', nil, self)
- do
- ToggleButton:SetSize(20, 20)
- ToggleButton:SetPoint('BOTTOMLEFT', 23, 85)
- ToggleButton:SetNormalTexture([[Interface\Buttons\UI-CheckBox-Up]])
- ToggleButton:SetPushedTexture([[Interface\Buttons\UI-CheckBox-Down]])
- ToggleButton:SetCheckedTexture([[Interface\Buttons\UI-CheckBox-Check]])
- ToggleButton:SetHighlightTexture([[Interface\Buttons\UI-CheckBox-Highlight]], 'ADD')
- ToggleButton:SetFontString(ToggleButton:CreateFontString(nil, 'ARTWORK', 'GameFontNormalSmall'))
- ToggleButton:GetFontString():SetPoint('LEFT', ToggleButton, 'RIGHT', 0, 0)
- ToggleButton:SetNormalFontObject('GameFontNormalSmall')
- ToggleButton:SetHighlightFontObject('GameFontHighlightSmall')
- ToggleButton:SetText(L['Show Model'])
-
- ToggleButton:SetScript('OnClick', function(ToggleButton)
- ns.Addon.db.profile.showModel = not not ToggleButton:GetChecked()
-
- self:UpdateInset()
- end)
- end
-
---@type Texture
local RaceBackground = self:CreateTexture(nil, 'ARTWORK')
do
@@ -97,10 +75,11 @@ function PaperDoll:Constructor()
self.RaceBackground = RaceBackground
self.LastUpdate = LastUpdate
- self.ToggleButton = ToggleButton
self.LevelText = InspectLevelText
self.ModelFrame = ns.UI.ModelFrame:Bind(self:CreateInsetFrame())
- self.EquipFrame = ns.UI.EquipFrame:Bind(self:CreateInsetFrame())
+
+ self.GearFrame = ns.UI.InspectGearFrame:Create(self)
+ self.GearFrame:SetPoint('TOPLEFT', self, 'TOPRIGHT', -33, -12)
self:SetScript('OnShow', self.OnShow)
self:SetScript('OnHide', self.OnHide)
@@ -109,8 +88,6 @@ end
function PaperDoll:OnShow()
self:RegisterMessage('INSPECT_READY')
self:RegisterEvent('UNIT_LEVEL', 'UpdateInfo')
- self:UpdateControls()
- self:UpdateInset()
self:UpdateInfo()
self:Update()
end
@@ -132,10 +109,6 @@ function PaperDoll:CreateInsetFrame()
return frame
end
-function PaperDoll:UpdateControls()
- self.ToggleButton:SetChecked(ns.Addon.db.profile.showModel)
-end
-
function PaperDoll:Update()
for _, button in pairs(self.buttons) do
button:Update()
@@ -169,9 +142,3 @@ function PaperDoll:UpdateInfo()
self.LastUpdate:SetText('')
end
end
-
-function PaperDoll:UpdateInset()
- local checked = ns.Addon.db.profile.showModel
- self.ModelFrame:SetShown(checked)
- self.EquipFrame:SetShown(not checked)
-end
diff --git a/UI/SocketItem.lua b/UI/SocketItem.lua
new file mode 100644
index 0000000..a6271a3
--- /dev/null
+++ b/UI/SocketItem.lua
@@ -0,0 +1,57 @@
+-- SocketItem.lua
+-- @Author : Dencer (tdaddon@163.com)
+-- @Link : https://dengsir.github.io
+-- @Date : 8/23/2024, 5:40:57 PM
+--
+---@type ns
+local ns = select(2, ...)
+
+---@class UI.SocketItem : Button, AceEvent-3.0
+local SocketItem = ns.Addon:NewClass('UI.SocketItem', 'Button')
+
+SocketItem.pool = {}
+
+local SIZE = 16
+local ICON_SIZE = SIZE / 24 * 22
+local BORDER_SIZE = SIZE / 24 * 33
+
+function SocketItem:Inherit()
+ self.pool = {}
+end
+
+function SocketItem:Constructor()
+ self:SetSize(SIZE, SIZE)
+
+ local Icon = self:CreateTexture(nil, 'ARTWORK')
+ Icon:SetPoint('CENTER')
+ Icon:SetSize(ICON_SIZE, ICON_SIZE)
+ self.Icon = Icon
+
+ local Border = self:CreateTexture(nil, 'OVERLAY')
+ Border:SetPoint('CENTER')
+ Border:SetAtlas('worldquest-tracker-ring')
+ Border:SetSize(BORDER_SIZE, BORDER_SIZE)
+ self.Border = Border
+
+ local Mask = self:CreateMaskTexture()
+ Mask:SetAllPoints(Icon)
+ Mask:SetTexture([[Interface\CharacterFrame\TempPortraitAlphaMask]])
+ Icon:AddMaskTexture(Mask)
+end
+
+function SocketItem:Free()
+ self:Hide()
+ self:OnFree()
+ tinsert(self.pool, self)
+end
+
+function SocketItem:Alloc(parent)
+ local obj = tremove(self.pool)
+ if not obj then
+ obj = self:New(parent)
+ else
+ obj:SetParent(parent)
+ end
+ obj:Show()
+ return obj
+end
diff --git a/UI/TalentFrame.lua b/UI/TalentFrame.lua
index 584b15d..18178da 100644
--- a/UI/TalentFrame.lua
+++ b/UI/TalentFrame.lua
@@ -289,10 +289,10 @@ function TalentFrame:Update()
local isUnlocked = true
local name, background, pointsSpent = self.talent:GetTabInfo(self.tabIndex)
if name then
- base = 'Interface\\TalentFrame\\' .. background .. '-'
+ base = [[Interface\TalentFrame\]] .. background .. '-'
else
-- temporary default for classes without talents poor guys
- base = 'Interface\\TalentFrame\\MageFire-'
+ base = [[Interface\TalentFrame\MageFire-]]
end
self.TopLeft:SetTexture(base .. 'TopLeft')
diff --git a/UI/Template.xml b/UI/Template.xml
new file mode 100644
index 0000000..e69de29