diff --git a/SM_CollectionSystem.lua b/SM_CollectionSystem.lua index ade35b1..538f872 100644 --- a/SM_CollectionSystem.lua +++ b/SM_CollectionSystem.lua @@ -17,8 +17,8 @@ SM_Collections.Config.UseServerData 默认 false 读取本地数据 --]] +-- 这里将拆分为多个文件,主入口只保留加载和初始化逻辑 --- SM_CollectionSystem.lua print("收藏系统开始") SM_Collections = {} SM_Collections.MainFrame = nil @@ -33,1300 +33,4 @@ SM_Collections.Config = { Debug = true -- 调试模式 } --- 消息分割函数 -function SM_Collections:MessageSplit(inputstr, sep) - if not inputstr or inputstr == "" then - return {} - end - if sep == nil then - sep = "%s" - end - local t = {} - for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do - table.insert(t, str) - end - return t -end - --- 创建自定义字体对象 -local titleFont = CreateFont("SM_TitleFont") -titleFont:SetFont("Fonts\\ZYKai_T.ttf", 20, "MONOCHROME") - -local descFont = CreateFont("SM_DescFont") -descFont:SetFont("Fonts\\ZYKai_T.ttf", 10, "MONOCHROME") - --- 数据提供者基类 -SM_Collections.DataProvider = {} - -function SM_Collections.DataProvider:new() - local obj = {} - setmetatable(obj, self) - self.__index = self - return obj -end - --- 抽象方法,子类必须实现 -function SM_Collections.DataProvider:GetMounts(callback) - error("GetMounts must be implemented by subclass") -end - -function SM_Collections.DataProvider:GetCompanions(callback) - error("GetCompanions must be implemented by subclass") -end - -function SM_Collections.DataProvider:GetCards(callback) - error("GetCards must be implemented by subclass") -end - -function SM_Collections.DataProvider:GetItems(callback) - error("GetItems must be implemented by subclass") -end - --- 抽象方法,子类必须实现 -function SM_Collections.DataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) - error("GetAttributesForSpecificItem must be implemented by subclass") -end - --- 本地数据提供者 -SM_Collections.LocalDataProvider = SM_Collections.DataProvider:new() - -function SM_Collections.LocalDataProvider:GetMounts(callback) - local mounts = { - { id = 458, name = "棕色马", description = "暴风城卫兵的最爱", obtained = true }, - { id = 459, name = "灰狼", description = "喜欢在雾中狩猎的狼", obtained = true }, - { id = 468, name = "白色骏马", description = "强大不屈的白色骏马", obtained = false }, - { id = 470, name = "黑色骏马", description = "据说SI:7夜间任务的首选", obtained = true }, - { id = 578, name = "黑狼", description = "嚎叫声能传播数英里", obtained = false }, - { id = 468, name = "白色骏马", description = "强大不屈的白色骏马", obtained = false }, - { id = 470, name = "黑色骏马", description = "据说SI:7夜间任务的首选", obtained = true }, - { id = 578, name = "黑狼", description = "嚎叫声能传播数英里", obtained = false }, - { id = 458, name = "棕色马", description = "暴风城卫兵的最爱", obtained = true }, - { id = 458, name = "棕色马", description = "暴风城卫兵的最爱", obtained = true }, - { id = 459, name = "灰狼", description = "喜欢在雾中狩猎的狼", obtained = true }, - { id = 468, name = "白色骏马", description = "强大不屈的白色骏马", obtained = false }, - { id = 470, name = "黑色骏马", description = "据说SI:7夜间任务的首选", obtained = true }, - { id = 578, name = "黑狼", description = "嚎叫声能传播数英里", obtained = false }, - { id = 468, name = "白色骏马", description = "强大不屈的白色骏马", obtained = false }, - { id = 470, name = "黑色骏马", description = "据说SI:7夜间任务的首选", obtained = true }, - { id = 578, name = "黑狼", description = "嚎叫声能传播数英里", obtained = false }, - { id = 458, name = "棕色马", description = "暴风城卫兵的最爱", obtained = true }, - } - - if SM_Collections.Config.Debug then - print("LocalDataProvider: 返回", #mounts, "个坐骑") - end - - callback(mounts) -end - -function SM_Collections.LocalDataProvider:GetCompanions(callback) - local companions = { - { id = 62508, name = "丹莫罗熊宝宝", description = "一只可爱的小猫", obtained = true }, - { id = 28871, name = "仲夏之魂", description = "一只忠诚的小狗", obtained = false }, - { id = 13548, name = "农场小鸡", description = "一只活泼的兔子", obtained = true }, - { id = 23811, name = "冬天爷爷的小助手", description = "一只会唱歌的鸟", obtained = false }, - } - callback(companions) -end - -function SM_Collections.LocalDataProvider:GetCards(callback) - local cards = { - { id = 11502, name = "拉格纳罗斯", description = "火焰之王", obtained = true }, - { id = 24248, name = "巫妖王阿尔萨斯", description = "亡灵天灾的领袖", obtained = false }, - { id = 19299, name = "死亡耳语者", description = "毁灭者", obtained = true }, - { id = 32588, name = "伊利丹·怒风", description = "背叛者", obtained = false }, - } - callback(cards) -end - -function SM_Collections.LocalDataProvider:GetItems(callback) - local items = { - { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, - { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, - { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, - { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, - { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, - { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, - { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, - { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, - { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, - { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, - { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, - { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, - { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, - { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, - { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, - { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, - { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, - { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, - { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, - { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, - } - callback(items) -end - -function SM_Collections.LocalDataProvider:GetAttributes(callback) - local attributes = { - { Name = "生命值", value = 999, isPositive = true }, - { Name = "近战攻强", value = 999, isPositive = true }, - { Name = "法术强度", value = 999, isPositive = true }, - { Name = "暴击等级", value = 999, isPositive = true }, - { Name = "造成奥术伤害", value = 999, isPositive = true }, - { Name = "造成火焰伤害", value = 999, isPositive = true }, - { Name = "受到所有伤害", value = 999, isPositive = false }, - { Name = "造成暴击伤害", value = 999, isPositive = true }, - { Name = "造成所有伤害", value = 999, isPositive = true }, - { Name = "治疗效果", value = 999, isPositive = true }, - } - callback(attributes) -end - --- 服务端数据提供者(预留) -SM_Collections.ServerDataProvider = SM_Collections.DataProvider:new() - -function SM_Collections.ServerDataProvider:GetMounts(callback) - self:SendServerRequest("GET_MOUNTS", {}, function(response) - if response and response.success then - if SM_Collections.Config.Debug then - print("ServerDataProvider: 从服务端获取到", #response.data, "个坐骑") - end - callback(response.data) - else - if SM_Collections.Config.FallbackToLocal then - print("服务端获取坐骑失败,回退到本地数据") - SM_Collections.LocalDataProvider:GetMounts(callback) - else - callback({}) - end - end - end) -end - -function SM_Collections.ServerDataProvider:GetCompanions(callback) - print("GetCompanions1") - self:SendServerRequest("GET_COMPANIONS", {}, function(response) - print("GetCompanions2") - if response and response.success then - print("GetCompanions3") - callback(response.data) - else - print("GetCompanions4") - if SM_Collections.Config.FallbackToLocal then - print("服务端获取小伙伴收藏失败,回退到本地数据") - SM_Collections.LocalDataProvider:GetCompanions(callback) - else - callback({}) - end - end - end) -end - -function SM_Collections.ServerDataProvider:GetCards(callback) - self:SendServerRequest("GET_CARDS", {}, function(response) - if response and response.success then - callback(response.data) - else - if SM_Collections.Config.FallbackToLocal then - print("服务端获取卡牌收藏失败,回退到本地数据") - SM_Collections.LocalDataProvider:GetCards(callback) - else - callback({}) - end - end - end) -end - -function SM_Collections.ServerDataProvider:GetItems(callback) - self:SendServerRequest("GET_ITEMS", {}, function(response) - if response and response.success then - callback(response.data) - else - if SM_Collections.Config.FallbackToLocal then - print("服务端获取物品收藏失败,回退到本地数据") - SM_Collections.LocalDataProvider:GetItems(callback) - else - callback({}) - end - end - end) -end - -function SM_Collections.ServerDataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) - local requestData = { - itemId = itemId, - itemType = itemType - } - - self:SendServerRequest("GET_ITEM_ATTRIBUTES", requestData, function(response) - if response and response.success then - if SM_Collections.Config.Debug then - print("ServerDataProvider: 从服务端获取到", #response.data, "个特定属性") - end - callback(response.data) - else - if SM_Collections.Config.FallbackToLocal then - print("服务端获取特定属性失败,回退到本地数据") - SM_Collections.LocalDataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) - else - callback({}) - end - end - end) -end - -function SM_Collections.ServerDataProvider:SendServerRequest(command, data, callback) - if SM_Collections.Config.Debug then - print("发送服务端请求:", command) - end - - -- 存储回调函数 - SM_Collections.pendingCallbacks = SM_Collections.pendingCallbacks or {} - - -- 坐骑 - if command == "GET_MOUNTS" then - SM_Collections.pendingCallbacks.mounts = callback - -- 直接发送请求到服务端,不需要注册前缀 - SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_MOUNTS", "WHISPER", UnitName("player")) - - -- 属性加成标题 - elseif command == "GET_ATTRIBUTES" then - SM_Collections.pendingCallbacks.attributes = callback - SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_ATTRIBUTES", "WHISPER", UnitName("player")) - - --小伙伴收藏 - elseif command == "GET_COMPANIONS" then - SM_Collections.pendingCallbacks.companions = callback - SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_COMPANIONS", "WHISPER", UnitName("player")) - - --卡牌收藏 - elseif command == "GET_CARDS" then - SM_Collections.pendingCallbacks.cards = callback - SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_CARDS", "WHISPER", UnitName("player")) - - --物品收藏 - elseif command == "GET_ITEMS" then - SM_Collections.pendingCallbacks.items = callback - SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_ITEMS", "WHISPER", UnitName("player")) - - -- 特定项目属性 - elseif command == "GET_ITEM_ATTRIBUTES" then - SM_Collections.pendingCallbacks.item_attributes = callback - local requestMsg = data.itemType .. "|" .. data.itemId - SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_ITEM_ATTRIBUTES|" .. requestMsg, "WHISPER", UnitName("player")) - end - -- 使用 OnUpdate 脚本替代 C_Timer - local timeoutFrame = CreateFrame("Frame") - local startTime = GetTime() - local timeoutSeconds = SM_Collections.Config.ServerTimeout / 1000 - - timeoutFrame:SetScript("OnUpdate", function(self, elapsed) - if GetTime() - startTime >= timeoutSeconds then - local callbackKey = command:lower():gsub("get_", "") - if SM_Collections.pendingCallbacks and SM_Collections.pendingCallbacks[callbackKey] then - print("服务端请求超时:", command) - if SM_Collections.Config.FallbackToLocal then - -- 回退到本地数据 - local localProvider = SM_Collections.LocalDataProvider:new() - if command == "GET_MOUNTS" then -- 坐骑 - localProvider:GetMounts(callback) - elseif command == "GET_ATTRIBUTES" then -- 属性加成标题 - localProvider:GetAttributes(callback) - elseif command == "GET_COMPANIONS" then --小伙伴收藏 - localProvider:GetCompanions(callback) - elseif command == "GET_CARDS" then --卡牌收藏 - localProvider:GetCards(callback) - elseif command == "GET_ITEMS" then --物品收藏 - localProvider:GetItems(callback) - end - else - callback({}) - end - SM_Collections.pendingCallbacks[callbackKey] = nil - end - self:SetScript("OnUpdate", nil) -- 停止定时器 - end - end) -end - --- 数据管理器 -SM_Collections.DataManager = {} - -function SM_Collections.DataManager:Initialize() - if SM_Collections.Config.UseServerData then - self.dataProvider = SM_Collections.ServerDataProvider:new() - print("使用服务端数据提供者") - else - self.dataProvider = SM_Collections.LocalDataProvider:new() - print("使用本地数据提供者") - end -end - -function SM_Collections.DataManager:GetMounts(callback) - self.dataProvider:GetMounts(callback) -end - -function SM_Collections.DataManager:GetCompanions(callback) - self.dataProvider:GetCompanions(callback) -end - -function SM_Collections.DataManager:GetCards(callback) - self.dataProvider:GetCards(callback) -end - -function SM_Collections.DataManager:GetItems(callback) - self.dataProvider:GetItems(callback) -end - -function SM_Collections.DataManager:GetAttributes(callback) - self.dataProvider:GetAttributes(callback) -end - -function SM_Collections.DataManager:GetAttributesForSpecificItem(itemId, itemType, callback) - self.dataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) -end - --- 添加坐骑数据(保留用于兼容性) -SM_Collections.Mounts = { - [458] = { 284, 2, 0, "Brown Horse", "A favorite among Stormwind's guards thanks to its patience and stamina.", 2, "|cFFFFD200Vendor: |rWorld Vendors|n|cFFFFD200Cost: |r1|TINTERFACE\\MONEYFRAME\\UI-GOLDICON.BLP:0|t" }, - [459] = { 4268, 2, 64, "Gray Wolf", "This breed of wolf prefers hunting in the fog, relying on its smoky hide to camouflage it from unsuspecting prey.", 2, "|cFFFFD200Vendor: |rOgunaro Wolfrunner|n|cFFFFD200Zone: |rOrgrimmar|n|cFFFFD200Cost: |r1|TINTERFACE\\MONEYFRAME\\UI-GOLDICON.BLP:0|t" }, - [468] = { 305, 2, 64, "White Stallion", "The powerful and unyielding white stallion features heavily in the myths of ancient human tribes.", 2, "|cFFFFD200Legacy|r" }, - [470] = { 308, 2, 0, "Black Stallion", "Rumored to be favored by SI:7 for night missions due to its dark coat.", 2, "|cFFFFD200Vendor: |rUnger Statforth|n|cFFFFD200Zone: |rWetlands|n|cFFFFD200Cost: |r1|TINTERFACE\\MONEYFRAME\\UI-GOLDICON.BLP:0|t" }, - [578] = { 356, 2, 64, "Black Wolf", "Can howl loudly enough to be heard for miles.", 2, "|cFFFFD200Vendor: |rOgunaro Wolfrunner|n|cFFFFD200Zone: |rOrgrimmar|n|cFFFFD200Cost: |r1|TINTERFACE\\MONEYFRAME\\UI-GOLDICON.BLP:0|t" }, -} - --- 获取坐骑信息 -function SM_Collections:GetMountInfo(spellID) - local info = self.Mounts[spellID] - if info then - return unpack(info, 1, 9) - end -end - --- 获取生物显示ID -function SM_Collections:GetCreatureDisplayID(itemID, itemType) - if itemType == "mount" then - local mountInfo = self:GetMountInfo(itemID) - if mountInfo then - return mountInfo -- 第一个返回值就是 creatureDisplayID - end - elseif itemType == "companion" then - local companionMap = { - -- 新的小伙伴映射 - [62508] = 33194, -- 丹莫罗熊宝宝 -> 熊的显示ID - [28871] = 16701, -- 仲夏之魂 -> 火元素显示ID - [13548] = 30379, -- 农场小鸡 -> 鸡的显示ID - [23811] = 14878, -- 加布林 - } - return companionMap[itemID] or itemID - elseif itemType == "card" then - local cardMap = { - [11502] = 11502, -- 拉格纳罗斯 - [24248] = 24248, -- 巫妖王 - [19299] = 19299, -- 死亡耳语者 - [32588] = 32588, -- 伊利丹 - } - return cardMap[itemID] or itemID - end - - return itemID -end - --- 创建主界面 -function SM_Collections:CreateMainFrame() - if self.MainFrame then - return self.MainFrame - end - - SM_Collections_Frame = CreateFrame("Frame", "SM_Collections_MainFrame", UIParent); - SM_Collections_Frame:SetSize(800, 540); - SM_Collections_Frame:SetPoint("CENTER", 0, 0); - SM_Collections_Frame_Texture = SM_Collections_Frame:CreateTexture(nil, 'OVERLAY') - SM_Collections_Frame_Texture:SetPoint('TOP') - SM_Collections_Frame_Texture:SetAllPoints(SM_Collections_Frame) - SM_Collections_Frame_Texture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\back") - - -- 左上角圆形头像/LOGO - local icon = SM_Collections_Frame:CreateTexture(nil, "ARTWORK") - icon:SetSize(80, 80) - icon:SetPoint("TOPLEFT", 5, -5) - SetPortraitToTexture(icon, "Interface\\ICONS\\INV_Misc_QuestionMark") - - -- 标题 - local title = SM_Collections_Frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge") - title:SetPoint("TOP", 0, -20) - title:SetText("我的收藏系统") - - -- 关闭按钮 - local closeBtn = CreateFrame("Button", "SM_CollectionsCloseBtn", SM_Collections_Frame, "UIPanelCloseButton") - closeBtn:SetSize(40, 40) - closeBtn:SetPoint("TOPRIGHT", 4, -8) - closeBtn:SetScript("OnClick", function() SM_Collections_Frame:Hide() end) - - -- 创建右侧面板容器 - local rightSidePanel = CreateFrame("Frame", "SM_CollectionsRightSidePanel", SM_Collections_Frame) - rightSidePanel:SetSize(190, 400) - rightSidePanel:SetPoint("TOPRIGHT", 10, -100) - SM_Collections_Frame.RightSidePanel = rightSidePanel - self.RightSidePanel = rightSidePanel - - -- 坐骑召唤、小伙伴召唤、卡牌召唤按钮 - rightSidePanel.CallButon = CreateFrame("Button", "SM_CollectionsRightSidePanelCallButon", rightSidePanel) - rightSidePanel.CallButon:SetSize(30, 30) - rightSidePanel.CallButon:SetPoint("TOPRIGHT", closeBtn, -20, -45) - rightSidePanel.CallButon:SetNormalTexture("Interface\\ICONS\\Ability_Mount_RidingHorse.blp") - rightSidePanel.CallButon:SetHighlightTexture("Interface\\ICONS\\Ability_Mount_RidingHorse.blp") - rightSidePanel.CallButon:SetPushedTexture("Interface\\ICONS\\Ability_Mount_RidingHorse.blp") - rightSidePanel.CallButon:SetScript("OnClick", function() print("召唤") end) - - -- 坐骑名称文本 - 使用自定义字体 - local MountNama = rightSidePanel:CreateFontString(nil, "OVERLAY") - MountNama:SetPoint("TOPLEFT", 5, 0) - MountNama:SetFontObject(titleFont) - MountNama:SetText("") - MountNama:SetJustifyH("LEFT") - MountNama:SetJustifyV("TOP") - MountNama:SetTextColor(230 / 255, 150 / 255, 0 / 255) - rightSidePanel.MountNama = MountNama -- 保存引用 - - -- 右上角介绍文本的框体 - local introFrame = CreateFrame("Frame", nil, rightSidePanel) - local width = MountNama:GetStringWidth() - introFrame:SetSize(width + 80, 80) - introFrame:SetPoint("TOPLEFT", MountNama, "BOTTOMLEFT", 0, -10) - - -- 介绍文本 - 使用自定义字体 - local introText = introFrame:CreateFontString(nil, "OVERLAY") - introText:SetPoint("TOPLEFT", 0, -5) - introText:SetJustifyH("LEFT") - introText:SetJustifyV("TOP") - introText:SetWidth(introFrame:GetWidth() - 20) - introText:SetWordWrap(true) - introText:SetFontObject(descFont) - local text = - "|cFFe59700成就:|r领导骑兵|r\r|cFFe59700类别:|r将军即使是龙族原住民协会的测试也证明,在确定白化公鸭是否与已知的蜻蜓有关方面没有定论。\r\r |cFFe59700--布雷安尼|r" - introText:SetText("") - introFrame:SetHeight(introText:GetStringHeight() + 20) - rightSidePanel.introText = introText -- 保存引用 - - -- 属性加成标题 - local AttributeBonusFrame = CreateFrame("Frame", "AttributeBonusFrame", introFrame) - AttributeBonusFrame:SetSize(120, 20) - AttributeBonusFrame:SetPoint("CENTER", introFrame, "CENTER", -12, -60) - AttributeBonusFrame:SetBackdrop({ bgFile = "Interface\\AddOns\\SM_CollectionSystem\\Textures\\AttributeBonusFrame" }) - AttributeBonusFrameText = AttributeBonusFrame:CreateFontString(nil, "OVERLAY") - AttributeBonusFrameText:SetPoint("CENTER", 0, 0) - AttributeBonusFrameText:SetFontObject(titleFont) - AttributeBonusFrameText:SetText("属性加成") - AttributeBonusFrameText:SetFont("Fonts\\ZYKai_T.ttf", 16, "MONOCHROME") - -- 属性加成框架初始隐藏 - AttributeBonusFrame:Hide() - rightSidePanel.AttributeBonusFrame = AttributeBonusFrame -- 保存引用 - - -- 拖拽功能 - SM_Collections_Frame:SetScript("OnMouseDown", function(self, button) - if button == "LeftButton" then - self:StartMoving() - end - end) - SM_Collections_Frame:SetScript("OnMouseUp", function(self, button) - if button == "LeftButton" then - self:StopMovingOrSizing() - end - end) - - -- 创建标签页 - self:CreateTabs(SM_Collections_Frame) - - -- 创建内容区域 - local contentFrame = CreateFrame("Frame", "SM_CollectionsContentFrame", SM_Collections_Frame) - contentFrame:SetPoint("TOPLEFT", 20, -80) - contentFrame:SetPoint("BOTTOMRIGHT", -20, 20) - SM_Collections_Frame.ContentFrame = contentFrame - - self.MainFrame = SM_Collections_Frame - return SM_Collections_Frame -end - --- 创建标签页 -function SM_Collections:CreateTabs(parent) - local tabs = {} - local tabNames = { "坐骑收藏", "小伙伴收藏", "卡牌收藏", "物品收藏" } - - for i = 1, 4 do - local tab = CreateFrame("Button", "SM_CollectionTab" .. i, parent, "CharacterFrameTabButtonTemplate") - tab:SetSize(120, 30) - tab:SetID(i) - - if i == 1 then - tab:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", 20, 5) - else - tab:SetPoint("LEFT", tabs[i - 1], "RIGHT", 5, 0) - end - - tab:SetText(tabNames[i]) - - tab:SetScript("OnClick", function(self) - SM_Collections:UpdateTabAppearance(self:GetID()) - SM_Collections:ShowTab(self:GetID()) - PlaySound("igCharacterInfoTab") - end) - - tabs[i] = tab - end - - parent.tabs = tabs - parent.numTabs = 4 - parent.selectedTab = 1 - - self:UpdateTabAppearance(1) -end - --- 更新标签页外观 -function SM_Collections:UpdateTabAppearance(selectedTab) - if not self.MainFrame or not self.MainFrame.tabs then return end - - for i = 1, self.MainFrame.numTabs do - local tab = self.MainFrame.tabs[i] - if tab then - if i == selectedTab then - tab:SetAlpha(1.0) - if tab.GetFontString and tab:GetFontString() then - tab:GetFontString():SetTextColor(1, 1, 1) - end - else - tab:SetAlpha(0.7) - if tab.GetFontString and tab:GetFontString() then - tab:GetFontString():SetTextColor(0.7, 0.7, 0.7) - end - end - end - end - - self.MainFrame.selectedTab = selectedTab - self.CurrentTab = selectedTab -end - --- 显示指定标签页 -function SM_Collections:ShowTab(tabId) - self:UpdateTabAppearance(tabId) - - -- 在ShowTab函数开始处添加 - if self.MainFrame and self.MainFrame.RightSidePanel then - -- 清空模型框右侧面板内容 - if self.MainFrame.RightSidePanel.MountNama then - self.MainFrame.RightSidePanel.MountNama:SetText("") - end - if self.MainFrame.RightSidePanel.introText then - self.MainFrame.RightSidePanel.introText:SetText("") - end - if self.MainFrame.RightSidePanel.AttributeBonusFrame then - self.MainFrame.RightSidePanel.AttributeBonusFrame:Hide() - end - end - - -- 更彻底地清空当前内容 - if self.CurrentPanel then - self.CurrentPanel:Hide() - local children = { self.CurrentPanel:GetChildren() } - for _, child in ipairs(children) do - child:Hide() - end - self.CurrentPanel = nil - end - - -- 清理内容框架中的所有子元素 - if self.MainFrame and self.MainFrame.ContentFrame then - local children = { self.MainFrame.ContentFrame:GetChildren() } - for _, child in ipairs(children) do - child:Hide() - end - end - - -- 【新增】根据标签页控制右侧面板的显示/隐藏 - if self.MainFrame and self.MainFrame.RightSidePanel then - if tabId == 4 then -- 物品收藏页面 - self.MainFrame.RightSidePanel:Hide() - else -- 其他页面(坐骑、小伙伴、卡牌收藏) - self.MainFrame.RightSidePanel:Show() - end - end - - -- 根据标签页显示对应内容 - if tabId == 1 then - self:ShowMounts() - elseif tabId == 2 then - self:ShowCompanions() - elseif tabId == 3 then - self:ShowCards() - elseif tabId == 4 then - self:ShowItems() - end -end - --- 创建左右分栏面板 -function SM_Collections:CreateSplitPanel(parent, data, itemType) - local panel = CreateFrame("Frame", "SM_CollectionsPanel", parent) - panel:SetAllPoints() - - -- 左侧列表 - local listFrame = CreateFrame("Frame", "SM_CollectionslistFrame", panel) - listFrame:SetSize(220, 410) - listFrame:SetPoint("TOPLEFT", 5, -13) - listFrame:SetBackdrop({ - bgFile = "Interface\\AddOns\\SM_CollectionSystem\\Textures\\liebiaoditu" - }) - - local scrollFrameName = "SM_ScrollFrame_" .. itemType .. "_" .. math.random(1000, 9999) - local scrollFrame = CreateFrame("ScrollFrame", scrollFrameName, listFrame, "UIPanelScrollFrameTemplate") - scrollFrame:SetSize(200, 415) - scrollFrame:SetPoint("TOPLEFT", 5, 2) - - -- 滚动条装饰 - local BackgroundFrame = CreateFrame("Frame", "SM_CollectionsOverlayFrame", scrollFrame) - BackgroundFrame:SetSize(25, 410) - BackgroundFrame:SetPoint("RIGHT", scrollFrame, "RIGHT", 25.5, 1) - BackgroundFrame:SetFrameLevel(scrollFrame:GetFrameLevel() + 1) - local ScrollBarBackground = BackgroundFrame:CreateTexture(nil, "BACKGROUND") - ScrollBarBackground:SetSize(25, 410) - ScrollBarBackground:SetPoint("CENTER", BackgroundFrame, "CENTER", 0, 0) - ScrollBarBackground:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\cooldown") - - local overlayFrame = CreateFrame("Frame", "SM_CollectionsOverlayFrame", BackgroundFrame) - overlayFrame:SetSize(30, 420) - overlayFrame:SetPoint("CENTER", BackgroundFrame, "CENTER", 0, 1) - overlayFrame:SetFrameLevel(BackgroundFrame:GetFrameLevel() + 10) - local scrollBarOverlay = overlayFrame:CreateTexture(nil, "OVERLAY") - scrollBarOverlay:SetAllPoints(overlayFrame) - scrollBarOverlay:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\ScrollFrame") - scrollBarOverlay:SetTexCoord(0, 1, 0, 1) - scrollBarOverlay:SetVertexColor(1, 1, 1, 1) - scrollBarOverlay:SetBlendMode("BLEND") - - local scrollChild = CreateFrame("Frame", "SM_CollectionsScrollChild", scrollFrame) - scrollChild:SetSize(300, 1) - scrollFrame:SetScrollChild(scrollChild) - - -- 右侧模型显示 - local modelFrame = CreateFrame("Frame", "SM_CollectionsModelFrame", parent) - modelFrame:SetSize(380, 410) - modelFrame:SetPoint("CENTER", 30, 0) - - -- 3D模型 - local model = CreateFrame("PlayerModel", "SM_CollectionsModel", modelFrame) - model:SetSize(350, 350) - model:SetPoint("TOP", 0, -30) - model:SetCamera(0) - model:SetFacing(0) - model.zoomLevel = 0 - model:SetPosition(0, 0, 0) - - -- 模型旋转功能 - model:EnableMouse(true) - model:SetScript("OnMouseDown", function(self, button) - if button == "LeftButton" then - self.isRotating = true - self.lastX = GetCursorPosition() - end - end) - model:SetScript("OnMouseUp", function(self, button) - if button == "LeftButton" then - self.isRotating = false - end - end) - - local ROTATE_SPEED = math.rad(90) - model.isRotatingLeft = false - model.isRotatingRight = false - - -- 左旋转按钮 - local rotateLeftBtn = CreateFrame("Button", nil, modelFrame) - rotateLeftBtn:SetSize(32, 32) - rotateLeftBtn:SetPoint("BOTTOM", modelFrame, "BOTTOM", -100, 10) - rotateLeftBtn:SetNormalTexture("Interface\\Buttons\\UI-RotationLeft-Button-Up") - rotateLeftBtn:SetPushedTexture("Interface\\Buttons\\UI-RotationLeft-Button-Down") - rotateLeftBtn:SetHighlightTexture("Interface\\Buttons\\UI-RotationLeft-Button-Highlight") - rotateLeftBtn:SetScript("OnMouseDown", function() model.isRotatingLeft = true end) - rotateLeftBtn:SetScript("OnMouseUp", function() model.isRotatingLeft = false end) - rotateLeftBtn:HookScript("OnLeave", function() model.isRotatingLeft = false end) - - -- 右旋转按钮 - local rotateRightBtn = CreateFrame("Button", nil, modelFrame) - rotateRightBtn:SetSize(32, 32) - rotateRightBtn:SetPoint("BOTTOM", modelFrame, "BOTTOM", 100, 10) - rotateRightBtn:SetNormalTexture("Interface\\Buttons\\UI-RotationRight-Button-Up") - rotateRightBtn:SetPushedTexture("Interface\\Buttons\\UI-RotationRight-Button-Down") - rotateRightBtn:SetHighlightTexture("Interface\\Buttons\\UI-RotationRight-Button-Highlight") - rotateRightBtn:SetScript("OnMouseDown", function() model.isRotatingRight = true end) - rotateRightBtn:SetScript("OnMouseUp", function() model.isRotatingRight = false end) - rotateRightBtn:HookScript("OnLeave", function() model.isRotatingRight = false end) - - -- 旋转更新 - model:SetScript("OnUpdate", function(self, elapsed) - if self.isRotating then - local x = GetCursorPosition() - local delta = (x - (self.lastX or x)) * 0.01 - self.lastX = x - self:SetFacing(self:GetFacing() + delta) - end - if self.isRotatingLeft then - self:SetFacing(self:GetFacing() + ROTATE_SPEED * elapsed) - elseif self.isRotatingRight then - self:SetFacing(self:GetFacing() - ROTATE_SPEED * elapsed) - end - end) - - -- UI元素 - local nameText = modelFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge") - nameText:SetPoint("BOTTOM", 0, 20) - nameText:SetTextColor(1, 1, 1) - - local descText = modelFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") - descText:SetSize(320, 60) - descText:SetPoint("BOTTOM", 0, 20) - descText:SetJustifyH("CENTER") - - panel.listFrame = listFrame - panel.scrollChild = scrollChild - panel.modelFrame = modelFrame - panel.model = model - panel.nameText = nameText - panel.descText = descText - - self:CreateListItems(scrollChild, data, itemType, model, nameText, descText) - return panel -end - --- 更新模型右侧面板信息 -function SM_Collections:UpdateRightPanel(selectedItem, itemType) - if not self.MainFrame or not self.MainFrame.RightSidePanel then - return - end - - local rightPanel = self.MainFrame.RightSidePanel - - -- 更新名称 - if rightPanel.MountNama then - rightPanel.MountNama:SetText(selectedItem.name or "") - end - - -- 更新介绍 - if rightPanel.introText then - rightPanel.introText:SetText(selectedItem.description or "") - end - - -- 更新属性加成(对所有类型都显示) - if rightPanel.AttributeBonusFrame then - rightPanel.AttributeBonusFrame:Show() - self:UpdateAttributesForItem(selectedItem, rightPanel.AttributeBonusFrame, itemType) - end -end - --- 获取特定项目的属性加成 -function SM_Collections:GetAttributesForItem(item, callback, itemType) - -- 使用新的特定项目属性获取方法 - SM_Collections.DataManager:GetAttributesForSpecificItem(item.id, itemType, function(attributes) - callback(attributes) - end) -end - --- 更新特定项目的属性显示 -function SM_Collections:UpdateAttributesForItem(item, parentFrame, itemType) - -- 清除现有属性按钮 - local children = { parentFrame:GetChildren() } - for _, child in ipairs(children) do - if child:GetName() and string.find(child:GetName(), "SM_CollectionsAttributeutton") then - child:Hide() - end - end - - -- 获取并显示新属性 - self:GetAttributesForItem(item, function(attributes) - if #attributes == 0 then - -- 如果没有特定属性,隐藏属性框架 - parentFrame:Hide() - return - end - - parentFrame:Show() - local buttonH = 150 - local buttonW = 20 - - for i, attribute in ipairs(attributes) do - local AttributeName = attribute.Name - local AttributeValue = attribute.value - local isPositive = attribute.isPositive - - local button = CreateFrame("Button", "SM_CollectionsAttributeutton" .. i, parentFrame) - button:SetSize(buttonH, buttonW) - button:SetNormalTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\AttributeuttonTexture") - button:SetPoint("TOPLEFT", -15, -30 - (i - 1) * (buttonW)) - - -- 创建属性文本... - local nameText = button:CreateFontString(nil, "OVERLAY") - nameText:SetPoint("LEFT", 5, 0) - nameText:SetFont("Fonts\\ZYKai_T.ttf", 10, "MONOCHROME") - nameText:SetText(AttributeName) - nameText:SetTextColor(1, 1, 1) - - local valueText = button:CreateFontString(nil, "OVERLAY") - valueText:SetPoint("RIGHT", -5, 0) - valueText:SetFont("Fonts\\ZYKai_T.ttf", 10, "MONOCHROME") - local formattedValue = isPositive and ("+ " .. AttributeValue) or ("- " .. AttributeValue) - valueText:SetText(formattedValue) - valueText:SetTextColor(isPositive and 0 or 1, isPositive and 1 or 0, 0) - - button:Show() - end - end, itemType) -end - --- 创建列表项 -function SM_Collections:CreateListItems(parent, data, itemType, model, nameText, descText) - local buttonW = 170 - local buttonHeight = 40 - local spacing = 2 - local iconSize = 30 - - -- 根据itemType调整按钮大小 - if itemType == "card" then - buttonW = 200 -- 卡牌收藏使用更大的按钮 - end - - for i, item in ipairs(data) do - local button = CreateFrame("Button", "Collectionsbutton" .. i, parent) - button:SetSize(buttonW, buttonHeight) - button:SetPoint("TOPLEFT", 30, -(i - 1) * (buttonHeight + spacing)) - button:SetNormalTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\liebiaoditu_kuang_A") - button:SetHighlightTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\liebiaoditu_kuang_B") - - -- 只为坐骑收藏和小伙伴收藏创建ButtonIcon - local ButtonIcon = nil - if itemType == "mount" or itemType == "companion" then - ButtonIcon = CreateFrame("Button", "CollectionsButtonIcon" .. i, button) - ButtonIcon:SetSize(iconSize, iconSize) - ButtonIcon:SetPoint("RIGHT", button, "LEFT", 0, 0) - - -- 坐骑和小伙伴都使用技能图标 - local name, rank, icon = GetSpellInfo(item.id) - if icon then - ButtonIcon:SetNormalTexture(icon) - ButtonIcon:SetHighlightTexture(icon) - else - ButtonIcon:SetNormalTexture("Interface\\Icons\\INV_Misc_QuestionMark") - ButtonIcon:SetHighlightTexture("Interface\\Icons\\INV_Misc_QuestionMark") - end - ButtonIcon:SetFrameLevel(button:GetFrameLevel() + 1) - - -- 设置图标的工具提示 - ButtonIcon:SetScript("OnEnter", function() - GameTooltip:SetOwner(ButtonIcon, "ANCHOR_RIGHT") - GameTooltip:SetHyperlink("spell:" .. item.id) - GameTooltip:Show() - end) - ButtonIcon:SetScript("OnLeave", function() GameTooltip:Hide() end) - - ButtonIcon:Show() - end - - -- 创建文本,根据是否有图标调整位置 - local text = button:CreateFontString(nil, "OVERLAY", "GameFontNormal") - if itemType == "card" then - button:SetPoint("TOPLEFT", 0, -(i - 1) * (buttonHeight + spacing)) - text:SetPoint("CENTER", 0, 0) - else - -- 有图标的情况,文本左对齐 - text:SetPoint("LEFT", 10, 0) - end - text:SetText(item.name) - text:SetTextColor(item.obtained and 1 or 0.5, item.obtained and 1 or 0.5, item.obtained and 1 or 0.5) - - button:SetScript("OnClick", function() - nameText:SetText(item.name) - descText:SetText(item.description) - local creatureDisplayID = self:GetCreatureDisplayID(item.id, itemType) - if creatureDisplayID and creatureDisplayID > 0 then - model:Hide() - model:SetPosition(0, 0, 0) - model.zoomLevel = 0 - model:Show() - model:SetCreature(creatureDisplayID) - print("creatureDisplayID= ", creatureDisplayID) - end - -- 新增:更新右侧面板 - self:UpdateRightPanel(item, itemType) - end) - - button:SetScript("OnEnter", function() - nameText:SetText(item.obtained and item.name or (item.name .. " (未获得)")) - nameText:SetTextColor(item.obtained and 1 or 0.8, item.obtained and 1 or 0.8, item.obtained and 1 or 0.8) - end) - - button:Show() - end - - local totalHeight = #data * (buttonHeight + spacing) - parent:SetHeight(math.max(totalHeight, 1)) -end - --- 修改后的显示坐骑函数 - 使用数据管理器 -function SM_Collections:ShowMounts() - print("显示坐骑") - SM_Collections.DataManager:GetMounts(function(mounts) - local panel = self:CreateSplitPanel(self.MainFrame.ContentFrame, mounts, "mount") - - local firstObtained = nil - for _, mount in ipairs(mounts) do - if mount.obtained then - firstObtained = mount - break - end - end - - if firstObtained then - panel.nameText:SetText(firstObtained.name) - panel.descText:SetText(firstObtained.description) - local creatureDisplayID = self:GetCreatureDisplayID(firstObtained.id, "mount") - if creatureDisplayID and creatureDisplayID > 0 then - panel.model:Hide() - panel.model:SetPosition(0, 0, 0) - panel.model.zoomLevel = 0 - panel.model:Show() - panel.model:SetCreature(creatureDisplayID) - print("显示坐骑= " .. creatureDisplayID) - end - end - - panel:Show() - self.CurrentPanel = panel - end) -end - --- 修改后的显示小伙伴函数 - 使用数据管理器 -function SM_Collections:ShowCompanions() - print("显示小伙伴") - SM_Collections.DataManager:GetCompanions(function(companions) - local panel = self:CreateSplitPanel(self.MainFrame.ContentFrame, companions, "companion") - - local firstObtained = nil - for _, companion in ipairs(companions) do - if companion.obtained then - firstObtained = companion - break - end - end - - if firstObtained then - panel.nameText:SetText(firstObtained.name) - panel.descText:SetText(firstObtained.description) - - local creatureDisplayID = self:GetCreatureDisplayID(firstObtained.id, "companion") - if creatureDisplayID and creatureDisplayID > 0 then - panel.model:Hide() - panel.model:SetPosition(0, 0, 0) - panel.model.zoomLevel = 0 - panel.model:Show() - panel.model:SetCreature(creatureDisplayID) - print("显示小伙伴= " .. creatureDisplayID) - end - end - - panel:Show() - self.CurrentPanel = panel - end) -end - --- 显示卡牌收藏 -function SM_Collections:ShowCards() - print("显示卡牌收藏") - SM_Collections.DataManager:GetCards(function(cards) - local panel = self:CreateSplitPanel(self.MainFrame.ContentFrame, cards, "card") - - local firstObtained = nil - for _, card in ipairs(cards) do - if card.obtained then - firstObtained = card - break - end - end - - if firstObtained then - panel.nameText:SetText(firstObtained.name) - panel.descText:SetText(firstObtained.description) - - local creatureDisplayID = self:GetCreatureDisplayID(firstObtained.id, "card") - if creatureDisplayID and creatureDisplayID > 0 then - panel.model:Hide() - panel.model:SetPosition(0, 0, 0) - panel.model.zoomLevel = 0 - panel.model:Show() - panel.model:SetCreature(creatureDisplayID) - print("显示卡牌收藏= " .. creatureDisplayID) - end - end - - panel:Show() - self.CurrentPanel = panel - end) -end - --- 修改后的显示物品函数 - 使用数据管理器 -function SM_Collections:ShowItems() - print("显示物品函数") - SM_Collections.DataManager:GetItems(function(items) - local panel = CreateFrame("Frame", "SM_CollectionsItemsPanel", self.MainFrame.ContentFrame) - panel:SetAllPoints() - - panel:SetBackdrop({ - bgFile = "Interface\\AddOns\\SM_CollectionSystem\\Interface\\DialogFrame\\UI-DialogBox-Background", - edgeFile = "Interface\\AddOns\\SM_CollectionSystem\\Interface\\DialogFrame\\UI-DialogBox-Border", - tile = true, - tileSize = 32, - edgeSize = 32, - insets = { left = 11, right = 12, top = 12, bottom = 11 } - }) - - local scrollFrameName = "SM_ItemScrollFrame_" .. math.random(1000, 9999) - local scrollFrame = CreateFrame("ScrollFrame", scrollFrameName, panel, "UIPanelScrollFrameTemplate") - scrollFrame:SetSize(740, 480) - scrollFrame:SetPoint("TOPLEFT", 10, -10) - - local scrollChild = CreateFrame("Frame", "SM_CollectionsItemsScrollChild", scrollFrame) - scrollChild:SetSize(720, 1) - scrollFrame:SetScrollChild(scrollChild) - - self:CreateItemGrid(scrollChild, items) - panel:Show() - self.CurrentPanel = panel - end) -end - -function SM_Collections.LocalDataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) - -- 根据不同类型和ID返回不同属性 - local attributeMap = { - mount = { - [458] = { -- 棕色马 - { Name = "移动速度", value = 60, isPositive = true }, - { Name = "耐力", value = 50, isPositive = true }, - { Name = "载重", value = 100, isPositive = true }, - }, - [459] = { -- 灰狼 - { Name = "移动速度", value = 100, isPositive = true }, - { Name = "敏捷", value = 80, isPositive = true }, - { Name = "夜视", value = 1, isPositive = true }, - }, - [468] = { -- 白色骏马 - { Name = "移动速度", value = 100, isPositive = true }, - { Name = "威望", value = 25, isPositive = true }, - { Name = "圣光抗性", value = 15, isPositive = true }, - }, - }, - companion = { - [62508] = { -- 丹莫罗熊宝宝 - { Name = "忠诚度", value = 100, isPositive = true }, - { Name = "战斗辅助", value = 20, isPositive = true }, - { Name = "寻宝能力", value = 15, isPositive = true }, - }, - [28871] = { -- 仲夏之魂 - { Name = "火焰抗性", value = 50, isPositive = true }, - { Name = "法力恢复", value = 10, isPositive = true }, - { Name = "照明", value = 1, isPositive = true }, - }, - }, - card = { - [11502] = { -- 拉格纳罗斯 - { Name = "火焰伤害", value = 500, isPositive = true }, - { Name = "法术强度", value = 200, isPositive = true }, - { Name = "冰霜抗性", value = 75, isPositive = true }, - }, - [24248] = { -- 巫妖王阿尔萨斯 - { Name = "冰霜伤害", value = 600, isPositive = true }, - { Name = "亡灵控制", value = 100, isPositive = true }, - { Name = "生命汲取", value = 50, isPositive = true }, - }, - } - } - - local attributes = attributeMap[itemType] and attributeMap[itemType][itemId] or {} - - if SM_Collections.Config.Debug then - print("LocalDataProvider: 为", itemType, itemId, "返回", #attributes, "个特定属性") - end - - callback(attributes) -end - --- 修改后的创建物品网格函数 -function SM_Collections:CreateItemGrid(parent, items) - local buttonSize = 40 - local spacing = 5 - local buttonsPerRow = 16 - - for i, item in ipairs(items) do - local button = CreateFrame("Button", "SM_CollectionsItemGridButton", parent) - button:SetSize(buttonSize, buttonSize) - - local row = math.floor((i - 1) / buttonsPerRow) - local col = (i - 1) % buttonsPerRow - button:SetPoint("TOPLEFT", 10 + col * (buttonSize + spacing), -10 + -row * (buttonSize + spacing)) - - local texture = button:CreateTexture(nil, "ARTWORK") - texture:SetAllPoints() - - local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, itemTexture = - GetItemInfo(item.id) - texture:SetTexture(itemTexture) - - -- 根据获得状态设置颜色 - if not item.obtained then - texture:SetDesaturated(true) -- 灰色效果 - else - texture:SetDesaturated(false) -- 正常颜色 - end - - -- 鼠标悬停效果 - button:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square") - - -- 点击事件 - button:HookScript("OnClick", function() - if item.obtained then - print("选择了物品: " .. item.name) - else - print("您还没有获得: " .. item.name) - end - end) - - -- 工具提示 - button:HookScript("OnEnter", function(self) - GameTooltip:SetOwner(button, "ANCHOR_RIGHT") - GameTooltip:SetText(item.name) - GameTooltip:SetHyperlink('Hitem:' .. item.id) - GameTooltip:Show() - end) - - button:HookScript("OnLeave", function() - GameTooltip:Hide() - end) - - button:Show() - end - - -- 更新滚动区域高度 - local rows = math.ceil(#items / buttonsPerRow) - local totalHeight = rows * (buttonSize + spacing) - parent:SetHeight(math.max(totalHeight, 1)) -end - --- 斜杠命令 -SLASH_SM_COLLECTIONS1 = "/smcollections" -SLASH_SM_COLLECTIONS2 = "/sm收藏" -SlashCmdList["SM_COLLECTIONS"] = function() - -- 确保只创建一次主界面 - if not SM_Collections.MainFrame then - SM_Collections:CreateMainFrame() - end - - -- 简化显示/隐藏逻辑 - if SM_Collections.MainFrame:IsVisible() then - SM_Collections.MainFrame:Hide() - else - SM_Collections.MainFrame:Show() - -- 只在首次显示时设置默认标签页 - if not SM_Collections.CurrentTab then - SM_Collections:ShowTab(1) - end - end -end - --- 处理坐骑数据 -function SM_Collections:HandleMountsData(msg) - local data = self:MessageSplit(msg, "|") - local mounts = {} - - -- 解析格式:id|name|description|obtained|id|name|description|obtained... - for i = 1, #data, 4 do - if data[i] and data[i + 1] and data[i + 2] and data[i + 3] then - table.insert(mounts, { - id = tonumber(data[i]), - name = data[i + 1], - description = data[i + 2], - obtained = data[i + 3] == "1" - }) - end - end - - -- 触发回调 - if self.pendingCallbacks and self.pendingCallbacks.mounts then - self.pendingCallbacks.mounts(mounts) - self.pendingCallbacks.mounts = nil - end -end - --- 处理属性数据 -function SM_Collections:HandleAttributesData(msg) - local data = self:MessageSplit(msg, "|") - local attributes = {} - - -- 解析格式:name|value|isPositive|name|value|isPositive... - for i = 1, #data, 3 do - if data[i] and data[i + 1] and data[i + 2] then - table.insert(attributes, { - Name = data[i], - value = tonumber(data[i + 1]), - isPositive = data[i + 2] == "1" - }) - end - end - - if self.pendingCallbacks and self.pendingCallbacks.attributes then - self.pendingCallbacks.attributes(attributes) - self.pendingCallbacks.attributes = nil - end -end - --- 消息处理函数 -function SM_Collections_MessageEvent(self, event, packet, msg, type, sender) - if event == 'CHAT_MSG_ADDON' then - -- 坐骑数据响应 - if packet == 'SM_S_COLLECTIONS_MOUNTS' then - SM_Collections:HandleMountsData(msg) - - -- 小伙伴数据响应 - elseif packet == 'SM_S_COLLECTIONS_COMPANIONS' then - SM_Collections:HandleCompanionsData(msg) - - -- 卡牌数据响应 - elseif packet == 'SM_S_COLLECTIONS_CARDS' then - SM_Collections:HandleCardsData(msg) - - -- 物品数据响应 - elseif packet == 'SM_S_COLLECTIONS_ITEMS' then - SM_Collections:HandleItemsData(msg) - - -- 属性数据响应 - elseif packet == 'SM_S_COLLECTIONS_ATTRIBUTES' then - SM_Collections:HandleAttributesData(msg) - end - end -end - --- 事件监听框架 -local SM_Collections_EventFrame = CreateFrame('Frame', 'SM_Collections_EventFrame') -SM_Collections_EventFrame:RegisterEvent('CHAT_MSG_ADDON') -SM_Collections_EventFrame:RegisterEvent('ADDON_LOADED') - -SM_Collections_EventFrame:SetScript('OnEvent', function(self, event, ...) - if event == 'ADDON_LOADED' then - local addonName = ... - if addonName == "SM_CollectionSystem" then - -- 初始化数据管理器 - SM_Collections.DataManager:Initialize() - print("SM收藏系统已加载!使用 /smcollections 打开界面") - print("数据源模式:", SM_Collections.Config.UseServerData and "服务端" or "本地") - end - elseif event == 'CHAT_MSG_ADDON' then - -- 调用消息处理函数 - SM_Collections_MessageEvent(self, event, ...) - end -end) - print("收藏系统结束") diff --git a/SM_CollectionSystem.toc b/SM_CollectionSystem.toc index 02f858c..545a174 100644 --- a/SM_CollectionSystem.toc +++ b/SM_CollectionSystem.toc @@ -6,5 +6,10 @@ ################################ #SM_CollectionSystem.xml -CreatureDisplay.lua -SM_CollectionSystem.lua \ No newline at end of file +SM_CollectionSystem.lua +SM_DataProvider.lua +SM_UI_MainFrame.lua +SM_UI_SplitPanel.lua +SM_Utils.lua +SM_Events.lua +CreatureDisplay.lua \ No newline at end of file diff --git a/SM_DataProvider.lua b/SM_DataProvider.lua new file mode 100644 index 0000000..4de9d30 --- /dev/null +++ b/SM_DataProvider.lua @@ -0,0 +1,348 @@ +-- SM_DataProvider.lua + +-- 数据提供者基类 +SM_Collections.DataProvider = {} +function SM_Collections.DataProvider:new() + local obj = {} + setmetatable(obj, self) + self.__index = self + return obj +end +function SM_Collections.DataProvider:GetMounts(callback) error("GetMounts must be implemented by subclass") end +function SM_Collections.DataProvider:GetCompanions(callback) error("GetCompanions must be implemented by subclass") end +function SM_Collections.DataProvider:GetCards(callback) error("GetCards must be implemented by subclass") end +function SM_Collections.DataProvider:GetItems(callback) error("GetItems must be implemented by subclass") end +function SM_Collections.DataProvider:GetAttributes(callback) error("GetAttributes must be implemented by subclass") end +function SM_Collections.DataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) error("GetAttributesForSpecificItem must be implemented by subclass") end + +-- 本地数据提供者 +SM_Collections.LocalDataProvider = SM_Collections.DataProvider:new() + +function SM_Collections.LocalDataProvider:GetMounts(callback) + local mounts = { + { id = 458, name = "棕色马", description = "暴风城卫兵的最爱", obtained = true }, + { id = 459, name = "灰狼", description = "喜欢在雾中狩猎的狼", obtained = true }, + { id = 468, name = "白色骏马", description = "强大不屈的白色骏马", obtained = false }, + { id = 470, name = "黑色骏马", description = "据说SI:7夜间任务的首选", obtained = true }, + { id = 578, name = "黑狼", description = "嚎叫声能传播数英里", obtained = false }, + { id = 468, name = "白色骏马", description = "强大不屈的白色骏马", obtained = false }, + { id = 470, name = "黑色骏马", description = "据说SI:7夜间任务的首选", obtained = true }, + { id = 578, name = "黑狼", description = "嚎叫声能传播数英里", obtained = false }, + { id = 458, name = "棕色马", description = "暴风城卫兵的最爱", obtained = true }, + { id = 458, name = "棕色马", description = "暴风城卫兵的最爱", obtained = true }, + { id = 459, name = "灰狼", description = "喜欢在雾中狩猎的狼", obtained = true }, + { id = 468, name = "白色骏马", description = "强大不屈的白色骏马", obtained = false }, + { id = 470, name = "黑色骏马", description = "据说SI:7夜间任务的首选", obtained = true }, + { id = 578, name = "黑狼", description = "嚎叫声能传播数英里", obtained = false }, + { id = 468, name = "白色骏马", description = "强大不屈的白色骏马", obtained = false }, + { id = 470, name = "黑色骏马", description = "据说SI:7夜间任务的首选", obtained = true }, + { id = 578, name = "黑狼", description = "嚎叫声能传播数英里", obtained = false }, + { id = 458, name = "棕色马", description = "暴风城卫兵的最爱", obtained = true }, + } + if SM_Collections.Config.Debug then + print("LocalDataProvider: 返回", #mounts, "个坐骑") + end + callback(mounts) +end + +function SM_Collections.LocalDataProvider:GetCompanions(callback) + local companions = { + { id = 62508, name = "丹莫罗熊宝宝", description = "一只可爱的小猫", obtained = true }, + { id = 28871, name = "仲夏之魂", description = "一只忠诚的小狗", obtained = false }, + { id = 13548, name = "农场小鸡", description = "一只活泼的兔子", obtained = true }, + { id = 23811, name = "冬天爷爷的小助手", description = "一只会唱歌的鸟", obtained = false }, + } + callback(companions) +end + +function SM_Collections.LocalDataProvider:GetCards(callback) + local cards = { + { id = 11502, name = "拉格纳罗斯", description = "火焰之王", obtained = true }, + { id = 24248, name = "巫妖王阿尔萨斯", description = "亡灵天灾的领袖", obtained = false }, + { id = 19299, name = "死亡耳语者", description = "毁灭者", obtained = true }, + { id = 32588, name = "伊利丹·怒风", description = "背叛者", obtained = false }, + } + callback(cards) +end + +function SM_Collections.LocalDataProvider:GetItems(callback) + local items = { + { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, + { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, + { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, + { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, + { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, + { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, + { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, + { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, + { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, + { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, + { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, + { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, + { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, + { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, + { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, + { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, + { id = 33138, name = "秘法刀石", icon = "Interface\\Icons\\INV_Sword_04", obtained = true }, + { id = 33129, name = "菲纳特的爆竹", icon = "Interface\\Icons\\INV_Shield_05", obtained = false }, + { id = 33132, name = "精致焰红石", icon = "Interface\\Icons\\INV_Helmet_01", obtained = true }, + { id = 33133, name = "胡里奥之心", icon = "Interface\\Icons\\INV_Chest_Plate01", obtained = false }, + } + callback(items) +end + +function SM_Collections.LocalDataProvider:GetAttributes(callback) + local attributes = { + { Name = "生命值", value = 999, isPositive = true }, + { Name = "近战攻强", value = 999, isPositive = true }, + { Name = "法术强度", value = 999, isPositive = true }, + { Name = "暴击等级", value = 999, isPositive = true }, + { Name = "造成奥术伤害", value = 999, isPositive = true }, + { Name = "造成火焰伤害", value = 999, isPositive = true }, + { Name = "受到所有伤害", value = 999, isPositive = false }, + { Name = "造成暴击伤害", value = 999, isPositive = true }, + { Name = "造成所有伤害", value = 999, isPositive = true }, + { Name = "治疗效果", value = 999, isPositive = true }, + } + callback(attributes) +end + +function SM_Collections.LocalDataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) + local attributeMap = { + mount = { + [458] = { + { Name = "移动速度", value = 60, isPositive = true }, + { Name = "耐力", value = 50, isPositive = true }, + { Name = "载重", value = 100, isPositive = true }, + }, + [459] = { + { Name = "移动速度", value = 100, isPositive = true }, + { Name = "敏捷", value = 80, isPositive = true }, + { Name = "夜视", value = 1, isPositive = true }, + }, + [468] = { + { Name = "移动速度", value = 100, isPositive = true }, + { Name = "威望", value = 25, isPositive = true }, + { Name = "圣光抗性", value = 15, isPositive = true }, + }, + }, + companion = { + [62508] = { + { Name = "忠诚度", value = 100, isPositive = true }, + { Name = "战斗辅助", value = 20, isPositive = true }, + { Name = "寻宝能力", value = 15, isPositive = true }, + }, + [28871] = { + { Name = "火焰抗性", value = 50, isPositive = true }, + { Name = "法力恢复", value = 10, isPositive = true }, + { Name = "照明", value = 1, isPositive = true }, + }, + }, + card = { + [11502] = { + { Name = "火焰伤害", value = 500, isPositive = true }, + { Name = "法术强度", value = 200, isPositive = true }, + { Name = "冰霜抗性", value = 75, isPositive = true }, + }, + [24248] = { + { Name = "冰霜伤害", value = 600, isPositive = true }, + { Name = "亡灵控制", value = 100, isPositive = true }, + { Name = "生命汲取", value = 50, isPositive = true }, + }, + } + } + local attributes = attributeMap[itemType] and attributeMap[itemType][itemId] or {} + if SM_Collections.Config.Debug then + print("LocalDataProvider: 为", itemType, itemId, "返回", #attributes, "个特定属性") + end + callback(attributes) +end + +-- 服务端数据提供者 +SM_Collections.ServerDataProvider = SM_Collections.DataProvider:new() + +function SM_Collections.ServerDataProvider:GetMounts(callback) + self:SendServerRequest("GET_MOUNTS", {}, function(response) + if response and response.success then + if SM_Collections.Config.Debug then + print("ServerDataProvider: 从服务端获取到", #response.data, "个坐骑") + end + callback(response.data) + else + if SM_Collections.Config.FallbackToLocal then + print("服务端获取坐骑失败,回退到本地数据") + SM_Collections.LocalDataProvider:GetMounts(callback) + else + callback({}) + end + end + end) +end + +function SM_Collections.ServerDataProvider:GetCompanions(callback) + self:SendServerRequest("GET_COMPANIONS", {}, function(response) + if response and response.success then + callback(response.data) + else + if SM_Collections.Config.FallbackToLocal then + print("服务端获取小伙伴收藏失败,回退到本地数据") + SM_Collections.LocalDataProvider:GetCompanions(callback) + else + callback({}) + end + end + end) +end + +function SM_Collections.ServerDataProvider:GetCards(callback) + self:SendServerRequest("GET_CARDS", {}, function(response) + if response and response.success then + callback(response.data) + else + if SM_Collections.Config.FallbackToLocal then + print("服务端获取卡牌收藏失败,回退到本地数据") + SM_Collections.LocalDataProvider:GetCards(callback) + else + callback({}) + end + end + end) +end + +function SM_Collections.ServerDataProvider:GetItems(callback) + self:SendServerRequest("GET_ITEMS", {}, function(response) + if response and response.success then + callback(response.data) + else + if SM_Collections.Config.FallbackToLocal then + print("服务端获取物品收藏失败,回退到本地数据") + SM_Collections.LocalDataProvider:GetItems(callback) + else + callback({}) + end + end + end) +end + +function SM_Collections.ServerDataProvider:GetAttributes(callback) + self:SendServerRequest("GET_ATTRIBUTES", {}, function(response) + if response and response.success then + if SM_Collections.Config.Debug then + print("ServerDataProvider: 从服务端获取到", #response.data, "个属性加成") + end + callback(response.data) + else + if SM_Collections.Config.FallbackToLocal then + print("服务端获取坐骑属性加成收藏失败,回退到本地数据") + SM_Collections.LocalDataProvider:GetAttributes(callback) + else + callback({}) + end + end + end) +end + +function SM_Collections.ServerDataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) + local requestData = { + itemId = itemId, + itemType = itemType + } + self:SendServerRequest("GET_ITEM_ATTRIBUTES", requestData, function(response) + if response and response.success then + if SM_Collections.Config.Debug then + print("ServerDataProvider: 从服务端获取到", #response.data, "个特定属性") + end + callback(response.data) + else + if SM_Collections.Config.FallbackToLocal then + print("服务端获取特定属性失败,回退到本地数据") + SM_Collections.LocalDataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) + else + callback({}) + end + end + end) +end + +function SM_Collections.ServerDataProvider:SendServerRequest(command, data, callback) + if SM_Collections.Config.Debug then + print("发送服务端请求:", command) + end + SM_Collections.pendingCallbacks = SM_Collections.pendingCallbacks or {} + if command == "GET_MOUNTS" then + SM_Collections.pendingCallbacks.mounts = callback + SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_MOUNTS", "WHISPER", UnitName("player")) + elseif command == "GET_ATTRIBUTES" then + SM_Collections.pendingCallbacks.attributes = callback + SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_ATTRIBUTES", "WHISPER", UnitName("player")) + elseif command == "GET_COMPANIONS" then + SM_Collections.pendingCallbacks.companions = callback + SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_COMPANIONS", "WHISPER", UnitName("player")) + elseif command == "GET_CARDS" then + SM_Collections.pendingCallbacks.cards = callback + SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_CARDS", "WHISPER", UnitName("player")) + elseif command == "GET_ITEMS" then + SM_Collections.pendingCallbacks.items = callback + SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_ITEMS", "WHISPER", UnitName("player")) + elseif command == "GET_ITEM_ATTRIBUTES" then + SM_Collections.pendingCallbacks.item_attributes = callback + local requestMsg = data.itemType .. "|" .. data.itemId + SendAddonMessage("SM_C_COLLECTIONS_REQUEST", "GET_ITEM_ATTRIBUTES|" .. requestMsg, "WHISPER", UnitName("player")) + end + local timeoutFrame = CreateFrame("Frame") + local startTime = GetTime() + local timeoutSeconds = SM_Collections.Config.ServerTimeout / 1000 + timeoutFrame:SetScript("OnUpdate", function(self, elapsed) + if GetTime() - startTime >= timeoutSeconds then + local callbackKey = command:lower():gsub("get_", "") + if SM_Collections.pendingCallbacks and SM_Collections.pendingCallbacks[callbackKey] then + print("服务端请求超时:", command) + if SM_Collections.Config.FallbackToLocal then + local localProvider = SM_Collections.LocalDataProvider:new() + if command == "GET_MOUNTS" then + localProvider:GetMounts(callback) + elseif command == "GET_ATTRIBUTES" then + localProvider:GetAttributes(callback) + elseif command == "GET_COMPANIONS" then + localProvider:GetCompanions(callback) + elseif command == "GET_CARDS" then + localProvider:GetCards(callback) + elseif command == "GET_ITEMS" then + localProvider:GetItems(callback) + end + else + callback({}) + end + SM_Collections.pendingCallbacks[callbackKey] = nil + end + self:SetScript("OnUpdate", nil) + end + end) +end + +-- 数据管理器 +SM_Collections.DataManager = {} +function SM_Collections.DataManager:Initialize() + if SM_Collections.Config.UseServerData then + self.dataProvider = SM_Collections.ServerDataProvider:new() + print("使用服务端数据提供者") + else + self.dataProvider = SM_Collections.LocalDataProvider:new() + print("使用本地数据提供者") + end +end +function SM_Collections.DataManager:GetMounts(callback) self.dataProvider:GetMounts(callback) end +function SM_Collections.DataManager:GetCompanions(callback) self.dataProvider:GetCompanions(callback) end +function SM_Collections.DataManager:GetCards(callback) self.dataProvider:GetCards(callback) end +function SM_Collections.DataManager:GetItems(callback) self.dataProvider:GetItems(callback) end +function SM_Collections.DataManager:GetAttributes(callback) self.dataProvider:GetAttributes(callback) end +function SM_Collections.DataManager:GetAttributesForSpecificItem(itemId, itemType, callback) self.dataProvider:GetAttributesForSpecificItem(itemId, itemType, callback) end + +-- 兼容性坐骑数据 +SM_Collections.Mounts = { + [458] = { 284, 2, 0, "Brown Horse", "A favorite among Stormwind's guards thanks to its patience and stamina.", 2, "|cFFFFD200Vendor: |rWorld Vendors|n|cFFFFD200Cost: |r1|TINTERFACE\\MONEYFRAME\\UI-GOLDICON.BLP:0|t" }, + [459] = { 4268, 2, 64, "Gray Wolf", "This breed of wolf prefers hunting in the fog, relying on its smoky hide to camouflage it from unsuspecting prey.", 2, "|cFFFFD200Vendor: |rOgunaro Wolfrunner|n|cFFFFD200Zone: |rOrgrimmar|n|cFFFFD200Cost: |r1|TINTERFACE\\MONEYFRAME\\UI-GOLDICON.BLP:0|t" }, + [468] = { 305, 2, 64, "White Stallion", "The powerful and unyielding white stallion features heavily in the myths of ancient human tribes.", 2, "|cFFFFD200Legacy|r" }, + [470] = { 308, 2, 0, "Black Stallion", "Rumored to be favored by SI:7 for night missions due to its dark coat.", 2, "|cFFFFD200Vendor: |rUnger Statforth|n|cFFFFD200Zone: |rWetlands|n|cFFFFD200Cost: |r1|TINTERFACE\\MONEYFRAME\\UI-GOLDICON.BLP:0|t" }, + [578] = { 356, 2, 64, "Black Wolf", "Can howl loudly enough to be heard for miles.", 2, "|cFFFFD200Vendor: |rOgunaro Wolfrunner|n|cFFFFD200Zone: |rOrgrimmar|n|cFFFFD200Cost: |r1|TINTERFACE\\MONEYFRAME\\UI-GOLDICON.BLP:0|t" }, +} \ No newline at end of file diff --git a/SM_Events.lua b/SM_Events.lua new file mode 100644 index 0000000..69fc09d --- /dev/null +++ b/SM_Events.lua @@ -0,0 +1,91 @@ +-- SM_Events.lua + +-- 斜杠命令 +SLASH_SM_COLLECTIONS1 = "/smcollections" +SLASH_SM_COLLECTIONS2 = "/sm收藏" +SlashCmdList["SM_COLLECTIONS"] = function() + if not SM_Collections.MainFrame then + SM_Collections:CreateMainFrame() + end + if SM_Collections.MainFrame:IsVisible() then + SM_Collections.MainFrame:Hide() + else + SM_Collections.MainFrame:Show() + if not SM_Collections.CurrentTab then + SM_Collections:ShowTab(1) + end + end +end + +-- 处理坐骑数据 +function SM_Collections:HandleMountsData(msg) + local data = self:MessageSplit(msg, "|") + local mounts = {} + for i = 1, #data, 4 do + if data[i] and data[i + 1] and data[i + 2] and data[i + 3] then + table.insert(mounts, { + id = tonumber(data[i]), + name = data[i + 1], + description = data[i + 2], + obtained = data[i + 3] == "1" + }) + end + end + if self.pendingCallbacks and self.pendingCallbacks.mounts then + self.pendingCallbacks.mounts(mounts) + self.pendingCallbacks.mounts = nil + end +end + +-- 处理属性数据 +function SM_Collections:HandleAttributesData(msg) + local data = self:MessageSplit(msg, "|") + local attributes = {} + for i = 1, #data, 3 do + if data[i] and data[i + 1] and data[i + 2] then + table.insert(attributes, { + Name = data[i], + value = tonumber(data[i + 1]), + isPositive = data[i + 2] == "1" + }) + end + end + if self.pendingCallbacks and self.pendingCallbacks.attributes then + self.pendingCallbacks.attributes(attributes) + self.pendingCallbacks.attributes = nil + end +end + +-- 消息处理函数 +function SM_Collections_MessageEvent(self, event, packet, msg, type, sender) + if event == 'CHAT_MSG_ADDON' then + if packet == 'SM_S_COLLECTIONS_MOUNTS' then + SM_Collections:HandleMountsData(msg) + elseif packet == 'SM_S_COLLECTIONS_COMPANIONS' then + SM_Collections:HandleCompanionsData(msg) + elseif packet == 'SM_S_COLLECTIONS_CARDS' then + SM_Collections:HandleCardsData(msg) + elseif packet == 'SM_S_COLLECTIONS_ITEMS' then + SM_Collections:HandleItemsData(msg) + elseif packet == 'SM_S_COLLECTIONS_ATTRIBUTES' then + SM_Collections:HandleAttributesData(msg) + end + end +end + +-- 事件监听框架 +local SM_Collections_EventFrame = CreateFrame('Frame', 'SM_Collections_EventFrame') +SM_Collections_EventFrame:RegisterEvent('CHAT_MSG_ADDON') +SM_Collections_EventFrame:RegisterEvent('ADDON_LOADED') +SM_Collections_EventFrame:SetScript('OnEvent', function(self, event, ...) + if event == 'ADDON_LOADED' then + local addonName = ... + if addonName == "SM_CollectionSystem" then + SM_Collections.DataManager:Initialize() + print("SM收藏系统已加载!使用 /smcollections 打开界面") + print("数据源模式:", SM_Collections.Config.UseServerData and "服务端" or "本地") + end + elseif event == 'CHAT_MSG_ADDON' then + SM_Collections_MessageEvent(self, event, ...) + end +end) \ No newline at end of file diff --git a/SM_UI_MainFrame.lua b/SM_UI_MainFrame.lua new file mode 100644 index 0000000..e4a3f7b --- /dev/null +++ b/SM_UI_MainFrame.lua @@ -0,0 +1,395 @@ +-- SM_UI_MainFrame.lua + +-- 创建主界面 +function SM_Collections:CreateMainFrame() + if self.MainFrame then + return self.MainFrame + end + + SM_Collections_Frame = CreateFrame("Frame", "SM_Collections_MainFrame", UIParent); + SM_Collections_Frame:SetSize(800, 540); + SM_Collections_Frame:SetPoint("CENTER", 0, 0); + SM_Collections_Frame_Texture = SM_Collections_Frame:CreateTexture(nil, 'OVERLAY') + SM_Collections_Frame_Texture:SetPoint('TOP') + SM_Collections_Frame_Texture:SetAllPoints(SM_Collections_Frame) + SM_Collections_Frame_Texture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\back") + + -- 左上角圆形头像/LOGO + local icon = SM_Collections_Frame:CreateTexture(nil, "ARTWORK") + icon:SetSize(80, 80) + icon:SetPoint("TOPLEFT", 5, -5) + SetPortraitToTexture(icon, "Interface\\ICONS\\INV_Misc_QuestionMark") + + -- 标题 + local title = SM_Collections_Frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge") + title:SetPoint("TOP", 0, -20) + title:SetText("我的收藏系统") + + -- 关闭按钮 + local closeBtn = CreateFrame("Button", "SM_CollectionsCloseBtn", SM_Collections_Frame, "UIPanelCloseButton") + closeBtn:SetSize(40, 40) + closeBtn:SetPoint("TOPRIGHT", 4, -8) + closeBtn:SetScript("OnClick", function() SM_Collections_Frame:Hide() end) + + -- 创建右侧面板容器 + local rightSidePanel = CreateFrame("Frame", "SM_CollectionsRightSidePanel", SM_Collections_Frame) + rightSidePanel:SetSize(190, 400) + rightSidePanel:SetPoint("TOPRIGHT", 20, -80) + SM_Collections_Frame.RightSidePanel = rightSidePanel + self.RightSidePanel = rightSidePanel + + -- 右侧面板 + local rightPanel = CreateFrame("Frame", nil, SM_Collections_Frame) + rightPanel:SetPoint("TOPRIGHT", SM_Collections_Frame, "TOPRIGHT", -20, -60) + rightPanel:SetSize(320, 420) + + -- 名称 + rightPanel.name = rightPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge") + rightPanel.name:SetPoint("TOPLEFT", rightPanel, "TOPLEFT", 16, -16) + rightPanel.name:SetJustifyH("LEFT") + + -- 描述 + rightPanel.desc = rightPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal") + rightPanel.desc:SetPoint("TOPLEFT", rightPanel.name, "BOTTOMLEFT", 0, -8) + rightPanel.desc:SetWidth(280) + rightPanel.desc:SetJustifyH("LEFT") + rightPanel.desc:SetWordWrap(true) + + -- 坐骑召唤、小伙伴召唤、卡牌召唤按钮 + rightSidePanel.CallButon = CreateFrame("Button", "SM_CollectionsRightSidePanelCallButon", rightSidePanel) + rightSidePanel.CallButon:SetSize(30, 30) + rightSidePanel.CallButon:SetPoint("TOPRIGHT", -40, 30) + rightSidePanel.CallButon:SetNormalTexture("Interface\\ICONS\\Ability_Mount_RidingHorse.blp") + rightSidePanel.CallButon:SetHighlightTexture("Interface\\ICONS\\Ability_Mount_RidingHorse.blp") + rightSidePanel.CallButon:SetPushedTexture("Interface\\ICONS\\Ability_Mount_RidingHorse.blp") + rightSidePanel.CallButon:SetScript("OnClick", function() print("召唤") end) + + -- 创建标题容器 + local titleContainer = CreateFrame("Frame", nil, rightSidePanel) + titleContainer:SetSize(180, 30) + titleContainer:SetPoint("TOPLEFT", 5, -5) + + -- 坐骑名称文本 - 使用自定义字体 + local titleFont = CreateFont("SM_TitleFont") + titleFont:SetFont("Fonts\\ZYKai_T.ttf", 20, "MONOCHROME") + local MountNama = titleContainer:CreateFontString(nil, "OVERLAY") + MountNama:SetPoint("LEFT", 0, 0) + MountNama:SetFontObject(titleFont) + MountNama:SetText("") + MountNama:SetJustifyH("LEFT") + MountNama:SetJustifyV("TOP") + MountNama:SetTextColor(230 / 255, 150 / 255, 0 / 255) + rightSidePanel.MountNama = MountNama + + -- 创建介绍文本容器 + local introContainer = CreateFrame("Frame", nil, rightSidePanel) + introContainer:SetSize(180, 120) -- 增加高度以容纳更多文本 + introContainer:SetPoint("TOPLEFT", titleContainer, "BOTTOMLEFT", 0, -10) + + -- 介绍文本 - 使用自定义字体 + local descFont = CreateFont("SM_DescFont") + descFont:SetFont("Fonts\\ZYKai_T.ttf", 12, "MONOCHROME") + local introText = introContainer:CreateFontString(nil, "OVERLAY") + introText:SetPoint("TOPLEFT", 0, 0) + introText:SetSize(180, 0) -- 宽度固定,高度自适应 + introText:SetJustifyH("LEFT") + introText:SetJustifyV("TOP") + introText:SetSpacing(2) + introText:SetWordWrap(true) + introText:SetFontObject(descFont) + introText:SetText("") + rightSidePanel.introText = introText + + -- 属性加成标题 - 调整位置防止与介绍文本重叠 + local AttributeBonusFrame = CreateFrame("Frame", "AttributeBonusFrame", rightSidePanel) + AttributeBonusFrame:SetSize(150, 20) + AttributeBonusFrame:SetPoint("CENTER", introContainer, "CENTER", -25, -40) -- 增加间距 + AttributeBonusFrame:SetBackdrop({ bgFile = "Interface\\AddOns\\SM_CollectionSystem\\Textures\\AttributeBonusFrame" }) + + local AttributeBonusFrameText = AttributeBonusFrame:CreateFontString(nil, "OVERLAY") + AttributeBonusFrameText:SetPoint("CENTER", 0, 0) + AttributeBonusFrameText:SetFontObject(titleFont) + AttributeBonusFrameText:SetText("属性加成") + AttributeBonusFrameText:SetFont("Fonts\\ZYKai_T.ttf", 16, "MONOCHROME") + AttributeBonusFrame:Hide() + rightSidePanel.AttributeBonusFrame = AttributeBonusFrame + + -- 拖拽功能 + SM_Collections_Frame:SetScript("OnMouseDown", function(self, button) + if button == "LeftButton" then + self:StartMoving() + end + end) + SM_Collections_Frame:SetScript("OnMouseUp", function(self, button) + if button == "LeftButton" then + self:StopMovingOrSizing() + end + end) + + -- 创建标签页 + self:CreateTabs(SM_Collections_Frame) + + -- 创建内容区域 + local contentFrame = CreateFrame("Frame", "SM_CollectionsContentFrame", SM_Collections_Frame) + contentFrame:SetPoint("TOPLEFT", 20, -80) + contentFrame:SetPoint("BOTTOMRIGHT", -20, 20) + SM_Collections_Frame.ContentFrame = contentFrame + + self.MainFrame = SM_Collections_Frame + return SM_Collections_Frame +end + +-- 创建标签页 +function SM_Collections:CreateTabs(parent) + local tabs = {} + local tabNames = { "坐骑收藏", "小伙伴收藏", "卡牌收藏", "物品收藏" } + for i = 1, 4 do + local tab = CreateFrame("Button", "SM_CollectionTab" .. i, parent, "CharacterFrameTabButtonTemplate") + tab:SetSize(120, 30) + tab:SetID(i) + if i == 1 then + tab:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", 20, 5) + else + tab:SetPoint("LEFT", tabs[i - 1], "RIGHT", 5, 0) + end + tab:SetText(tabNames[i]) + tab:SetScript("OnClick", function(self) + SM_Collections:UpdateTabAppearance(self:GetID()) + SM_Collections:ShowTab(self:GetID()) + PlaySound("igCharacterInfoTab") + end) + tabs[i] = tab + end + parent.tabs = tabs + parent.numTabs = 4 + parent.selectedTab = 1 + self:UpdateTabAppearance(1) +end + +-- 更新标签页外观 +function SM_Collections:UpdateTabAppearance(selectedTab) + if not self.MainFrame or not self.MainFrame.tabs then return end + for i = 1, self.MainFrame.numTabs do + local tab = self.MainFrame.tabs[i] + if tab then + if i == selectedTab then + tab:SetAlpha(1.0) + if tab.GetFontString and tab:GetFontString() then + tab:GetFontString():SetTextColor(1, 1, 1) + end + else + tab:SetAlpha(0.7) + if tab.GetFontString and tab:GetFontString() then + tab:GetFontString():SetTextColor(0.7, 0.7, 0.7) + end + end + end + end + self.MainFrame.selectedTab = selectedTab + self.CurrentTab = selectedTab +end + +-- 显示指定标签页 +function SM_Collections:ShowTab(tabId) + self:UpdateTabAppearance(tabId) + if self.MainFrame and self.MainFrame.RightSidePanel then + if self.MainFrame.RightSidePanel.MountNama then + self.MainFrame.RightSidePanel.MountNama:SetText("") + end + if self.MainFrame.RightSidePanel.introText then + self.MainFrame.RightSidePanel.introText:SetText("") + end + if self.MainFrame.RightSidePanel.AttributeBonusFrame then + self.MainFrame.RightSidePanel.AttributeBonusFrame:Hide() + end + end + if self.CurrentPanel then + self.CurrentPanel:Hide() + local children = { self.CurrentPanel:GetChildren() } + for _, child in ipairs(children) do + child:Hide() + end + self.CurrentPanel = nil + end + if self.MainFrame and self.MainFrame.ContentFrame then + local children = { self.MainFrame.ContentFrame:GetChildren() } + for _, child in ipairs(children) do + child:Hide() + end + end + if self.MainFrame and self.MainFrame.RightSidePanel then + if tabId == 4 then + self.MainFrame.RightSidePanel:Hide() + else + self.MainFrame.RightSidePanel:Show() + end + end + if tabId == 1 then + self:ShowMounts() + elseif tabId == 2 then + self:ShowCompanions() + elseif tabId == 3 then + self:ShowCards() + elseif tabId == 4 then + self:ShowItems() + end +end + +-- 下面补充内容切换的函数(示例) +function SM_Collections:ShowMounts() + print("显示坐骑") + SM_Collections.DataManager:GetMounts(function(mounts) + local panel = self:CreateSplitPanel(self.MainFrame.ContentFrame, mounts, "mount") + local firstObtained = nil + for _, mount in ipairs(mounts) do + if mount.obtained then + firstObtained = mount + break + end + end + if firstObtained then + -- 只在模型下方显示坐骑名称 + -- panel.nameText:SetText(firstObtained.name) + + -- 不在模型下方显示描述文本,只设置右侧面板 + if self.MainFrame and self.MainFrame.RightSidePanel then + if self.MainFrame.RightSidePanel.MountNama then + self.MainFrame.RightSidePanel.MountNama:SetText(firstObtained.name or "") + end + if self.MainFrame.RightSidePanel.introText then + self.MainFrame.RightSidePanel.introText:SetText(firstObtained.description or "") + self.MainFrame.RightSidePanel.introText:SetHeight(0) -- 自动调整高度 + end + end + + local creatureDisplayID = self:GetCreatureDisplayID(firstObtained.id, "mount") + if creatureDisplayID and creatureDisplayID > 0 then + panel.model:Hide() + panel.model:SetPosition(0, 0, 0) + panel.model.zoomLevel = 0 + panel.model:Show() + panel.model:SetCreature(creatureDisplayID) + print("显示坐骑= " .. creatureDisplayID) + end + + -- 更新右侧面板的属性加成 + self:UpdateRightPanel(firstObtained, "mount") + end + panel:Show() + self.CurrentPanel = panel + end) +end + +function SM_Collections:ShowCompanions() + print("显示小伙伴") + SM_Collections.DataManager:GetCompanions(function(companions) + local panel = self:CreateSplitPanel(self.MainFrame.ContentFrame, companions, "companion") + local firstObtained = nil + for _, companion in ipairs(companions) do + if companion.obtained then + firstObtained = companion + break + end + end + if firstObtained then + -- 只在模型下方显示名称 + --panel.nameText:SetText(firstObtained.name) + + -- 不在模型下方显示描述文本,只设置右侧面板 + if self.MainFrame and self.MainFrame.RightSidePanel then + if self.MainFrame.RightSidePanel.MountNama then + self.MainFrame.RightSidePanel.MountNama:SetText(firstObtained.name or "") + end + if self.MainFrame.RightSidePanel.introText then + self.MainFrame.RightSidePanel.introText:SetText(firstObtained.description or "") + self.MainFrame.RightSidePanel.introText:SetHeight(0) -- 自动调整高度 + end + end + + local creatureDisplayID = self:GetCreatureDisplayID(firstObtained.id, "companion") + if creatureDisplayID and creatureDisplayID > 0 then + panel.model:Hide() + panel.model:SetPosition(0, 0, 0) + panel.model.zoomLevel = 0 + panel.model:Show() + panel.model:SetCreature(creatureDisplayID) + print("显示小伙伴= " .. creatureDisplayID) + end + + -- 更新右侧面板的属性加成 + self:UpdateRightPanel(firstObtained, "companion") + end + panel:Show() + self.CurrentPanel = panel + end) +end + +function SM_Collections:ShowCards() + print("显示卡牌收藏") + SM_Collections.DataManager:GetCards(function(cards) + local panel = self:CreateSplitPanel(self.MainFrame.ContentFrame, cards, "card") + local firstObtained = nil + for _, card in ipairs(cards) do + if card.obtained then + firstObtained = card + break + end + end + if firstObtained then + -- 只在模型下方显示名称 + --panel.nameText:SetText(firstObtained.name) + + -- 不在模型下方显示描述文本,只设置右侧面板 + if self.MainFrame and self.MainFrame.RightSidePanel then + if self.MainFrame.RightSidePanel.MountNama then + self.MainFrame.RightSidePanel.MountNama:SetText(firstObtained.name or "") + end + if self.MainFrame.RightSidePanel.introText then + self.MainFrame.RightSidePanel.introText:SetText(firstObtained.description or "") + self.MainFrame.RightSidePanel.introText:SetHeight(0) -- 自动调整高度 + end + end + + local creatureDisplayID = self:GetCreatureDisplayID(firstObtained.id, "card") + if creatureDisplayID and creatureDisplayID > 0 then + panel.model:Hide() + panel.model:SetPosition(0, 0, 0) + panel.model.zoomLevel = 0 + panel.model:Show() + panel.model:SetCreature(creatureDisplayID) + print("显示卡牌收藏= " .. creatureDisplayID) + end + + -- 更新右侧面板的属性加成 + self:UpdateRightPanel(firstObtained, "card") + end + panel:Show() + self.CurrentPanel = panel + end) +end + +function SM_Collections:ShowItems() + print("显示物品函数") + SM_Collections.DataManager:GetItems(function(items) + local panel = CreateFrame("Frame", "SM_CollectionsItemsPanel", self.MainFrame.ContentFrame) + panel:SetAllPoints() + panel:SetBackdrop({ + bgFile = "Interface\\AddOns\\SM_CollectionSystem\\Interface\\DialogFrame\\UI-DialogBox-Background", + edgeFile = "Interface\\AddOns\\SM_CollectionSystem\\Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + tileSize = 32, + edgeSize = 32, + insets = { left = 11, right = 12, top = 12, bottom = 11 } + }) + local scrollFrameName = "SM_ItemScrollFrame_" .. math.random(1000, 9999) + local scrollFrame = CreateFrame("ScrollFrame", scrollFrameName, panel, "UIPanelScrollFrameTemplate") + scrollFrame:SetSize(740, 480) + scrollFrame:SetPoint("TOPLEFT", 10, -10) + local scrollChild = CreateFrame("Frame", "SM_CollectionsItemsScrollChild", scrollFrame) + scrollChild:SetSize(720, 1) + scrollFrame:SetScrollChild(scrollChild) + self:CreateItemGrid(scrollChild, items) + panel:Show() + self.CurrentPanel = panel + end) +end \ No newline at end of file diff --git a/SM_UI_SplitPanel.lua b/SM_UI_SplitPanel.lua new file mode 100644 index 0000000..d45079c --- /dev/null +++ b/SM_UI_SplitPanel.lua @@ -0,0 +1,349 @@ +-- SM_UI_SplitPanel.lua + +-- 迁移左右分栏、列表、滚动条、模型、物品网格、CreateSplitPanel、CreateListItems、CreateItemGrid等所有UI细节和逻辑 +-- ...(此处插入完整实现,详见原始大文件) + +function SM_Collections:CreateSplitPanel(parent, data, itemType) + assert(parent, "CreateSplitPanel: parent is nil!") + local panel = CreateFrame("Frame", "SM_CollectionsPanel", parent) + panel:SetAllPoints() + + -- 左侧列表 + local listFrame = CreateFrame("Frame", "SM_CollectionslistFrame", panel) + listFrame:SetSize(220, 410) + listFrame:SetPoint("TOPLEFT", 5, -13) + listFrame:SetBackdrop({ + bgFile = "Interface\\AddOns\\SM_CollectionSystem\\Textures\\liebiaoditu" + }) + + local scrollFrameName = "SM_ScrollFrame_" .. itemType .. "_" .. math.random(1000, 9999) + local scrollFrame = CreateFrame("ScrollFrame", scrollFrameName, listFrame, "UIPanelScrollFrameTemplate") + scrollFrame:SetSize(200, 415) + scrollFrame:SetPoint("TOPLEFT", 5, 2) + + -- 滚动条装饰 + local BackgroundFrame = CreateFrame("Frame", "SM_CollectionsOverlayFrame", scrollFrame) + BackgroundFrame:SetSize(25, 410) + BackgroundFrame:SetPoint("RIGHT", scrollFrame, "RIGHT", 25.5, 1) + BackgroundFrame:SetFrameLevel(scrollFrame:GetFrameLevel() + 1) + local ScrollBarBackground = BackgroundFrame:CreateTexture(nil, "BACKGROUND") + ScrollBarBackground:SetSize(25, 410) + ScrollBarBackground:SetPoint("CENTER", BackgroundFrame, "CENTER", 0, 0) + ScrollBarBackground:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\cooldown") + + local overlayFrame = CreateFrame("Frame", "SM_CollectionsOverlayFrame", BackgroundFrame) + overlayFrame:SetSize(30, 420) + overlayFrame:SetPoint("CENTER", BackgroundFrame, "CENTER", 0, 1) + overlayFrame:SetFrameLevel(BackgroundFrame:GetFrameLevel() + 10) + local scrollBarOverlay = overlayFrame:CreateTexture(nil, "OVERLAY") + scrollBarOverlay:SetAllPoints(overlayFrame) + scrollBarOverlay:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\ScrollFrame") + scrollBarOverlay:SetTexCoord(0, 1, 0, 1) + scrollBarOverlay:SetVertexColor(1, 1, 1, 1) + scrollBarOverlay:SetBlendMode("BLEND") + + local scrollChild = CreateFrame("Frame", "SM_CollectionsScrollChild", scrollFrame) + scrollChild:SetSize(300, 1) + scrollFrame:SetScrollChild(scrollChild) + + -- 右侧模型显示 + local modelFrame = CreateFrame("Frame", "SM_CollectionsModelFrame", parent) + modelFrame:SetSize(380, 430) + modelFrame:SetPoint("CENTER", 30, -3) + modelFrame:SetFrameStrata("HIGH") + modelFrame:SetFrameLevel(parent:GetFrameLevel() + 10) + + -- 3D模型 + local model = CreateFrame("PlayerModel", "SM_CollectionsModel", modelFrame) + model:SetSize(360, 415) + model:SetPoint("TOP", 5, 0) + model:SetCamera(0) + model:SetFacing(0) + model.zoomLevel = 0 + model:SetPosition(0, 0, 0) + model:SetFrameStrata("HIGH") + model:SetFrameLevel(modelFrame:GetFrameLevel() + 1) + + -- 模型旋转功能 + model:EnableMouse(true) + model:SetScript("OnMouseDown", function(self, button) + if button == "LeftButton" then + self.isRotating = true + self.lastX = GetCursorPosition() + end + end) + model:SetScript("OnMouseUp", function(self, button) + if button == "LeftButton" then + self.isRotating = false + end + end) + + local ROTATE_SPEED = math.rad(90) + model.isRotatingLeft = false + model.isRotatingRight = false + + -- 左旋转按钮 + local rotateLeftBtn = CreateFrame("Button", nil, modelFrame) + rotateLeftBtn:SetSize(32, 32) + rotateLeftBtn:SetPoint("BOTTOM", modelFrame, "BOTTOM", -50, 30) + rotateLeftBtn:SetNormalTexture("Interface\\Buttons\\UI-RotationLeft-Button-Up") + rotateLeftBtn:SetPushedTexture("Interface\\Buttons\\UI-RotationLeft-Button-Down") + rotateLeftBtn:SetHighlightTexture("Interface\\Buttons\\UI-RotationLeft-Button-Highlight") + rotateLeftBtn:SetFrameStrata("HIGH") + rotateLeftBtn:SetFrameLevel(modelFrame:GetFrameLevel() + 2) + rotateLeftBtn:SetScript("OnMouseDown", function() model.isRotatingLeft = true end) + rotateLeftBtn:SetScript("OnMouseUp", function() model.isRotatingLeft = false end) + rotateLeftBtn:HookScript("OnLeave", function() model.isRotatingLeft = false end) + + -- 右旋转按钮 + local rotateRightBtn = CreateFrame("Button", nil, modelFrame) + rotateRightBtn:SetSize(32, 32) + rotateRightBtn:SetPoint("BOTTOM", modelFrame, "BOTTOM", 50, 30) + rotateRightBtn:SetNormalTexture("Interface\\Buttons\\UI-RotationRight-Button-Up") + rotateRightBtn:SetPushedTexture("Interface\\Buttons\\UI-RotationRight-Button-Down") + rotateRightBtn:SetHighlightTexture("Interface\\Buttons\\UI-RotationRight-Button-Highlight") + rotateRightBtn:SetFrameStrata("HIGH") + rotateRightBtn:SetFrameLevel(modelFrame:GetFrameLevel() + 2) + rotateRightBtn:SetScript("OnMouseDown", function() model.isRotatingRight = true end) + rotateRightBtn:SetScript("OnMouseUp", function() model.isRotatingRight = false end) + rotateRightBtn:HookScript("OnLeave", function() model.isRotatingRight = false end) + + -- 旋转更新 + model:SetScript("OnUpdate", function(self, elapsed) + if self.isRotating then + local x = GetCursorPosition() + local delta = (x - (self.lastX or x)) * 0.01 + self.lastX = x + self:SetFacing(self:GetFacing() + delta) + end + if self.isRotatingLeft then + self:SetFacing(self:GetFacing() + ROTATE_SPEED * elapsed) + elseif self.isRotatingRight then + self:SetFacing(self:GetFacing() - ROTATE_SPEED * elapsed) + end + end) + + -- UI元素 - 移除重复的文本显示 + local nameText = modelFrame:CreateFontString(nil, "OVERLAY","GameFontNormalLarge") + nameText:SetPoint("BOTTOM", modelFrame, "BOTTOM", 0, 80) -- 将名称移到模型下方,避免与模型重叠 + nameText:SetTextColor(1, 1, 1) + nameText:SetWidth(320) -- 限制宽度避免文本溢出 + nameText:SetHeight(0) -- 自动调整高度 + nameText:SetJustifyH("CENTER") + + -- 描述文本不在模型框架中显示,让右侧面板来显示 + local descText = modelFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + descText:SetSize(320, 0) -- 自动高度 + descText:SetPoint("TOP", nameText, "BOTTOM", 0, -5) -- 放在名称下方 + descText:SetJustifyH("CENTER") + descText:Hide() -- 隐藏这个文本,我们将使用右侧面板的文本 + + panel.listFrame = listFrame + panel.scrollChild = scrollChild + panel.modelFrame = modelFrame + panel.model = model + panel.nameText = nameText + panel.descText = descText + + self:CreateListItems(scrollChild, data, itemType, model, nameText, descText) + -- 绑定当前panel,便于切换标签时只隐藏panel,不隐藏模型区 + if self.CurrentPanel then + self.CurrentPanel:Hide() + end + self.CurrentPanel = panel + return panel +end + +function SM_Collections:CreateListItems(parent, data, itemType, model, nameText, descText) + local buttonW = 170 + local buttonHeight = 40 + local spacing = 2 + local iconSize = 30 + if itemType == "card" then + buttonW = 200 + end + for i, item in ipairs(data) do + local button = CreateFrame("Button", "Collectionsbutton" .. i, parent) + button:SetSize(buttonW, buttonHeight) + button:SetPoint("TOPLEFT", 30, -(i - 1) * (buttonHeight + spacing)) + button:SetNormalTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\liebiaoditu_kuang_A") + button:SetHighlightTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\liebiaoditu_kuang_B") + local ButtonIcon = nil + if itemType == "mount" or itemType == "companion" then + ButtonIcon = CreateFrame("Button", "CollectionsButtonIcon" .. i, button) + ButtonIcon:SetSize(iconSize, iconSize) + ButtonIcon:SetPoint("RIGHT", button, "LEFT", 0, 0) + local name, rank, icon = GetSpellInfo(item.id) + if icon then + ButtonIcon:SetNormalTexture(icon) + ButtonIcon:SetHighlightTexture(icon) + else + ButtonIcon:SetNormalTexture("Interface\\Icons\\INV_Misc_QuestionMark") + ButtonIcon:SetHighlightTexture("Interface\\Icons\\INV_Misc_QuestionMark") + end + ButtonIcon:SetFrameLevel(button:GetFrameLevel() + 1) + ButtonIcon:SetScript("OnEnter", function() + GameTooltip:SetOwner(ButtonIcon, "ANCHOR_RIGHT") + GameTooltip:SetHyperlink("spell:" .. item.id) + GameTooltip:Show() + end) + ButtonIcon:SetScript("OnLeave", function() GameTooltip:Hide() end) + ButtonIcon:Show() + end + local text = button:CreateFontString(nil, "OVERLAY", "GameFontNormal") + if itemType == "card" then + button:SetPoint("TOPLEFT", 0, -(i - 1) * (buttonHeight + spacing)) + text:SetPoint("CENTER", 0, 0) + else + text:SetPoint("LEFT", 10, 0) + end + text:SetText(item.name) + text:SetTextColor(item.obtained and 1 or 0.5, item.obtained and 1 or 0.5, item.obtained and 1 or 0.5) + button:SetScript("OnClick", function() + --nameText:SetText(item.name) + -- 不在点击时显示获得状态,只显示名称 + local creatureDisplayID = self:GetCreatureDisplayID(item.id, itemType) + if creatureDisplayID and creatureDisplayID > 0 then + model:Hide() + model:SetPosition(0, 0, 0) + model.zoomLevel = 0 + model:Show() + model:SetCreature(creatureDisplayID) + print("creatureDisplayID= ", creatureDisplayID) + end + self:UpdateRightPanel(item, itemType) + end) + -- 在鼠标悬停时在工具提示中显示获得状态 + button:SetScript("OnEnter", function() + GameTooltip:SetOwner(button, "ANCHOR_RIGHT") + GameTooltip:SetText(item.name) + local statusText = item.obtained and "|cFF00FF00已获得|r" or "|cFFFF0000未获得|r" + GameTooltip:AddLine(statusText) + GameTooltip:Show() + + -- 不在模型下方显示获得状态 + --nameText:SetText(item.name) + --nameText:SetTextColor(1, 1, 1) + end) + + button:SetScript("OnLeave", function() + GameTooltip:Hide() + end) + + button:Show() + end + local totalHeight = #data * (buttonHeight + spacing) + parent:SetHeight(math.max(totalHeight, 1)) +end + +function SM_Collections:UpdateRightPanel(selectedItem, itemType) + if not self.MainFrame or not self.MainFrame.RightSidePanel then + return + end + local rightPanel = self.MainFrame.RightSidePanel + + -- 更新坐骑名称 + if rightPanel.MountNama then + rightPanel.MountNama:SetText(selectedItem.name or "") + end + + -- 更新描述文本并确保正确换行 + if rightPanel.introText then + rightPanel.introText:SetText(selectedItem.description or "") + rightPanel.introText:SetHeight(0) -- 重置高度以便自动计算 + end + + -- 显示属性加成 + if rightPanel.AttributeBonusFrame then + self:UpdateAttributesForItem(selectedItem, rightPanel.AttributeBonusFrame, itemType) + end +end + +function SM_Collections:UpdateAttributesForItem(item, parentFrame, itemType) + local children = { parentFrame:GetChildren() } + for _, child in ipairs(children) do + if child:GetName() and string.find(child:GetName(), "SM_CollectionsAttributeutton") then + child:Hide() + end + end + self:GetAttributesForItem(item, function(attributes) + if #attributes == 0 then + parentFrame:Hide() + return + end + parentFrame:Show() + local buttonH = 150 + local buttonW = 20 + for i, attribute in ipairs(attributes) do + local AttributeName = attribute.Name + local AttributeValue = attribute.value + local isPositive = attribute.isPositive + local button = CreateFrame("Button", "SM_CollectionsAttributeutton" .. i, parentFrame) + 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("CENTER", 0, 0) + nameText:SetFont("Fonts\\ZYKai_T.ttf", 10, "MONOCHROME") + nameText:SetText(AttributeName) + nameText:SetTextColor(1, 1, 1) + local valueText = button:CreateFontString(nil, "OVERLAY") + valueText:SetPoint("RIGHT", -5, 0) + valueText:SetFont("Fonts\\ZYKai_T.ttf", 10, "MONOCHROME") + local formattedValue = isPositive and ("+ " .. AttributeValue) or ("- " .. AttributeValue) + valueText:SetText(formattedValue) + valueText:SetTextColor(isPositive and 0 or 1, isPositive and 1 or 0, 0) + button:Show() + end + end, itemType) +end + +function SM_Collections:GetAttributesForItem(item, callback, itemType) + SM_Collections.DataManager:GetAttributesForSpecificItem(item.id, itemType, function(attributes) + callback(attributes) + end) +end + +function SM_Collections:CreateItemGrid(parent, items) + local buttonSize = 40 + local spacing = 5 + local buttonsPerRow = 16 + for i, item in ipairs(items) do + local button = CreateFrame("Button", "SM_CollectionsItemGridButton", parent) + button:SetSize(buttonSize, buttonSize) + local row = math.floor((i - 1) / buttonsPerRow) + local col = (i - 1) % buttonsPerRow + button:SetPoint("TOPLEFT", 10 + col * (buttonSize + spacing), -10 + -row * (buttonSize + spacing)) + local texture = button:CreateTexture(nil, "ARTWORK") + texture:SetAllPoints() + local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, itemTexture = + GetItemInfo(item.id) + texture:SetTexture(itemTexture) + if not item.obtained then + texture:SetDesaturated(true) + else + texture:SetDesaturated(false) + end + button:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square") + button:HookScript("OnClick", function() + if item.obtained then + print("选择了物品: " .. item.name) + else + print("您还没有获得: " .. item.name) + end + end) + button:HookScript("OnEnter", function(self) + GameTooltip:SetOwner(button, "ANCHOR_RIGHT") + GameTooltip:SetText(item.name) + GameTooltip:SetHyperlink('Hitem:' .. item.id) + GameTooltip:Show() + end) + button:HookScript("OnLeave", function() + GameTooltip:Hide() + end) + button:Show() + end + local rows = math.ceil(#items / buttonsPerRow) + local totalHeight = rows * (buttonSize + spacing) + parent:SetHeight(math.max(totalHeight, 1)) +end diff --git a/SM_Utils.lua b/SM_Utils.lua new file mode 100644 index 0000000..6407355 --- /dev/null +++ b/SM_Utils.lua @@ -0,0 +1,48 @@ +-- SM_Utils.lua + +function SM_Collections:MessageSplit(inputstr, sep) + if not inputstr or inputstr == "" then + return {} + end + if sep == nil then + sep = "%s" + end + local t = {} + for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do + table.insert(t, str) + end + return t +end + +function SM_Collections:GetMountInfo(spellID) + local info = self.Mounts[spellID] + if info then + return unpack(info, 1, 9) + end +end + +function SM_Collections:GetCreatureDisplayID(itemID, itemType) + if itemType == "mount" then + local mountInfo = self:GetMountInfo(itemID) + if mountInfo then + return mountInfo -- 第一个返回值就是 creatureDisplayID + end + elseif itemType == "companion" then + local companionMap = { + [62508] = 33194, -- 丹莫罗熊宝宝 -> 熊的显示ID + [28871] = 16701, -- 仲夏之魂 -> 火元素显示ID + [13548] = 30379, -- 农场小鸡 -> 鸡的显示ID + [23811] = 14878, -- 加布林 + } + return companionMap[itemID] or itemID + elseif itemType == "card" then + local cardMap = { + [11502] = 11502, -- 拉格纳罗斯 + [24248] = 24248, -- 巫妖王 + [19299] = 19299, -- 死亡耳语者 + [32588] = 32588, -- 伊利丹 + } + return cardMap[itemID] or itemID + end + return itemID +end \ No newline at end of file