WOW_Collection_System/ItemCollection/SM_ItemCollectionUI.lua
尚美 7d57073759 优化“物品收藏”中(头部)等部位对于已获得和未获得的状态,
已获得的以绿色边框、绿色高光、绿色选中颜色显示
未获得的以红色边框、红色高光、红色选中颜色显示
2025-06-16 02:37:01 +08:00

1166 lines
49 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- ItemCollection/SM_ItemCollectionUI.lua
-- 物品收藏界面实现
SM_CollectionsDB = SM_CollectionsDB or {}
SM_CollectionData.Config = {
CameraOption = "Classic" -- 默认使用Classic视角
}
SM_ItemCollectionUI = {}
SM_ItemCollectionUI.buttons = {} -- 存储所有创建的按钮引用
SM_ItemCollectionUI.currentSelectedModel = nil -- 跟踪当前选中的模型
SM_ItemCollectionUI.currentPanel = nil -- 存储当前面板引用
SM_ItemCollectionUI.slotData = {} -- 存储物品槽位数据
SM_ItemCollectionUI.initialized = false -- 标记是否已经初始化
SM_ItemCollectionUI.currentSelectedButton = nil -- 跟踪当前选中的按钮
-- 分页相关变量
SM_ItemCollectionUI.currentPage = 1
SM_ItemCollectionUI.itemsPerPage = 18 -- 每页显示18个物品
SM_ItemCollectionUI.totalPages = 1
SM_ItemCollectionUI.pageButtons = {}
SM_ItemCollectionUI.lastUpdateTime = 0 -- 上次更新时间
SM_ItemCollectionUI.CACHE_EXPIRE_TIME = 3600 -- 缓存过期时间1小时
-- 初始化物品收藏界面
function SM_ItemCollectionUI:Init()
-- 只做一次全局声明绝不重置SM_CollectionsDB或itemCache
-- 从其他文件加载必要的模块
if not SM_CollectionData then
LoadAddOn("SM_CollectionSystem")
end
-- 初始化物品槽位数据
self:InitSlotData()
self.initialized = true
end
-- 初始化物品槽位数据
function SM_ItemCollectionUI:InitSlotData()
-- 获取物品分类数据
local MODEL_SLOTS = {
{ name = "头部", invType = "INVTYPE_HEAD", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Head" },
{ name = "肩部", invType = "INVTYPE_SHOULDER", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Shoulder" },
{ name = "背部", invType = "INVTYPE_CLOAK", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Chest" },
{ name = "胸部", invType = "INVTYPE_CHEST", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Chest" },
{ name = "衬衣", invType = "INVTYPE_BODY", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Shirt" },
{ name = "战袍", invType = "INVTYPE_TABARD", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Tabard" },
{ name = "手腕", invType = "INVTYPE_WRIST", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Wrists" },
{ name = "", invType = "INVTYPE_HAND", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Hands" },
{ name = "腰带", invType = "INVTYPE_WAIST", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Waist" },
{ name = "", invType = "INVTYPE_LEGS", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Legs" },
{ name = "", invType = "INVTYPE_FEET", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Feet" },
{ name = "主手", invType = "INVTYPE_WEAPONMAINHAND", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-MainHand" },
{ name = "副手", invType = "INVTYPE_WEAPONOFFHAND", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Relic" },
{ name = "远程", invType = "INVTYPE_RANGED", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Ranged" },
{ name = "颈部", invType = "INVTYPE_NECK", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Neck" },
{ name = "戒指", invType = "INVTYPE_FINGER", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Finger" },
{ name = "饰品", invType = "INVTYPE_TRINKET", items = {}, icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Trinket" },
}
self.ALL_SLOTS = MODEL_SLOTS
-- 动态生成类型映射表,保证和槽位定义一致
self.typeToInvType = {}
for _, slot in ipairs(self.ALL_SLOTS) do
self.typeToInvType[slot.name] = slot.invType
end
end
-- 隐藏所有按钮
function SM_ItemCollectionUI:HideButtons()
for _, button in ipairs(self.buttons) do
button:Hide()
end
-- 如果有预览框也隐藏
if self.previewFrame and self.previewFrame:IsShown() then
self.previewFrame:Hide()
end
end
-- 显示所有按钮
function SM_ItemCollectionUI:ShowButtons()
for _, button in ipairs(self.buttons) do
button:Show()
-- 默认隐藏所有按钮的选中状态
if button.SelectedTexture then
button.SelectedTexture:Hide()
end
end
-- 恢复之前选中按钮的状态
if self.currentSelectedButton and self.currentSelectedButton.SelectedTexture then
self.currentSelectedButton.SelectedTexture:Show()
end
end
-- 清除所有模型选中状态
function SM_ItemCollectionUI:ClearModelSelection()
if self.selectedModel and self.selectedModel.TransmogStateTexture then
self.selectedModel.TransmogStateTexture:Hide()
end
self.selectedModel = nil
end
-- 设置模型选中状态
function SM_ItemCollectionUI:SelectModel(model)
-- 清除之前的选中状态
self:ClearModelSelection()
-- 设置当前模型为选中状态
if model then
if model.TransmogStateTexture then
model.TransmogStateTexture:Show()
-- 根据物品是否已获得设置选中纹理颜色
if model.itemData and model.itemData.obtained then
model.TransmogStateTexture:SetVertexColor(0, 1, 0, 0.7) -- 绿色选中纹理
else
model.TransmogStateTexture:SetVertexColor(1, 0, 0, 0.7) -- 红色选中纹理
end
end
self.selectedModel = model
end
end
-- 辅助函数:设置模型类型
function SM_ItemCollectionUI:SetModelType(model, type)
model.type = type
model:SetPosition(0, 0, 0)
model:SetFacing(0)
model:SetRotation(0)
if type == "player" then
model:SetUnit("player")
model.animID = ANIMATION_ARMOR_PREVIEW
elseif type == "main" then
model:SetCreature(2334) --隐身模型
model.animID = ANIMATION_WEAPON_PREVIEW_MAIN
elseif type == "off" then
model:SetCreature(2334)--隐身模型
model.animID = ANIMATION_WEAPON_PREVIEW_OFF
elseif type == "ranged" then
model:SetUnit("player")
model.animID = ANIMATION_RANGED_PREVIEW
end
end
-- 辅助函数:应用摄像机参数
function SM_ItemCollectionUI:ApplyCamera(model, cameraID)
-- 确保cameraID是有效的数值ID
if type(cameraID) == "string" then
-- 如果传入的是字符串ID需要转换为数值ID
--print("警告传入了字符串相机ID: " .. cameraID .. "应该使用GetCharacterCameraID或GetWeaponCameraID获取数值ID")
return
end
local params = SM_CollectionData.Cameras[cameraID]
if params then
if #params == 4 then
-- 装备部位使用的格式scale, leftRight, upDown, facing
local scale, leftRight, upDown, facing = unpack(params)
model:SetModelScale(scale)
model:SetPosition(0, leftRight, upDown) -- 装备使用相对偏移
model:SetFacing(facing or 0)
else
-- 武器使用的格式scale, x, y, z, facing
local scale, x, y, z, facing = unpack(params)
model:SetModelScale(scale)
model:SetPosition(x, y, z) -- 武器使用绝对坐标
model:SetFacing(facing or 0)
end
else
--print("摄像机参数未找到ID:", cameraID)
end
end
-- 辅助函数:冻结动画
function SM_ItemCollectionUI:FreezeAnimation(model)
-- 清除现有OnUpdate脚本
model:SetScript("OnUpdate", nil)
-- 设置正确的动画ID
local animID = model.animID or ANIMATION_ARMOR_PREVIEW
-- 设置动画序列
model:SetSequence(animID)
if animID ~= ANIMATION_RANGED_PREVIEW then
-- 其他动画:冻结在第一帧
model:SetSequenceTime(animID, 0)
-- 添加OnUpdate冻结 - 每帧重置动画时间
model:SetScript("OnUpdate", function(self)
self:SetSequenceTime(self.animID, 0)
end)
end
end
-- 辅助函数:更新属性加成
function SM_ItemCollectionUI:UpdateAttributes(itemID, itemType)
if not SM_Collections.MainFrame or not SM_Collections.MainFrame.RightSidePanel then
return
end
local rightSidePanel = SM_Collections.MainFrame.RightSidePanel
-- 清理其他收藏界面的属性按钮
if rightSidePanel.AttributeBonusFrame then
local children = { rightSidePanel.AttributeBonusFrame:GetChildren() }
for _, child in ipairs(children) do
if child:GetName() and string.find(child:GetName(), "SM_CollectionsAttributeutton") then
child:Hide()
end
end
end
-- 确保属性加成框架存在并显示
if not rightSidePanel.AttributeBonusFrame then
-- 创建属性加成框架
local attributeFrame = CreateFrame("Frame", nil, rightSidePanel)
attributeFrame:SetSize(180, 30)
attributeFrame:SetPoint("TOP", rightSidePanel, "TOP", 0, -140)
local attributeTitle = attributeFrame:CreateFontString(nil, "OVERLAY")
attributeTitle:SetFont("Fonts\\ZYKai_T.ttf", 14, "OUTLINE")
attributeTitle:SetPoint("TOP", 0, 0)
attributeTitle:SetText("属性加成")
attributeTitle:SetTextColor(1, 0.82, 0)
rightSidePanel.AttributeBonusFrame = attributeFrame
end
-- 显示属性加成区域
rightSidePanel.AttributeBonusFrame:Show()
-- 清理旧的属性按钮和文本
if rightSidePanel.attributeButtons then
for _, button in ipairs(rightSidePanel.attributeButtons) do
button:Hide()
end
end
-- 清理旧的属性文本
if rightSidePanel.attributeTexts then
for _, text in ipairs(rightSidePanel.attributeTexts) do
text:Hide()
end
end
-- 重置数组
rightSidePanel.attributeButtons = {}
rightSidePanel.attributeTexts = {}
-- 模拟不同物品的不同属性加成
local attributes = {}
-- 根据物品ID的不同添加不同的属性示例
if itemID % 2 == 0 then
table.insert(attributes, { name = "火焰伤害", value = "+500", isPositive = true })
else
table.insert(attributes, { name = "敏捷", value = "+20", isPositive = true })
end
if itemID % 3 == 0 then
table.insert(attributes, { name = "法术强度", value = "+200", isPositive = true })
end
if itemID % 5 == 0 then
table.insert(attributes, { name = "冰霜抗性", value = "+75", isPositive = true })
end
-- 根据物品类型添加特有的属性
if itemType == "INVTYPE_HEAD" or itemType == "INVTYPE_CHEST" or itemType == "INVTYPE_LEGS" then
table.insert(attributes, { name = "护甲", value = "+100", isPositive = true })
elseif itemType == "INVTYPE_WEAPONMAINHAND" then
table.insert(attributes, { name = "攻击强度", value = "+50", isPositive = true })
elseif itemType == "INVTYPE_TRINKET" then
table.insert(attributes, { name = "暴击率", value = "+2%", isPositive = true })
end
-- 添加属性按钮,与其他收藏页面风格一致
local buttonH = 150
local buttonW = 20
for i, attribute in ipairs(attributes) do
-- 创建带背景纹理的按钮
local button = CreateFrame("Button", "SM_ItemCollectionAttributeButton" .. i, rightSidePanel.AttributeBonusFrame)
button:SetSize(buttonH, buttonW)
button:SetNormalTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\AttributeuttonTexture")
button:SetPoint("TOPLEFT", 0, -30 - (i - 1) * buttonW)
-- 属性名称文本
local nameText = button:CreateFontString(nil, "OVERLAY")
nameText:SetPoint("LEFT", 10, 0)
nameText:SetFont("Fonts\\ZYKai_T.ttf", 10, "MONOCHROME")
nameText:SetText(attribute.name)
nameText:SetTextColor(1, 1, 1)
-- 属性数值文本
local valueText = button:CreateFontString(nil, "OVERLAY")
valueText:SetPoint("RIGHT", -5, 0)
valueText:SetFont("Fonts\\ZYKai_T.ttf", 10, "MONOCHROME")
valueText:SetText(attribute.value)
valueText:SetTextColor(0, 1, 0) -- 绿色显示属性
button:Show()
-- 存储按钮引用
table.insert(rightSidePanel.attributeButtons, button)
-- 也将文本添加到文本数组中以便清理
table.insert(rightSidePanel.attributeTexts, nameText)
table.insert(rightSidePanel.attributeTexts, valueText)
end
end
-- 处理按钮点击事件
function SM_ItemCollectionUI:HandleButtonClick(slot)
if not self.currentPanel then
return
end
-- 记录当前选中的按钮
for _, button in ipairs(self.buttons) do
if button.slotData == slot then
self.currentSelectedButton = button
break
end
end
self.currentPage = 1
self:ShowItemPreview(slot, self.currentPanel)
end
-- 显示物品预览
function SM_ItemCollectionUI:ShowItemPreview(slot, panel)
-- 清除当前选中的模型
self:ClearModelSelection()
if not panel then
panel = self.currentPanel
end
if not panel then
return
end
-- 清理旧的预览内容
if panel.previewFrame and panel.previewFrame:IsShown() then
local children = { panel.previewFrame:GetChildren() }
for _, child in ipairs(children) do
child:Hide()
child:SetParent(nil)
end
panel.previewFrame:Hide()
end
-- 创建预览框架
local previewFrame = CreateFrame("Frame", "ItemCollectionPreviewFrame", panel)
previewFrame:SetSize(580, 400)
previewFrame:SetPoint("LEFT", SM_Collections.MainFrame, "LEFT", 30, -20)
previewFrame:SetBackdrop({
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
})
previewFrame:Show()
panel.previewFrame = previewFrame
self.previewFrame = previewFrame
-- 判断是否是图标类物品
local isIconOnly = (slot.invType == "INVTYPE_NECK" or slot.invType == "INVTYPE_FINGER" or slot.invType == "INVTYPE_TRINKET")
-- 检查槽位是否有物品
if #slot.items == 0 then
-- 如果没有物品,显示一个提示信息
local noItemsText = previewFrame:CreateFontString(nil, "OVERLAY")
noItemsText:SetFont("Fonts\\ZYKai_T.ttf", 16, "OUTLINE")
noItemsText:SetPoint("CENTER", previewFrame, "CENTER", 0, 0)
noItemsText:SetText("该分类下暂无物品数据")
noItemsText:SetTextColor(1, 0.82, 0)
noItemsText:Show()
-- 更新右侧信息面板
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
if SM_Collections.MainFrame.RightSidePanel.MountNama then
SM_Collections.MainFrame.RightSidePanel.MountNama:SetText("无物品")
end
if SM_Collections.MainFrame.RightSidePanel.introText then
SM_Collections.MainFrame.RightSidePanel.introText:SetText("类型: " .. slot.name .. "\n暂无物品数据")
end
-- 清空属性加成显示
if SM_Collections.MainFrame.RightSidePanel.AttributeBonusFrame then
SM_Collections.MainFrame.RightSidePanel.AttributeBonusFrame:Hide()
end
end
return
end
local startIdx = (self.currentPage - 1) * self.itemsPerPage + 1
local endIdx = math.min(startIdx + self.itemsPerPage - 1, #slot.items)
if isIconOnly then
local modelFrames = {}
for j = startIdx, endIdx do
local itemID = slot.items[j]
if not itemID then break end
local pageIndex = j - startIdx
local row = math.floor(pageIndex / 6)
local col = pageIndex % 6
local model = CreateFrame("Frame", nil, previewFrame, "SM_CollectionSystemWardrobeItemsModelTemplate")
model:SetSize(78, 104)
model:SetPoint("TOPLEFT", 24 + col * 92, -10 - row * 120)
if model.Model then model.Model:Hide() end
local icon = model:CreateTexture(nil, "ARTWORK")
icon:SetSize(50, 50)
icon:SetPoint("CENTER", 0, 10)
icon:SetTexture(GetItemIcon(itemID))
icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
-- 检查物品是否已获得,设置灰度效果
local itemData = nil
if SM_CollectionsDB and SM_CollectionsDB.itemCache and SM_CollectionsDB.itemCache.items then
for _, item in ipairs(SM_CollectionsDB.itemCache.items) do
if tonumber(item.id) == tonumber(itemID) then
itemData = item
break
end
end
end
-- 如果物品未获得,设置灰度效果
if not (itemData and itemData.obtained) then
icon:SetDesaturated(true)
end
-- 设置边框颜色
if model.Border then
if itemData and itemData.obtained then
model.Border:SetVertexColor(0, 1, 0, 1) -- 绿色边框
else
model.Border:SetVertexColor(1, 0, 0, 1) -- 红色边框
end
end
-- 设置高光颜色
local highlightTextures = { model:GetRegions() }
for _, region in ipairs(highlightTextures) do
if region:GetDrawLayer() == "HIGHLIGHT" then
if itemData and itemData.obtained then
region:SetVertexColor(0, 1, 0, 0.7) -- 绿色高光
else
region:SetVertexColor(1, 0, 0, 0.7) -- 红色高光
end
end
end
model.itemData = itemData -- 保存物品数据以便后续使用
if model.TransmogStateTexture then model.TransmogStateTexture:Hide() end
table.insert(modelFrames, model)
model:Show()
model:EnableMouse(true)
model:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetHyperlink("item:" .. itemID)
GameTooltip:Show()
end)
model:SetScript("OnLeave", function() GameTooltip:Hide() end)
local currentItemID = itemID
local currentModel = model
model:SetScript("OnMouseDown", function(self)
SM_ItemCollectionUI:SelectModel(currentModel)
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
local itemName = GetItemInfo(currentItemID)
if SM_Collections.MainFrame.RightSidePanel.MountNama then
SM_Collections.MainFrame.RightSidePanel.MountNama:SetText(itemName or "")
end
if SM_Collections.MainFrame.RightSidePanel.introText then
SM_Collections.MainFrame.RightSidePanel.introText:SetText("物品ID: " ..
currentItemID .. "\n类型: " .. slot.name)
end
SM_ItemCollectionUI:UpdateAttributes(currentItemID, slot.invType)
end
end)
end
if #modelFrames > 0 and slot.items[startIdx] then
local firstModel = modelFrames[1]
self:SelectModel(firstModel)
local itemID = slot.items[startIdx]
local itemName = GetItemInfo(itemID)
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
if SM_Collections.MainFrame.RightSidePanel.MountNama then
SM_Collections.MainFrame.RightSidePanel.MountNama:SetText(itemName or "")
end
if SM_Collections.MainFrame.RightSidePanel.introText then
SM_Collections.MainFrame.RightSidePanel.introText:SetText("物品ID: " .. itemID .. "\n类型: " .. slot
.name)
end
self:UpdateAttributes(itemID, slot.invType)
end
end
else
local modelFrames = {}
for j = startIdx, endIdx do
local itemID = slot.items[j]
if not itemID then break end
local pageIndex = j - startIdx
local row = math.floor(pageIndex / 6)
local col = pageIndex % 6
local model = CreateFrame("DressUpModel", nil, previewFrame, "SM_CollectionSystemWardrobeItemsModelTemplate")
model:SetSize(78, 104)
model:SetPoint("TOPLEFT", 24 + col * 92, -10 - row * 120)
if model.TransmogStateTexture then model.TransmogStateTexture:Hide() end
-- 检查物品是否已获得,设置灰度效果
local itemData = nil
if SM_CollectionsDB and SM_CollectionsDB.itemCache and SM_CollectionsDB.itemCache.items then
for _, item in ipairs(SM_CollectionsDB.itemCache.items) do
if tonumber(item.id) == tonumber(itemID) then
itemData = item
break
end
end
end
-- 设置边框颜色
if model.Border then
if itemData and itemData.obtained then
model.Border:SetVertexColor(0, 1, 0, 1) -- 绿色边框
else
model.Border:SetVertexColor(1, 0, 0, 1) -- 红色边框
end
end
-- 设置高光颜色
local highlightTextures = { model:GetRegions() }
for _, region in ipairs(highlightTextures) do
if region:GetDrawLayer() == "HIGHLIGHT" then
if itemData and itemData.obtained then
region:SetVertexColor(0, 1, 0, 0.7) -- 绿色高光
else
region:SetVertexColor(1, 0, 0, 0.7) -- 红色高光
end
end
end
model.itemData = itemData -- 保存物品数据以便后续使用
table.insert(modelFrames, model)
model:Show()
model:EnableMouse(true)
model:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetHyperlink("item:" .. itemID)
GameTooltip:Show()
end)
model:SetScript("OnLeave", function(self) GameTooltip:Hide() end)
local currentItemID = itemID
local currentModel = model
model:SetScript("OnMouseDown", function(self)
SM_ItemCollectionUI:SelectModel(currentModel)
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
local itemName = GetItemInfo(currentItemID)
if SM_Collections.MainFrame.RightSidePanel.MountNama then
SM_Collections.MainFrame.RightSidePanel.MountNama:SetText(itemName or "")
end
if SM_Collections.MainFrame.RightSidePanel.introText then
SM_Collections.MainFrame.RightSidePanel.introText:SetText("物品ID: " ..
currentItemID .. "\n类型: " .. slot.name)
-- 获取物品的 obtained 状态
local itemData = nil
for _, item in ipairs(SM_CollectionsDB.itemCache and SM_CollectionsDB.itemCache.items or {}) do
if tonumber(item.id) == tonumber(currentItemID) then
itemData = item
break
end
end
-- 添加状态文本
if not SM_Collections.MainFrame.RightSidePanel.statusText then
SM_Collections.MainFrame.RightSidePanel.statusText = SM_Collections.MainFrame.RightSidePanel
:CreateFontString(nil, "OVERLAY")
SM_Collections.MainFrame.RightSidePanel.statusText:SetFont("Fonts\\ZYKai_T.ttf", 14,
"OUTLINE")
SM_Collections.MainFrame.RightSidePanel.statusText:SetPoint("TOP",
SM_Collections.MainFrame.RightSidePanel.introText, "BOTTOM", 0, -10)
end
local statusText = itemData and itemData.obtained and "|cFF00FF00已获得|r" or "|cFFFF0000未获得|r"
SM_Collections.MainFrame.RightSidePanel.statusText:SetText(statusText)
SM_Collections.MainFrame.RightSidePanel.statusText:Show()
end
SM_ItemCollectionUI:UpdateAttributes(currentItemID, slot.invType)
end
end)
if slot.invType == "INVTYPE_WEAPONMAINHAND" or slot.invType == "INVTYPE_WEAPONOFFHAND" then
model:ClearModel()
if slot.invType == "INVTYPE_WEAPONOFFHAND" then
model.originalType = "off"
self:SetModelType(model, "off")
else
model.originalType = "main"
self:SetModelType(model, "main")
end
model:Undress()
local success, error = pcall(function() model:TryOn(itemID) end)
local weaponCameraID
if slot.invType == "INVTYPE_WEAPONOFFHAND" then
weaponCameraID = SM_CollectionData:GetWeaponCameraID("INVTYPE_WEAPONOFFHAND")
else
weaponCameraID = SM_CollectionData:GetWeaponCameraID("INVTYPE_WEAPONMAINHAND")
end
self:ApplyCamera(model, weaponCameraID)
elseif slot.invType == "INVTYPE_RANGED" then
model:ClearModel()
model:SetUnit("player")
model.animID = ANIMATION_RANGED_PREVIEW
model:Undress()
local success, error = pcall(function() model:TryOn(itemID) end)
local cameraID = SM_CollectionData:GetCharacterCameraID(slot.invType)
self:ApplyCamera(model, cameraID)
model:EnableMouse(true)
model:EnableMouseWheel(true)
model.isRotating = false
model.lastX = 0
local currentModel = model
local currentItemID = itemID
local updateFrame = CreateFrame("Frame", nil, model)
updateFrame:SetScript("OnUpdate", function(self, elapsed)
if currentModel.isRotating then
local x = GetCursorPosition()
local delta = (x - (currentModel.lastX or x)) * 0.01
currentModel.lastX = x
currentModel:SetFacing(currentModel:GetFacing() + delta)
end
end)
model:SetScript("OnMouseDown", function(self, button)
if button == "LeftButton" then
SM_ItemCollectionUI:SelectModel(currentModel)
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
local itemName = GetItemInfo(currentItemID)
if SM_Collections.MainFrame.RightSidePanel.MountNama then
SM_Collections.MainFrame.RightSidePanel.MountNama:SetText(itemName or "")
end
if SM_Collections.MainFrame.RightSidePanel.introText then
SM_Collections.MainFrame.RightSidePanel.introText:SetText("物品ID: " ..
currentItemID .. "\n类型: " .. slot.name)
end
SM_ItemCollectionUI:UpdateAttributes(currentItemID, slot.invType)
end
self.isRotating = true
self.lastX = GetCursorPosition()
end
end)
model:SetScript("OnMouseWheel", function(self, delta)
local rotationAmount = math.rad(15)
self:SetFacing(self:GetFacing() - (delta * rotationAmount))
end)
model:SetScript("OnMouseUp", function(self, button)
if button == "LeftButton" then
self.isRotating = false
end
end)
model:SetScript("OnLeave", function(self)
if self.isRotating then
self.isRotating = false
end
GameTooltip:Hide()
end)
else
self:SetModelType(model, "player")
local success, error = pcall(function() model:TryOn(itemID) end)
local cameraID = SM_CollectionData:GetCharacterCameraID(slot.invType)
self:ApplyCamera(model, cameraID)
end
self:FreezeAnimation(model)
if model.NewString and model.NewGlow then end
if model.Favorite and model.Favorite.Icon then end
if model.HideVisual and model.HideVisual.Icon then end
end
if #modelFrames > 0 and slot.items[startIdx] then
local firstModel = modelFrames[1]
self:SelectModel(firstModel)
local itemID = slot.items[startIdx]
local itemName = GetItemInfo(itemID)
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
if SM_Collections.MainFrame.RightSidePanel.MountNama then
SM_Collections.MainFrame.RightSidePanel.MountNama:SetText(itemName or "")
end
if SM_Collections.MainFrame.RightSidePanel.introText then
SM_Collections.MainFrame.RightSidePanel.introText:SetText("物品ID: " .. itemID .. "\n类型: " .. slot
.name)
end
self:UpdateAttributes(itemID, slot.invType)
end
end
end
self:CreatePageButtons(panel, slot)
-- 在切换部位时更新物品状态显示
if #slot.items > 0 then
local startIdx = (self.currentPage - 1) * self.itemsPerPage + 1
local itemID = slot.items[startIdx]
if itemID then
-- 获取物品的 obtained 状态
local itemData = nil
if SM_CollectionsDB and SM_CollectionsDB.itemCache and SM_CollectionsDB.itemCache.items then
for _, item in ipairs(SM_CollectionsDB.itemCache.items) do
if tonumber(item.id) == tonumber(itemID) then
itemData = item
break
end
end
end
-- 添加或更新状态文本
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
if not SM_Collections.MainFrame.RightSidePanel.statusText then
SM_Collections.MainFrame.RightSidePanel.statusText = SM_Collections.MainFrame.RightSidePanel
:CreateFontString(nil, "OVERLAY")
SM_Collections.MainFrame.RightSidePanel.statusText:SetFont("Fonts\\ZYKai_T.ttf", 14, "OUTLINE")
SM_Collections.MainFrame.RightSidePanel.statusText:SetPoint("TOP",
SM_Collections.MainFrame.RightSidePanel.introText, "BOTTOM", 0, -10)
end
local statusText = itemData and itemData.obtained and "|cFF00FF00已获得|r" or "|cFFFF0000未获得|r"
SM_Collections.MainFrame.RightSidePanel.statusText:SetText(statusText)
SM_Collections.MainFrame.RightSidePanel.statusText:Show()
end
end
end
end
-- 创建分页按钮
function SM_ItemCollectionUI:CreatePageButtons(panel, slot)
-- 移除旧按钮
if self.pageButtons.prev then self.pageButtons.prev:Hide() end
if self.pageButtons.next then self.pageButtons.next:Hide() end
if self.pageButtons.text then self.pageButtons.text:Hide() end
-- 计算总页数
local totalItems = #slot.items
self.totalPages = math.max(1, math.ceil(totalItems / self.itemsPerPage))
if self.currentPage > self.totalPages then self.currentPage = self.totalPages end
-- 上一页按钮
local prevBtn = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
prevBtn:SetSize(60, 24)
prevBtn:SetPoint("BOTTOM", panel, "BOTTOM", 0, 30)
prevBtn:SetText("上一页")
prevBtn:SetScript("OnClick", function()
if self.currentPage > 1 then
self.currentPage = self.currentPage - 1
self:ShowItemPreview(slot, panel)
end
end)
if self.currentPage <= 1 then
prevBtn:Disable()
else
prevBtn:Enable()
end
prevBtn:Show()
self.pageButtons.prev = prevBtn
-- 下一页按钮
local nextBtn = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
nextBtn:SetSize(60, 24)
nextBtn:SetPoint("BOTTOM", panel, "BOTTOM", 160, 30)
nextBtn:SetText("下一页")
nextBtn:SetScript("OnClick", function()
if self.currentPage < self.totalPages then
self.currentPage = self.currentPage + 1
self:ShowItemPreview(slot, panel)
end
end)
if self.currentPage >= self.totalPages then
nextBtn:Disable()
else
nextBtn:Enable()
end
nextBtn:Show()
self.pageButtons.next = nextBtn
-- 页码文本
local pageText = panel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
pageText:SetPoint("BOTTOM", panel, "BOTTOM", 80, 35)
pageText:SetText(string.format("第 %d / %d 页", self.currentPage, self.totalPages))
pageText:SetDrawLayer("OVERLAY", 7) -- 使用子层级7确保在OVERLAY层的最顶部
pageText:Show()
self.pageButtons.text = pageText
end
-- 清除所有按钮
function SM_ItemCollectionUI:ClearButtons()
for _, button in ipairs(self.buttons) do
button:Hide()
button:SetParent(nil)
end
self.buttons = {}
end
-- 创建按钮
function SM_ItemCollectionUI:CreateButtons()
-- 先清除之前的按钮
self:ClearButtons()
local lastButton = nil -- 记录最后一个按钮(包括正常和特殊按钮)
local specialButtonsOffset = false
-- 创建所有槽位按钮
for i, slot in ipairs(self.ALL_SLOTS) do
local btn
local slotName = string.lower(string.gsub(slot.invType, "INVTYPE_", ""))
-- 对于没有对应纹理的槽位(颈部、戒指、饰品),创建独立按钮
if slotName == "neck" or slotName == "finger" or slotName == "trinket" then
-- 创建独立按钮,不使用模板
btn = CreateFrame("Button", nil, SM_ItemCollectionUI.currentPanel)
btn:SetSize(30, 30)
-- 智能定位:相对于最后一个按钮
if lastButton then
local xOffset = not specialButtonsOffset and 0 or 5 -- 第一个用10后续用8
local yOffset = not specialButtonsOffset and 2 or 0 -- 只有第一个向上偏移
if not specialButtonsOffset then specialButtonsOffset = true end
btn:SetPoint("LEFT", lastButton, "RIGHT", xOffset, yOffset)
else
btn:SetPoint("TOPLEFT", 90, -43)
end
-- 添加正常纹理
local normalTexture = btn:CreateTexture(nil, "BACKGROUND")
normalTexture:SetSize(28, 28)
normalTexture:SetPoint("CENTER")
normalTexture:SetTexture(slot.icon) -- ICON_SLOTS 图标纹理
SetPortraitToTexture(normalTexture, slot.icon) -- 圆形肖像
btn.NormalTexture = normalTexture
-- 添加高光纹理(使用通用的高光效果)
local highlightTexture = btn:CreateTexture(nil, "HIGHLIGHT")
highlightTexture:SetSize(30, 30)
highlightTexture:SetPoint("CENTER", 0, 0)
highlightTexture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Interface\\ContainerFrame\\Bags")
highlightTexture:SetTexCoord(0.1640625, 0.3046875, 0.6875, 0.828125) -- 这是XML里的
highlightTexture:SetBlendMode("ADD")
-- 添加覆盖纹理
local ArtworkTexture = btn:CreateTexture(nil, "OVERLAY")
ArtworkTexture:SetSize(33, 33)
ArtworkTexture:SetPoint("CENTER")
ArtworkTexture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\NeckButon_ARTWORK")
--SetPortraitToTexture(ArtworkTexture, "Interface\\AddOns\\SM_CollectionSystem\\Textures\\NeckButon_ARTWORK")
btn.ArtworkTexture = ArtworkTexture
-- local selectedTexture = btn:CreateTexture(nil, "OVERLAY", nil, 1)
-- selectedTexture:SetSize(45, 47)
-- selectedTexture:SetPoint("CENTER", 0, -2)
-- selectedTexture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Interface\\Transmogrify\\Transmogrify")
-- selectedTexture:SetTexCoord(0.734375, 0.802734375, 0.171875, 0.244140625) -- 这是XML里的
-- selectedTexture:Hide()
-- btn.SelectedTexture = selectedTexture
else
btn = CreateFrame("Button", nil, SM_ItemCollectionUI.currentPanel, "SM_CollectionSystemWardrobeSlotButtonTemplate")
btn:SetSize(40, 40)
btn:SetPoint("TOPLEFT", 80 + (i - 1) * 35, 35)
-- 设置图标
if btn.NormalTexture then
-- 增加纹理大小以适配按钮
btn.NormalTexture:SetSize(40, 40)
-- 如果有高亮纹理,调整其大小
if btn.Highlight then
btn.Highlight:SetSize(28, 28)
btn.Highlight:SetPoint("CENTER", 0, 2)
end
-- 如果有选中纹理,调整其大小
if btn.SelectedTexture then
btn.SelectedTexture:SetSize(45, 48)
btn.SelectedTexture:SetPoint("CENTER")
end
-- 使用SetAtlasMixin设置图标
SM_Collections:Mixin(btn.NormalTexture, SetAtlasMixin)
-- 根据槽位类型映射到合适的atlas纹理名称
local atlasName = "transmog-nav-slot-"
-- 处理特殊槽位名称映射
if slotName == "head" then
atlasName = atlasName .. "head"
elseif slotName == "shoulder" then
atlasName = atlasName .. "shoulder"
elseif slotName == "body" then
atlasName = atlasName .. "shirt"
elseif slotName == "chest" then
atlasName = atlasName .. "chest"
elseif slotName == "waist" then
atlasName = atlasName .. "waist"
elseif slotName == "legs" then
atlasName = atlasName .. "legs"
elseif slotName == "feet" then
atlasName = atlasName .. "feet"
elseif slotName == "wrist" then
atlasName = atlasName .. "wrist"
elseif slotName == "hand" then
atlasName = atlasName .. "hands"
elseif slotName == "cloak" then
atlasName = atlasName .. "back"
elseif slotName == "weaponmainhand" then
atlasName = atlasName .. "mainhand"
elseif slotName == "weaponoffhand" then
atlasName = atlasName .. "secondaryhand"
elseif slotName == "ranged" then
atlasName = atlasName .. "ranged"
elseif slotName == "tabard" then
atlasName = atlasName .. "tabard"
end
-- 应用atlas纹理
if not string.find(atlasName, "transmog-nav-slot-$") then
btn.NormalTexture:SetAtlas(atlasName, true)
end
end
end
-- 更新最后一个按钮的引用(关键修改)
lastButton = btn
-- 设置事件处理
btn:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetText(slot.name)
GameTooltip:Show()
-- 只有在按钮未被选中时才显示高光纹理
if self.Highlight and (not self.SelectedTexture or not self.SelectedTexture:IsShown()) then
self.Highlight:Show()
end
end)
btn:SetScript("OnLeave", function(self)
GameTooltip:Hide()
-- 隐藏高亮纹理
if self.Highlight then
self.Highlight:Hide()
end
end)
-- 关键改动将slot对象存储在按钮上而不是依赖闭包
btn.slotData = slot
btn:SetScript("OnClick", function(self)
-- 播放点击音效
PlaySound("igSpellBookSpellIconPickup")
-- 清除所有按钮的选中状态
for _, button in ipairs(SM_ItemCollectionUI.buttons) do
if button.SelectedTexture then
button.SelectedTexture:Hide()
end
end
-- 显示当前按钮的选中状态
if self.SelectedTexture then
self.SelectedTexture:Show()
end
-- 直接从按钮属性中获取slot数据
SM_ItemCollectionUI:HandleButtonClick(self.slotData)
end)
table.insert(self.buttons, btn)
end
-- 默认隐藏所有按钮
self:HideButtons()
end
-- 显示物品收藏界面
function SM_ItemCollectionUI:ShowItemCollectionUI(parent)
-- 确保已初始化防止ALL_SLOTS未初始化导致缓存数据无法分类
if not self.initialized then
self:Init()
end
-- 创建新的物品分栏面板
local panel = CreateFrame("Frame", "SM_CollectionsItemsPanel", parent)
panel:SetAllPoints()
self.currentPanel = panel
-- 隐藏右侧召唤按钮
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel and SM_Collections.MainFrame.RightSidePanel.CallButon then
SM_Collections.MainFrame.RightSidePanel.CallButon:Hide()
end
-- 确保属性加成框架存在并显示
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
if SM_Collections.MainFrame.RightSidePanel.attributeTexts then
for _, text in ipairs(SM_Collections.MainFrame.RightSidePanel.attributeTexts) do
text:Hide()
end
SM_Collections.MainFrame.RightSidePanel.attributeTexts = {}
end
if not SM_Collections.MainFrame.RightSidePanel.AttributeBonusFrame then
local attributeFrame = CreateFrame("Frame", nil, SM_Collections.MainFrame.RightSidePanel)
attributeFrame:SetSize(180, 30)
attributeFrame:SetPoint("TOP", SM_Collections.MainFrame.RightSidePanel, "TOP", 0, -140)
local attributeTitle = attributeFrame:CreateFontString(nil, "OVERLAY")
attributeTitle:SetFont("Fonts\\ZYKai_T.ttf", 14, "OUTLINE")
attributeTitle:SetPoint("TOP", 0, 0)
attributeTitle:SetText("属性加成")
attributeTitle:SetTextColor(1, 0.82, 0)
SM_Collections.MainFrame.RightSidePanel.AttributeBonusFrame = attributeFrame
end
SM_Collections.MainFrame.RightSidePanel.AttributeBonusFrame:Show()
if not SM_Collections.MainFrame.RightSidePanel.attributeTexts then
SM_Collections.MainFrame.RightSidePanel.attributeTexts = {}
end
end
-- 创建一个等待提示
local waitingText = panel:CreateFontString(nil, "OVERLAY")
waitingText:SetFont("Fonts\\ZYKai_T.ttf", 16, "OUTLINE")
waitingText:SetPoint("CENTER", panel, "CENTER", 0, 0)
waitingText:SetText("正在从服务器获取物品数据...")
waitingText:SetTextColor(1, 0.82, 0)
waitingText:Show()
panel.waitingText = waitingText
-- 读取SavedVariables缓存只判断不赋值
local cacheValid = false
if SM_CollectionsDB and SM_CollectionsDB.itemCache then
local cache = SM_CollectionsDB.itemCache
if cache.items and #cache.items > 0 then
cacheValid = true
end
end
if cacheValid then
print("[SM_ItemCollectionUI] 读取缓存,物品数量:"..#SM_CollectionsDB.itemCache.items)
if panel.waitingText then panel.waitingText:Hide() end
self:ProcessAndShowItems(SM_CollectionsDB.itemCache.items, panel)
else
-- 请求数据
for _, slot in ipairs(self.ALL_SLOTS) do
slot.items = {}
end
local slotTypeMap = {}
for _, slot in ipairs(self.ALL_SLOTS) do
slotTypeMap[slot.invType] = slot
end
function self:GetItemEquipLocFromServerData(serverItemType, nini)
if slotTypeMap[serverItemType] then
return slotTypeMap[serverItemType]
end
return nil
end
SM_Collections.DataManager:GetItems(function(items)
if panel.waitingText then panel.waitingText:Hide() end
if items and #items > 0 then
-- 只在有数据时才写入缓存
SM_CollectionsDB.itemCache = {
items = items,
lastUpdate = time()
}
self:ProcessAndShowItems(items, panel)
else
-- 没有数据,显示提示
if panel.waitingText then panel.waitingText:SetText("没有获取到任何物品数据,请检查服务端或本地数据配置!") end
end
end)
end
return panel
end
function SM_ItemCollectionUI:ProcessAndShowItems(items, panel)
print("[SM_ItemCollectionUI] ProcessAndShowItems, items数量"..#items)
-- 清空所有槽位的物品数组
for _, slot in ipairs(self.ALL_SLOTS) do
slot.items = {}
end
-- 创建槽位映射表
local slotTypeMap = {}
for _, slot in ipairs(self.ALL_SLOTS) do
slotTypeMap[slot.invType] = slot
end
-- 分类物品到各个槽位
for i, item in ipairs(items) do
local itemID = tonumber(item.id)
if itemID and itemID > 0 then
local itemEquipLoc = nil
-- 兼容缓存数据的itemType为中文或invType
if item.itemType and item.itemType ~= "" then
if self.typeToInvType and self.typeToInvType[item.itemType] then
itemEquipLoc = self.typeToInvType[item.itemType]
else
itemEquipLoc = item.itemType
end
end
local slotFound = false
if itemEquipLoc and slotTypeMap[itemEquipLoc] then
local slot = slotTypeMap[itemEquipLoc]
local exists = false
for _, existingID in ipairs(slot.items) do
if existingID == itemID then exists = true break end
end
if not exists then
table.insert(slot.items, itemID)
slotFound = true
end
end
if not slotFound then
print(string.format("[SM_ItemCollectionUI] 警告: 物品 %d (%s) 未找到对应槽位itemType: %s, 转换后: %s", itemID, item.name or "", tostring(item.itemType), tostring(itemEquipLoc)))
end
end
end
self:DebugPrintItemArrays()
self:CreateButtons()
self:ShowButtons()
if SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
SM_Collections.MainFrame.RightSidePanel:Show()
end
panel:Show()
if #self.buttons > 0 then
local firstButton = self.buttons[1]
self.currentSelectedButton = firstButton
if firstButton.SelectedTexture then
firstButton.SelectedTexture:Show()
end
self:ShowItemPreview(firstButton.slotData, panel)
end
end
-- 添加一个调试函数,用于打印物品数组状态
function SM_ItemCollectionUI:DebugPrintItemArrays()
--print("=========== 物品收藏系统调试信息 ===========")
--print("物品槽位数量: " .. #self.ALL_SLOTS)
local totalItems = 0
for i, slot in ipairs(self.ALL_SLOTS) do
local itemCount = slot.items and #slot.items or 0
totalItems = totalItems + itemCount
--print(string.format("%s 槽位包含 %d 个物品", slot.name, itemCount))
-- 如果有物品打印前三个物品的ID
if itemCount > 0 then
local previewItems = {}
for j = 1, math.min(3, itemCount) do
local itemName = GetItemInfo(slot.items[j]) or "未知"
table.insert(previewItems, string.format("%d(%s)", slot.items[j], itemName))
end
--print(" 示例物品: " .. table.concat(previewItems, ", ") ..
-- (itemCount > 3 and " ..." or ""))
end
end
--print("物品总数: " .. totalItems)
--print("===========================================")
end