获取新物品显示改变纹理、设置new图标,进行排序
This commit is contained in:
parent
c5f085f175
commit
e69e2e76f2
@ -613,7 +613,7 @@ SM_CollectionData.Cameras =
|
||||
[Chr(O.Classic, R.BloodElf, S.Male, I.INVTYPE_TABARD)] = { 2.15, 0.00, -1.80, 0.10 }, -- 战袍
|
||||
[Chr(O.Classic, R.BloodElf, S.Male, I.INVTYPE_WRIST)] = { 3.85, -0.22, -2.75, -0.80 }, -- 护腕
|
||||
[Chr(O.Classic, R.BloodElf, S.Male, I.INVTYPE_HAND)] = { 3.85, -0.22, -2.75, -0.80 }, -- 手套
|
||||
[Chr(O.Classic, R.BloodElf, S.Male, I.INVTYPE_WAIST)] = { 4, 0.3, -2.80, 0.10 }, -- 腰带
|
||||
[Chr(O.Classic, R.BloodElf, S.Male, I.INVTYPE_WAIST)] = { 5, 0.4, -4.2, 0 }, -- 腰带
|
||||
[Chr(O.Classic, R.BloodElf, S.Male, I.INVTYPE_LEGS)] = { 2.00, -0.10, -0.20, 0.10 }, -- 腿甲
|
||||
[Chr(O.Classic, R.BloodElf, S.Male, I.INVTYPE_FEET)] = { 2.45, -0.10, 0.47, -0.70 }, -- 靴子
|
||||
[Chr(O.Classic, R.BloodElf, S.Male, I.SetsDetails)] = { 0.00, 0.00, -0.33, 0.00 }, -- 套装详情
|
||||
|
||||
@ -23,6 +23,83 @@ SM_ItemCollectionUI.pageButtons = {}
|
||||
SM_ItemCollectionUI.lastUpdateTime = 0 -- 上次更新时间
|
||||
SM_ItemCollectionUI.CACHE_EXPIRE_TIME = 3600 -- 缓存过期时间(1小时)
|
||||
|
||||
-- 注册物品获取事件
|
||||
function SM_ItemCollectionUI:RegisterItemEvents()
|
||||
-- 创建事件处理框架
|
||||
if not self.eventFrame then
|
||||
self.eventFrame = CreateFrame("Frame")
|
||||
self.eventFrame:SetScript("OnEvent", function(self, event, ...)
|
||||
if event == "CHAT_MSG_LOOT" then
|
||||
SM_ItemCollectionUI:OnLootReceived(...)
|
||||
elseif event == "BAG_UPDATE" then
|
||||
-- 使用背包更新事件替代ITEM_PUSH
|
||||
SM_ItemCollectionUI:OnBagUpdate()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- 注册相关事件
|
||||
self.eventFrame:RegisterEvent("CHAT_MSG_LOOT")
|
||||
self.eventFrame:RegisterEvent("BAG_UPDATE")
|
||||
|
||||
print("[事件] 物品获取事件已注册")
|
||||
end
|
||||
|
||||
-- 处理物品获取事件
|
||||
function SM_ItemCollectionUI:OnLootReceived(msg)
|
||||
-- 解析聊天消息中的物品ID
|
||||
local itemLink = string.match(msg, "|H(item:[^|]+)|h")
|
||||
if itemLink then
|
||||
local itemID = string.match(itemLink, "item:(%d+)")
|
||||
if itemID then
|
||||
print("[事件] 检测到物品获取:", itemID)
|
||||
-- 延迟一点执行更新,确保服务器数据已同步
|
||||
local itemToUpdate = itemID
|
||||
local updateFrame = CreateFrame("Frame")
|
||||
updateFrame:SetScript("OnUpdate", function(self, elapsed)
|
||||
self.elapsed = (self.elapsed or 0) + elapsed
|
||||
if self.elapsed >= 0.5 then
|
||||
SM_ItemCollectionUI:UpdateItemObtainedStatus(itemToUpdate, true)
|
||||
self:SetScript("OnUpdate", nil)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 处理背包更新事件
|
||||
function SM_ItemCollectionUI:OnBagUpdate()
|
||||
-- 检查所有背包中的物品
|
||||
for bag = 0, 4 do
|
||||
local slots = GetContainerNumSlots(bag)
|
||||
for slot = 1, slots do
|
||||
local itemLink = GetContainerItemLink(bag, slot)
|
||||
if itemLink then
|
||||
local itemID = string.match(itemLink, "item:(%d+)")
|
||||
if itemID and not self.processedItems then
|
||||
self.processedItems = {}
|
||||
end
|
||||
|
||||
-- 避免重复处理同一物品
|
||||
if itemID and not self.processedItems[itemID] then
|
||||
self.processedItems[itemID] = true
|
||||
print("[事件] 检测到背包物品:", itemID)
|
||||
-- 延迟一点执行更新,确保服务器数据已同步
|
||||
local itemToUpdate = itemID
|
||||
local updateFrame = CreateFrame("Frame")
|
||||
updateFrame:SetScript("OnUpdate", function(self, elapsed)
|
||||
self.elapsed = (self.elapsed or 0) + elapsed
|
||||
if self.elapsed >= 0.5 then
|
||||
SM_ItemCollectionUI:UpdateItemObtainedStatus(itemToUpdate, true)
|
||||
self:SetScript("OnUpdate", nil)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 初始化物品收藏界面
|
||||
function SM_ItemCollectionUI:Init()
|
||||
-- 只做一次全局声明,绝不重置SM_CollectionsDB或itemCache
|
||||
@ -32,9 +109,45 @@ function SM_ItemCollectionUI:Init()
|
||||
end
|
||||
-- 初始化物品槽位数据
|
||||
self:InitSlotData()
|
||||
|
||||
-- 注册物品获取事件
|
||||
self:RegisterItemEvents()
|
||||
|
||||
self.initialized = true
|
||||
end
|
||||
|
||||
-- 添加处理NEW图标的统一函数
|
||||
function SM_ItemCollectionUI:HandleNewItemIcon(model, itemID)
|
||||
if model and itemID and SM_Collections and SM_Collections.NewItems and SM_Collections.NewItems.item and SM_Collections.NewItems.item[tonumber(itemID)] then
|
||||
-- 添加"NEW"标记,如果这是新获得的物品
|
||||
if model.itemData and model.itemData.obtained and SM_Collections.NewItems and SM_Collections.NewItems.item and SM_Collections.NewItems.item[tonumber(itemID)] then
|
||||
print("[收藏系统] 检测到新物品,准备添加NEW图标:", itemID)
|
||||
|
||||
-- 创建NEW图标,使用OVERLAY层的最高级别(7)确保显示在最顶层
|
||||
if not model.newTexture then
|
||||
local newTexture = model:CreateTexture(nil, "OVERLAY", nil, 7)
|
||||
newTexture:SetSize(32, 28)
|
||||
newTexture:SetPoint("TOPRIGHT", model, "TOPRIGHT", 10, 10)
|
||||
newTexture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\New_Icon")
|
||||
-- 确保纹理在最顶层
|
||||
newTexture:SetDrawLayer("OVERLAY", 7)
|
||||
model.newTexture = newTexture
|
||||
print("[收藏系统] 成功创建NEW图标:", itemID)
|
||||
else
|
||||
model.newTexture:Show()
|
||||
-- 确保纹理在最顶层
|
||||
model.newTexture:SetDrawLayer("OVERLAY", 7)
|
||||
print("[收藏系统] 显示已有NEW图标:", itemID)
|
||||
end
|
||||
else
|
||||
-- 如果不是新物品但存在NEW图标,隐藏它
|
||||
if model and model.newTexture then
|
||||
model.newTexture:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 初始化物品槽位数据
|
||||
function SM_ItemCollectionUI:InitSlotData()
|
||||
-- 获取物品分类数据
|
||||
@ -265,6 +378,14 @@ function SM_ItemCollectionUI:UpdateAttributes(itemID, itemType)
|
||||
-- 重置数组
|
||||
rightSidePanel.attributeButtons = {}
|
||||
rightSidePanel.attributeTexts = {}
|
||||
|
||||
-- 创建属性容器,用于RefreshCollectionStatus函数统一更新颜色
|
||||
if not rightSidePanel.attributesContainer then
|
||||
rightSidePanel.attributesContainer = CreateFrame("Frame", nil, rightSidePanel.AttributeBonusFrame)
|
||||
rightSidePanel.attributesContainer:SetSize(180, 200)
|
||||
rightSidePanel.attributesContainer:SetPoint("TOP", rightSidePanel.AttributeBonusFrame, "TOP", 0, -30)
|
||||
end
|
||||
rightSidePanel.attributesContainer:Show()
|
||||
|
||||
-- 模拟不同物品的不同属性加成
|
||||
local attributes = {}
|
||||
@ -299,10 +420,10 @@ function SM_ItemCollectionUI:UpdateAttributes(itemID, itemType)
|
||||
|
||||
for i, attribute in ipairs(attributes) do
|
||||
-- 创建带背景纹理的按钮
|
||||
local button = CreateFrame("Button", "SM_ItemCollectionAttributeButton" .. i, rightSidePanel.AttributeBonusFrame)
|
||||
local button = CreateFrame("Button", "SM_ItemCollectionAttributeButton" .. i, rightSidePanel.attributesContainer)
|
||||
button:SetSize(buttonH, buttonW)
|
||||
button:SetNormalTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\AttributeuttonTexture")
|
||||
button:SetPoint("TOPLEFT", 0, -30 - (i - 1) * buttonW)
|
||||
button:SetPoint("TOPLEFT", 0, -(i - 1) * buttonW)
|
||||
|
||||
-- 属性名称文本
|
||||
local nameText = button:CreateFontString(nil, "OVERLAY")
|
||||
@ -355,11 +476,49 @@ function SM_ItemCollectionUI:HandleButtonClick(slot)
|
||||
end
|
||||
end
|
||||
self.currentPage = 1
|
||||
|
||||
-- 确保按获得状态对物品排序
|
||||
self:SortSlotItems(slot)
|
||||
|
||||
-- 显示物品预览
|
||||
self:ShowItemPreview(slot, self.currentPanel)
|
||||
end
|
||||
|
||||
-- 强制清理所有物品模型
|
||||
function SM_ItemCollectionUI:ForceCleanupModels(panel)
|
||||
print("[清理] 强制清理所有物品模型")
|
||||
|
||||
-- 清理预览框架
|
||||
if panel and panel.previewFrame then
|
||||
local children = { panel.previewFrame:GetChildren() }
|
||||
for _, child in ipairs(children) do
|
||||
-- 清理所有事件处理器
|
||||
child:SetScript("OnEnter", nil)
|
||||
child:SetScript("OnLeave", nil)
|
||||
child:SetScript("OnMouseDown", nil)
|
||||
child:SetScript("OnMouseUp", nil)
|
||||
child:SetScript("OnMouseWheel", nil)
|
||||
child:SetScript("OnUpdate", nil)
|
||||
-- 清理所有纹理
|
||||
if child.newTexture then child.newTexture:Hide() end
|
||||
if child.TransmogStateTexture then child.TransmogStateTexture:Hide() end
|
||||
if child.Border then child.Border:Hide() end
|
||||
-- 隐藏并移除
|
||||
child:Hide()
|
||||
child:SetParent(nil)
|
||||
child:ClearAllPoints()
|
||||
end
|
||||
end
|
||||
|
||||
-- 清理全局缓存
|
||||
collectgarbage("collect")
|
||||
end
|
||||
|
||||
-- 显示物品预览
|
||||
function SM_ItemCollectionUI:ShowItemPreview(slot, panel)
|
||||
-- 确保物品已排序
|
||||
self:SortSlotItems(slot)
|
||||
|
||||
-- 清除当前选中的模型
|
||||
self:ClearModelSelection()
|
||||
|
||||
@ -482,12 +641,46 @@ function SM_ItemCollectionUI:ShowItemPreview(slot, panel)
|
||||
end
|
||||
end
|
||||
|
||||
model.itemData = itemData -- 保存物品数据以便后续使用
|
||||
model.itemData = itemData or {id = itemID, obtained = false} -- 保存物品数据以便后续使用
|
||||
|
||||
-- 添加"NEW"标记,如果这是新获得的物品
|
||||
if itemData and itemData.obtained and SM_Collections.NewItems and SM_Collections.NewItems.item and SM_Collections.NewItems.item[tonumber(itemID)] then
|
||||
print("[收藏系统] 检测到新物品,准备添加NEW图标:", itemID)
|
||||
|
||||
-- 创建NEW图标,使用OVERLAY层的最高级别(7)确保显示在最顶层
|
||||
if not model.newTexture then
|
||||
local newTexture = model:CreateTexture(nil, "OVERLAY", nil, 7)
|
||||
newTexture:SetSize(32, 28)
|
||||
newTexture:SetPoint("TOPRIGHT", model, "TOPRIGHT", 10, 10)
|
||||
newTexture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\New_Icon")
|
||||
-- 确保纹理在最顶层
|
||||
newTexture:SetDrawLayer("OVERLAY", 7)
|
||||
model.newTexture = newTexture
|
||||
print("[收藏系统] 成功创建NEW图标:", itemID)
|
||||
else
|
||||
model.newTexture:Show()
|
||||
-- 确保纹理在最顶层
|
||||
model.newTexture:SetDrawLayer("OVERLAY", 7)
|
||||
print("[收藏系统] 显示已有NEW图标:", itemID)
|
||||
end
|
||||
end
|
||||
|
||||
if model.TransmogStateTexture then model.TransmogStateTexture:Hide() end
|
||||
table.insert(modelFrames, model)
|
||||
model:Show()
|
||||
model:EnableMouse(true)
|
||||
model:SetScript("OnEnter", function(self)
|
||||
-- 处理NEW图标
|
||||
if self.newTexture and self.newTexture:IsShown() then
|
||||
print("[收藏系统] 清除NEW图标:", itemID)
|
||||
self.newTexture:Hide()
|
||||
-- 从NewItems表中移除
|
||||
if SM_Collections and SM_Collections.NewItems and SM_Collections.NewItems.item then
|
||||
SM_Collections.NewItems.item[tonumber(itemID)] = nil
|
||||
print("[收藏系统] 已清除NEW标记:", itemID)
|
||||
end
|
||||
end
|
||||
|
||||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||||
GameTooltip:SetHyperlink("item:" .. itemID)
|
||||
GameTooltip:Show()
|
||||
@ -574,12 +767,45 @@ function SM_ItemCollectionUI:ShowItemPreview(slot, panel)
|
||||
end
|
||||
end
|
||||
|
||||
model.itemData = itemData -- 保存物品数据以便后续使用
|
||||
model.itemData = itemData or {id = itemID, obtained = false} -- 保存物品数据以便后续使用
|
||||
|
||||
-- 添加"NEW"标记,如果这是新获得的物品
|
||||
if itemData and itemData.obtained and SM_Collections.NewItems and SM_Collections.NewItems.item and SM_Collections.NewItems.item[tonumber(itemID)] then
|
||||
print("[收藏系统] 检测到新物品,准备添加NEW图标(3D):", itemID)
|
||||
|
||||
-- 创建NEW图标,使用OVERLAY层的最高级别(7)确保显示在最顶层
|
||||
if not model.newTexture then
|
||||
local newTexture = model:CreateTexture(nil, "OVERLAY", nil, 7)
|
||||
newTexture:SetSize(32, 28)
|
||||
newTexture:SetPoint("TOPRIGHT", model, "TOPRIGHT", 10, 10)
|
||||
newTexture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\New_Icon")
|
||||
-- 确保纹理在最顶层
|
||||
newTexture:SetDrawLayer("OVERLAY", 7)
|
||||
model.newTexture = newTexture
|
||||
print("[收藏系统] 成功创建NEW图标(3D):", itemID)
|
||||
else
|
||||
model.newTexture:Show()
|
||||
-- 确保纹理在最顶层
|
||||
model.newTexture:SetDrawLayer("OVERLAY", 7)
|
||||
print("[收藏系统] 显示已有NEW图标(3D):", itemID)
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(modelFrames, model)
|
||||
model:Show()
|
||||
model:EnableMouse(true)
|
||||
model:SetScript("OnEnter", function(self)
|
||||
-- 处理NEW图标
|
||||
if self.newTexture and self.newTexture:IsShown() then
|
||||
print("[收藏系统] 清除NEW图标:", itemID)
|
||||
self.newTexture:Hide()
|
||||
-- 从NewItems表中移除
|
||||
if SM_Collections and SM_Collections.NewItems and SM_Collections.NewItems.item then
|
||||
SM_Collections.NewItems.item[tonumber(itemID)] = nil
|
||||
print("[收藏系统] 已清除NEW标记:", itemID)
|
||||
end
|
||||
end
|
||||
|
||||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||||
GameTooltip:SetHyperlink("item:" .. itemID)
|
||||
GameTooltip:Show()
|
||||
@ -774,11 +1000,20 @@ function SM_ItemCollectionUI:CreatePageButtons(panel, slot)
|
||||
-- 上一页按钮
|
||||
local prevBtn = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
|
||||
prevBtn:SetSize(60, 24)
|
||||
prevBtn:SetPoint("BOTTOM", panel, "BOTTOM", 0, 30)
|
||||
prevBtn:SetPoint("BOTTOM", panel, "BOTTOM", 0, 35)
|
||||
prevBtn:SetText("上一页")
|
||||
prevBtn:SetScript("OnClick", function()
|
||||
if self.currentPage > 1 then
|
||||
print("[分页] 切换到上一页:", self.currentPage - 1)
|
||||
self.currentPage = self.currentPage - 1
|
||||
-- 确保物品始终保持排序
|
||||
self:SortSlotItems(slot)
|
||||
-- 强制清理旧的预览内容
|
||||
if panel.previewFrame then
|
||||
panel.previewFrame:Hide()
|
||||
panel.previewFrame:SetParent(nil)
|
||||
panel.previewFrame = nil
|
||||
end
|
||||
self:ShowItemPreview(slot, panel)
|
||||
end
|
||||
end)
|
||||
@ -793,11 +1028,20 @@ function SM_ItemCollectionUI:CreatePageButtons(panel, slot)
|
||||
-- 下一页按钮
|
||||
local nextBtn = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
|
||||
nextBtn:SetSize(60, 24)
|
||||
nextBtn:SetPoint("BOTTOM", panel, "BOTTOM", 160, 30)
|
||||
nextBtn:SetPoint("BOTTOM", panel, "BOTTOM", 160, 35)
|
||||
nextBtn:SetText("下一页")
|
||||
nextBtn:SetScript("OnClick", function()
|
||||
if self.currentPage < self.totalPages then
|
||||
print("[分页] 切换到下一页:", self.currentPage + 1)
|
||||
self.currentPage = self.currentPage + 1
|
||||
-- 确保物品始终保持排序
|
||||
self:SortSlotItems(slot)
|
||||
-- 强制清理旧的预览内容
|
||||
if panel.previewFrame then
|
||||
panel.previewFrame:Hide()
|
||||
panel.previewFrame:SetParent(nil)
|
||||
panel.previewFrame = nil
|
||||
end
|
||||
self:ShowItemPreview(slot, panel)
|
||||
end
|
||||
end)
|
||||
@ -811,11 +1055,138 @@ function SM_ItemCollectionUI:CreatePageButtons(panel, slot)
|
||||
|
||||
-- 页码文本
|
||||
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
|
||||
pageText:SetPoint("BOTTOM", panel, "BOTTOM", 80, 40)
|
||||
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:SortSlotItems(slot)
|
||||
if not slot or not slot.items or #slot.items == 0 then
|
||||
print("[排序] 槽位", slot and slot.invType or "未知", "为空或没有物品,无需排序")
|
||||
return
|
||||
end
|
||||
|
||||
print("[排序] 开始对槽位", slot.invType, "中的", #slot.items, "个物品排序")
|
||||
|
||||
-- 对物品按照已获得状态进行排序,已获得的排在前面
|
||||
local sortedItems = {}
|
||||
|
||||
-- 首先创建一个带状态的物品列表
|
||||
for _, itemID in ipairs(slot.items) do
|
||||
local isObtained = false
|
||||
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
|
||||
isObtained = item.obtained
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
table.insert(sortedItems, {id = itemID, obtained = isObtained})
|
||||
end
|
||||
|
||||
-- 按照获得状态进行排序
|
||||
table.sort(sortedItems, function(a, b)
|
||||
if a.obtained and not b.obtained then
|
||||
return true -- a排在b前面
|
||||
elseif not a.obtained and b.obtained then
|
||||
return false -- b排在a前面
|
||||
else
|
||||
-- 如果获得状态相同,按ID排序
|
||||
return a.id < b.id
|
||||
end
|
||||
end)
|
||||
|
||||
-- 打印排序前后的状态
|
||||
local beforeIDs = {}
|
||||
for i, id in ipairs(slot.items) do
|
||||
beforeIDs[i] = id
|
||||
end
|
||||
|
||||
local afterIDs = {}
|
||||
for i, item in ipairs(sortedItems) do
|
||||
afterIDs[i] = item.id
|
||||
end
|
||||
|
||||
print("[排序] 排序前:", table.concat(beforeIDs, ", "))
|
||||
print("[排序] 排序后:", table.concat(afterIDs, ", "))
|
||||
|
||||
-- 更新排序后的物品ID列表
|
||||
local newItems = {}
|
||||
for _, item in ipairs(sortedItems) do
|
||||
table.insert(newItems, item.id)
|
||||
end
|
||||
slot.items = newItems
|
||||
|
||||
print("[排序] 槽位", slot.invType, "物品排序完成")
|
||||
return true -- 返回true表示排序成功
|
||||
end
|
||||
|
||||
-- 新增函数:更新物品获得状态并重新排序显示
|
||||
function SM_ItemCollectionUI:UpdateItemObtainedStatus(itemID, isObtained)
|
||||
if not itemID then return end
|
||||
|
||||
print("[更新] 更新物品", itemID, "获得状态为", isObtained and "已获得" or "未获得")
|
||||
|
||||
-- 更新物品缓存中的状态
|
||||
local itemUpdated = false
|
||||
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
|
||||
item.obtained = isObtained
|
||||
itemUpdated = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not itemUpdated then
|
||||
print("[更新] 警告:物品", itemID, "未在缓存中找到")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 如果物品是新获得的,添加到NewItems表中
|
||||
if isObtained then
|
||||
if not SM_Collections.NewItems then
|
||||
SM_Collections.NewItems = {}
|
||||
end
|
||||
if not SM_Collections.NewItems.item then
|
||||
SM_Collections.NewItems.item = {}
|
||||
end
|
||||
SM_Collections.NewItems.item[tonumber(itemID)] = true
|
||||
print("[更新] 物品", itemID, "标记为新获得")
|
||||
end
|
||||
|
||||
-- 找到当前物品所在的槽位
|
||||
local currentSlot = nil
|
||||
for _, slot in ipairs(self.ALL_SLOTS) do
|
||||
for _, slotItemID in ipairs(slot.items) do
|
||||
if tonumber(slotItemID) == tonumber(itemID) then
|
||||
currentSlot = slot
|
||||
break
|
||||
end
|
||||
end
|
||||
if currentSlot then break end
|
||||
end
|
||||
|
||||
if not currentSlot then
|
||||
print("[更新] 警告:物品", itemID, "未在任何槽位中找到")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 重新排序当前槽位的物品
|
||||
self:SortSlotItems(currentSlot)
|
||||
|
||||
-- 如果当前正在显示该槽位,则刷新显示
|
||||
if self.currentPanel and self.currentSelectedButton and self.currentSelectedButton.slotData == currentSlot then
|
||||
print("[更新] 刷新当前显示的槽位", currentSlot.name)
|
||||
self:ShowItemPreview(currentSlot, self.currentPanel)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- 清除所有按钮
|
||||
|
||||
@ -38,3 +38,57 @@ SM_Collections.NewItems = {
|
||||
card = {}, -- 新获得的卡牌ID
|
||||
item = {} -- 新获得的物品ID
|
||||
}
|
||||
|
||||
-- 添加ADDON_LOADED事件处理以初始化数据库
|
||||
local InitFrame = CreateFrame("Frame")
|
||||
InitFrame:RegisterEvent("ADDON_LOADED")
|
||||
InitFrame:SetScript("OnEvent", function(self, event, addonName)
|
||||
if addonName == "SM_CollectionSystem" then
|
||||
print("收藏系统插件加载:", addonName)
|
||||
|
||||
-- 确保SM_CollectionsDB存在
|
||||
if not SM_CollectionsDB then
|
||||
SM_CollectionsDB = {
|
||||
mountCache = { mounts = {} },
|
||||
companionCache = { companions = {} },
|
||||
cardCache = { cards = {} },
|
||||
itemCache = { items = {} }
|
||||
}
|
||||
end
|
||||
|
||||
-- 确保缓存子表存在
|
||||
if not SM_CollectionsDB.mountCache then
|
||||
SM_CollectionsDB.mountCache = { mounts = {} }
|
||||
end
|
||||
if not SM_CollectionsDB.companionCache then
|
||||
SM_CollectionsDB.companionCache = { companions = {} }
|
||||
end
|
||||
if not SM_CollectionsDB.cardCache then
|
||||
SM_CollectionsDB.cardCache = { cards = {} }
|
||||
end
|
||||
if not SM_CollectionsDB.itemCache then
|
||||
SM_CollectionsDB.itemCache = { items = {} }
|
||||
end
|
||||
|
||||
-- 确保items子表存在
|
||||
if not SM_CollectionsDB.itemCache.items then
|
||||
SM_CollectionsDB.itemCache.items = {}
|
||||
end
|
||||
|
||||
-- 注册插件消息(在3.3.5中不需要显式注册前缀)
|
||||
print("收藏系统消息通道已准备就绪")
|
||||
|
||||
-- 设置清理数据库的函数,在每次登录时调用
|
||||
self:RegisterEvent("PLAYER_LOGIN")
|
||||
elseif event == "PLAYER_LOGIN" then
|
||||
-- 在登录时清理过期的缓存条目
|
||||
SM_Collections.CleanupExpiredCacheEntries()
|
||||
print("收藏系统玩家登录初始化完成")
|
||||
end
|
||||
end)
|
||||
|
||||
-- 清理过期的缓存条目
|
||||
function SM_Collections.CleanupExpiredCacheEntries()
|
||||
-- 这里可以添加逻辑来删除很久未更新的缓存条目
|
||||
-- 或者根据服务器版本检测不再有效的条目
|
||||
end
|
||||
|
||||
216
SM_Events.lua
216
SM_Events.lua
@ -360,15 +360,82 @@ end
|
||||
|
||||
-- 处理收藏状态更新
|
||||
function SM_Collections:HandleCollectionUpdate(msg)
|
||||
|
||||
print("[收藏更新] 收到消息:", msg)
|
||||
local data = self:MessageSplit(msg, "|")
|
||||
|
||||
if #data >= 3 then
|
||||
local itemType = data[1]
|
||||
local itemID = tonumber(data[2])
|
||||
local isObtained = (data[3] == "1")
|
||||
|
||||
|
||||
print("[收藏更新] 解析消息:", itemType, itemID, isObtained and "已获得" or "未获得")
|
||||
|
||||
-- 确保数据结构存在
|
||||
if not SM_CollectionsDB then
|
||||
SM_CollectionsDB = {
|
||||
mountCache = { mounts = {} },
|
||||
companionCache = { companions = {} },
|
||||
cardCache = { cards = {} },
|
||||
itemCache = { items = {} }
|
||||
}
|
||||
end
|
||||
|
||||
-- 同步更新SM_CollectionsDB数据,确保立即生效
|
||||
if itemType == "mount" and SM_CollectionsDB.mountCache then
|
||||
local found = false
|
||||
for i, mount in ipairs(SM_CollectionsDB.mountCache.mounts or {}) do
|
||||
if mount.id == itemID then
|
||||
mount.obtained = isObtained
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found and isObtained then
|
||||
table.insert(SM_CollectionsDB.mountCache.mounts, {id = itemID, obtained = true})
|
||||
end
|
||||
elseif itemType == "companion" and SM_CollectionsDB.companionCache then
|
||||
local found = false
|
||||
for i, companion in ipairs(SM_CollectionsDB.companionCache.companions or {}) do
|
||||
if companion.id == itemID then
|
||||
companion.obtained = isObtained
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found and isObtained then
|
||||
table.insert(SM_CollectionsDB.companionCache.companions, {id = itemID, obtained = true})
|
||||
end
|
||||
elseif itemType == "card" and SM_CollectionsDB.cardCache then
|
||||
local found = false
|
||||
for i, card in ipairs(SM_CollectionsDB.cardCache.cards or {}) do
|
||||
if card.id == itemID then
|
||||
card.obtained = isObtained
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found and isObtained then
|
||||
table.insert(SM_CollectionsDB.cardCache.cards, {id = itemID, obtained = true})
|
||||
end
|
||||
elseif itemType == "item" and SM_CollectionsDB.itemCache then
|
||||
local found = false
|
||||
for i, item in ipairs(SM_CollectionsDB.itemCache.items or {}) do
|
||||
if tonumber(item.id) == itemID then
|
||||
item.obtained = isObtained
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found and isObtained then
|
||||
table.insert(SM_CollectionsDB.itemCache.items, {id = itemID, obtained = true})
|
||||
end
|
||||
|
||||
-- 物品收藏更新后,立即重新排序当前显示的物品
|
||||
print("[收藏更新] 物品获取:", itemID, isObtained and "已获得" or "未获得")
|
||||
|
||||
-- 立即执行物品排序,不等待延迟
|
||||
self:ForceItemReordering(itemID)
|
||||
end
|
||||
|
||||
if itemID and itemType then
|
||||
-- 更新本地数据
|
||||
@ -402,12 +469,10 @@ function SM_Collections:HandleCollectionUpdate(msg)
|
||||
-- 如果是新获得的物品,记录到NewItems表中
|
||||
if isObtained then
|
||||
self.NewItems.item[itemID] = true
|
||||
|
||||
print("[收藏系统] 新获得物品:", itemID)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- 检查当前是否显示了对应类型的面板
|
||||
local isCurrentPanel = false
|
||||
if self.MainFrame then
|
||||
@ -418,11 +483,6 @@ function SM_Collections:HandleCollectionUpdate(msg)
|
||||
if self.CurrentPanel.scrollChild and self.CurrentPanel.scrollChild.buttons and #self.CurrentPanel.scrollChild.buttons > 0 then
|
||||
local firstButton = self.CurrentPanel.scrollChild.buttons[1]
|
||||
|
||||
if firstButton then
|
||||
|
||||
|
||||
end
|
||||
|
||||
if firstButton and firstButton.itemType then
|
||||
if firstButton.itemType == "mount" then
|
||||
inferredTabID = 1
|
||||
@ -451,9 +511,6 @@ function SM_Collections:HandleCollectionUpdate(msg)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-- 无论当前面板是什么,都尝试刷新UI
|
||||
-- 如果不是当前面板,RefreshCollectionStatus函数内部会自己处理
|
||||
self:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
@ -510,14 +567,112 @@ function SM_Collections:HandleCollectionUpdate(msg)
|
||||
end)
|
||||
companionReloadFrame:Show()
|
||||
end
|
||||
|
||||
-- 如果是物品且获得了新物品,强制重新加载物品面板
|
||||
if itemType == "item" and isObtained then
|
||||
-- 使用 3.3.5 支持的延迟执行方法
|
||||
local itemReloadFrame = CreateFrame("Frame")
|
||||
itemReloadFrame:SetScript("OnUpdate", function(self, elapsed)
|
||||
self.elapsed = (self.elapsed or 0) + elapsed
|
||||
if self.elapsed >= 0.1 then
|
||||
self:SetScript("OnUpdate", nil)
|
||||
self:Hide()
|
||||
-- 如果物品页面当前打开,刷新显示
|
||||
if SM_Collections.MainFrame and SM_Collections.MainFrame.tabID == 4 then
|
||||
-- 如果当前正在使用物品收藏UI
|
||||
if SM_ItemCollectionUI and SM_ItemCollectionUI.currentPanel then
|
||||
-- 如果有当前选中的按钮和对应的槽位数据
|
||||
if SM_ItemCollectionUI.currentSelectedButton and SM_ItemCollectionUI.currentSelectedButton.slotData then
|
||||
-- 对当前槽位的物品重新排序并刷新显示
|
||||
local slot = SM_ItemCollectionUI.currentSelectedButton.slotData
|
||||
SM_ItemCollectionUI:SortSlotItems(slot)
|
||||
SM_ItemCollectionUI:ShowItemPreview(slot, SM_ItemCollectionUI.currentPanel)
|
||||
end
|
||||
end
|
||||
-- 这里调用现有的显示物品函数
|
||||
SM_Collections:ShowItems()
|
||||
end
|
||||
end
|
||||
end)
|
||||
itemReloadFrame:Show()
|
||||
end
|
||||
end
|
||||
else
|
||||
print("[收藏更新] 消息格式不正确:", msg)
|
||||
end
|
||||
end
|
||||
|
||||
-- 强制物品重排序,立即执行而不等待延迟
|
||||
function SM_Collections:ForceItemReordering(updatedItemID)
|
||||
print("[排序] 强制重排序:", updatedItemID)
|
||||
|
||||
-- 确保物品收藏UI存在
|
||||
if not SM_ItemCollectionUI then
|
||||
print("[排序] 物品收藏UI不存在,无法排序")
|
||||
return
|
||||
end
|
||||
|
||||
-- 确保物品槽位数据存在
|
||||
if not SM_ItemCollectionUI.ALL_SLOTS then
|
||||
print("[排序] 物品槽位数据不存在,无法排序")
|
||||
return
|
||||
end
|
||||
|
||||
-- 是否当前显示的是物品面板
|
||||
local isItemPanelVisible = (SM_Collections.MainFrame and SM_Collections.MainFrame.tabID == 4)
|
||||
print("[排序] 物品面板是否可见:", isItemPanelVisible)
|
||||
|
||||
-- 对所有槽位进行排序
|
||||
local allSlots = SM_ItemCollectionUI.ALL_SLOTS
|
||||
local targetSlot = nil
|
||||
|
||||
-- 找到包含更新物品的槽位
|
||||
for _, slot in ipairs(allSlots) do
|
||||
local containsItem = false
|
||||
for _, itemID in ipairs(slot.items or {}) do
|
||||
if tonumber(itemID) == tonumber(updatedItemID) then
|
||||
targetSlot = slot
|
||||
containsItem = true
|
||||
print("[排序] 在槽位", slot.invType, "中找到物品", updatedItemID)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- 无论是否包含物品,都对该槽位进行排序
|
||||
if #(slot.items or {}) > 0 then
|
||||
print("[排序] 对槽位", slot.invType, "进行排序")
|
||||
SM_ItemCollectionUI:SortSlotItems(slot)
|
||||
end
|
||||
end
|
||||
|
||||
-- 如果物品面板可见,且找到了包含更新物品的槽位
|
||||
if isItemPanelVisible and targetSlot then
|
||||
print("[排序] 物品面板可见,立即刷新")
|
||||
|
||||
-- 如果当前显示的正是包含更新物品的槽位
|
||||
if SM_ItemCollectionUI.currentSelectedButton and
|
||||
SM_ItemCollectionUI.currentSelectedButton.slotData and
|
||||
SM_ItemCollectionUI.currentSelectedButton.slotData.invType == targetSlot.invType then
|
||||
|
||||
print("[排序] 刷新当前槽位:", targetSlot.invType)
|
||||
|
||||
-- 直接重新显示物品预览
|
||||
SM_ItemCollectionUI:ShowItemPreview(targetSlot, SM_ItemCollectionUI.currentPanel)
|
||||
|
||||
-- 强制立即重新加载整个物品面板
|
||||
SM_Collections:ShowItems()
|
||||
else
|
||||
-- 当前显示的不是包含更新物品的槽位,但我们仍然刷新当前显示
|
||||
print("[排序] 当前显示的不是目标槽位,刷新当前槽位")
|
||||
local currentSlot = SM_ItemCollectionUI.currentSelectedButton.slotData
|
||||
SM_ItemCollectionUI:ShowItemPreview(currentSlot, SM_ItemCollectionUI.currentPanel)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 消息处理函数
|
||||
function SM_Collections_MessageEvent(self, event, prefix, msg, type, sender)
|
||||
print("收到消息: 事件=", event, "前缀=", prefix, "类型=", type, "发送者=", sender)
|
||||
if event == 'CHAT_MSG_WHISPER' or event == 'CHAT_MSG_ADDON' then
|
||||
if prefix == 'SM_S_COLLECTIONS_MOUNTS' then
|
||||
SM_Collections:HandleMountsData(msg) -- 坐骑
|
||||
@ -533,13 +688,36 @@ function SM_Collections_MessageEvent(self, event, prefix, msg, type, sender)
|
||||
SM_Collections:HandleItemAttributesData(msg) -- 物品属性
|
||||
|
||||
elseif prefix == "SM_S_COLLECTION_UPDATE" then
|
||||
|
||||
SM_Collections:HandleCollectionUpdate(msg) --404行
|
||||
print("收到收藏更新消息:", msg)
|
||||
SM_Collections:HandleCollectionUpdate(msg)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 添加测试更新命令
|
||||
SLASH_SM_COLLECTIONS_TEST1 = "/smtest"
|
||||
SLASH_SM_COLLECTIONS_TEST2 = "/收藏测试"
|
||||
SlashCmdList["SM_COLLECTIONS_TEST"] = function(msg)
|
||||
-- 解析命令参数 /smtest item 12345 1
|
||||
local args = {}
|
||||
for word in msg:gmatch("%S+") do
|
||||
table.insert(args, word)
|
||||
end
|
||||
|
||||
local itemType = args[1] or "item"
|
||||
local itemID = tonumber(args[2] or "12345")
|
||||
local status = args[3] or "1"
|
||||
|
||||
print("执行测试更新命令: 类型=", itemType, "ID=", itemID, "状态=", status)
|
||||
|
||||
-- 构造测试消息
|
||||
local testMsg = itemType .. "|" .. itemID .. "|" .. status
|
||||
|
||||
-- 直接调用处理函数
|
||||
SM_Collections:HandleCollectionUpdate(testMsg)
|
||||
end
|
||||
|
||||
-- 事件监听框架
|
||||
local SM_Collections_EventFrame = CreateFrame('Frame', 'SM_Collections_EventFrame')
|
||||
SM_Collections_EventFrame:RegisterEvent('CHAT_MSG_WHISPER')
|
||||
@ -549,8 +727,8 @@ SM_Collections_EventFrame:SetScript('OnEvent', function(self, event, ...)
|
||||
if event == 'ADDON_LOADED' then
|
||||
local addonName = ...
|
||||
if addonName == "SM_CollectionSystem" then
|
||||
|
||||
|
||||
print("收藏系统插件加载完成")
|
||||
-- 在3.3.5中不需要显式注册前缀
|
||||
end
|
||||
elseif event == 'CHAT_MSG_ADDON' then
|
||||
SM_Collections_MessageEvent(self, event, ...)
|
||||
@ -572,7 +750,9 @@ SM_Collections_EventFrame:SetScript('OnEvent', function(self, event, ...)
|
||||
prefix == "SM_S_COLLECTIONS_CARDS" or
|
||||
prefix == "SM_S_COLLECTIONS_ITEMS" or
|
||||
prefix == "SM_S_COLLECTIONS_ATTRIBUTES" or
|
||||
prefix == "SM_S_COLLECTIONS_ITEM_ATTRIBUTES") then
|
||||
prefix == "SM_S_COLLECTIONS_ITEM_ATTRIBUTES" or
|
||||
prefix == "SM_S_COLLECTION_UPDATE") then
|
||||
print("收到系统私聊消息:", prefix, content:sub(1, 50))
|
||||
SM_Collections_MessageEvent(self, "CHAT_MSG_WHISPER", prefix, content)
|
||||
end
|
||||
end
|
||||
|
||||
@ -374,22 +374,54 @@ function SM_Collections:CreateListItems(parent, data, itemType, model, nameText,
|
||||
|
||||
-- 添加"NEW"标记,如果这个项目是新获得的
|
||||
if item.obtained and self.NewItems and self.NewItems[itemType] and self.NewItems[itemType][item.id] then
|
||||
local newTexture = button:CreateTexture(nil, "OVERLAY")
|
||||
newTexture:SetSize(32, 28)
|
||||
newTexture:SetPoint("TOPRIGHT", button, "TOPRIGHT", -5, -5)
|
||||
newTexture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\New_Icon")
|
||||
button.newTexture = newTexture
|
||||
-- 检查是否已经有NEW标记
|
||||
if not button.newTexture then
|
||||
local newTexture = button:CreateTexture(nil, "OVERLAY")
|
||||
newTexture:SetSize(32, 28)
|
||||
newTexture:SetPoint("TOPRIGHT", button, "TOPRIGHT", 10, 10)
|
||||
newTexture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\New_Icon")
|
||||
button.newTexture = newTexture
|
||||
|
||||
-- 在鼠标悬停时隐藏"NEW"标记
|
||||
button:HookScript("OnEnter", function(self)
|
||||
if self.newTexture then
|
||||
self.newTexture:Hide()
|
||||
-- 从NewItems表中移除
|
||||
if SM_Collections.NewItems and SM_Collections.NewItems[itemType] then
|
||||
SM_Collections.NewItems[itemType][item.id] = nil
|
||||
-- 先清除现有的鼠标处理函数,防止多次注册
|
||||
button:SetScript("OnEnter", nil)
|
||||
|
||||
-- 使用SetScript而不是HookScript,确保只有一个处理函数
|
||||
button:SetScript("OnEnter", function(self)
|
||||
print("[收藏系统] 按钮鼠标悬停:", itemType, item.id)
|
||||
if self.newTexture and self.newTexture:IsShown() then
|
||||
self.newTexture:Hide()
|
||||
-- 从NewItems表中移除
|
||||
if SM_Collections.NewItems and SM_Collections.NewItems[itemType] then
|
||||
SM_Collections.NewItems[itemType][item.id] = nil
|
||||
print("[收藏系统] 清除NEW标记:", itemType, item.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- 显示提示信息
|
||||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||||
if self.itemData then
|
||||
GameTooltip:SetText(self.itemData.name or "未知物品")
|
||||
else
|
||||
GameTooltip:SetText("收藏项目")
|
||||
end
|
||||
GameTooltip:Show()
|
||||
|
||||
-- 显示高亮
|
||||
if self.Highlight then
|
||||
self.Highlight:Show()
|
||||
end
|
||||
end)
|
||||
|
||||
button:SetScript("OnLeave", function(self)
|
||||
GameTooltip:Hide()
|
||||
if self.Highlight then
|
||||
self.Highlight:Hide()
|
||||
end
|
||||
end)
|
||||
else
|
||||
-- 如果已经有NEW标记,确保它是可见的
|
||||
button.newTexture:Show()
|
||||
end
|
||||
end
|
||||
|
||||
local ButtonIcon = nil
|
||||
@ -861,7 +893,6 @@ function SM_Collections:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
for _, button in ipairs(buttons) do
|
||||
if button.itemData and button.itemData.id == itemID then
|
||||
isCorrectPanel = true
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
@ -873,7 +904,6 @@ function SM_Collections:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
for _, button in ipairs(buttons) do
|
||||
if button.itemData and button.itemData.id == itemID then
|
||||
isCorrectPanel = true
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
@ -895,18 +925,20 @@ function SM_Collections:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
for _, button in ipairs(buttons) do
|
||||
if button.itemData and button.itemData.id == itemID then
|
||||
isCorrectPanel = true
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not isCorrectPanel then
|
||||
-- 如果是物品类型且确实需要刷新
|
||||
if itemType == "item" then
|
||||
-- 尝试更新物品模型边框
|
||||
self:RefreshItemModelBorders(itemID, isObtained)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- 查找对应的按钮并更新状态
|
||||
local updatedButton = nil
|
||||
local buttonFound = false
|
||||
@ -915,7 +947,6 @@ function SM_Collections:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
if button.itemData and button.itemData.id == itemID then
|
||||
buttonFound = true
|
||||
|
||||
|
||||
-- 更新获取状态
|
||||
button.itemData.obtained = isObtained
|
||||
|
||||
@ -928,8 +959,6 @@ function SM_Collections:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
local text = button:GetRegions()
|
||||
if text and text:GetObjectType() == "FontString" then
|
||||
text:SetTextColor(isObtained and 1 or 0.5, isObtained and 1 or 0.5, isObtained and 1 or 0.5)
|
||||
else
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@ -969,19 +998,45 @@ function SM_Collections:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
if not button.newTexture then
|
||||
local newTexture = button:CreateTexture(nil, "OVERLAY")
|
||||
newTexture:SetSize(32, 28)
|
||||
newTexture:SetPoint("TOPRIGHT", button, "TOPRIGHT", -5, -5)
|
||||
newTexture:SetPoint("TOPRIGHT", button, "TOPRIGHT", 10, 10)
|
||||
newTexture:SetTexture("Interface\\AddOns\\SM_CollectionSystem\\Textures\\New_Icon")
|
||||
button.newTexture = newTexture
|
||||
|
||||
-- 在鼠标悬停时隐藏"NEW"标记
|
||||
button:HookScript("OnEnter", function(self)
|
||||
if self.newTexture then
|
||||
-- 先清除现有的鼠标处理函数,防止多次注册
|
||||
button:SetScript("OnEnter", nil)
|
||||
|
||||
-- 使用SetScript而不是HookScript,确保只有一个处理函数
|
||||
button:SetScript("OnEnter", function(self)
|
||||
print("[收藏系统] 按钮鼠标悬停:", itemType, itemID)
|
||||
if self.newTexture and self.newTexture:IsShown() then
|
||||
self.newTexture:Hide()
|
||||
-- 从NewItems表中移除
|
||||
if SM_Collections.NewItems and SM_Collections.NewItems[itemType] then
|
||||
SM_Collections.NewItems[itemType][itemID] = nil
|
||||
print("[收藏系统] 清除NEW标记:", itemType, itemID)
|
||||
end
|
||||
end
|
||||
|
||||
-- 显示提示信息
|
||||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||||
if self.itemData then
|
||||
GameTooltip:SetText(self.itemData.name or "未知物品")
|
||||
else
|
||||
GameTooltip:SetText("收藏项目")
|
||||
end
|
||||
GameTooltip:Show()
|
||||
|
||||
-- 显示高亮
|
||||
if self.Highlight then
|
||||
self.Highlight:Show()
|
||||
end
|
||||
end)
|
||||
|
||||
button:SetScript("OnLeave", function(self)
|
||||
GameTooltip:Hide()
|
||||
if self.Highlight then
|
||||
self.Highlight:Hide()
|
||||
end
|
||||
end)
|
||||
else
|
||||
-- 如果已经有NEW标记,确保它是可见的
|
||||
@ -1013,7 +1068,6 @@ function SM_Collections:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
for i, btn in ipairs(obtainedButtons) do
|
||||
if btn == button then
|
||||
table.remove(obtainedButtons, i)
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
@ -1027,15 +1081,22 @@ function SM_Collections:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
end
|
||||
end
|
||||
|
||||
if not buttonFound then
|
||||
|
||||
end
|
||||
|
||||
-- 如果更新的是当前选中的项目,刷新右侧面板
|
||||
if updatedButton then
|
||||
local panel = self.CurrentPanel
|
||||
|
||||
OnItemClick(updatedButton, updatedButton.itemData, itemType, panel)
|
||||
-- 如果我们需要更新右侧面板
|
||||
if updatedButton and updatedButton.isSelected and self.MainFrame and self.MainFrame.RightSidePanel then
|
||||
-- 更新状态文本
|
||||
if self.MainFrame.RightSidePanel.statusText then
|
||||
local statusText = isObtained and "|cFF00FF00已获得|r" or "|cFFFF0000未获得|r"
|
||||
self.MainFrame.RightSidePanel.statusText:SetText(statusText)
|
||||
end
|
||||
|
||||
-- 更新属性文本颜色
|
||||
if self.MainFrame.RightSidePanel.attributesContainer then
|
||||
for _, child in ipairs({self.MainFrame.RightSidePanel.attributesContainer:GetChildren()}) do
|
||||
if child:IsObjectType("FontString") then
|
||||
child:SetTextColor(isObtained and 1 or 0.5, isObtained and 1 or 0.5, isObtained and 1 or 0.5)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 通知玩家
|
||||
@ -1064,6 +1125,89 @@ function SM_Collections:RefreshCollectionStatus(itemType, itemID, isObtained)
|
||||
end
|
||||
end
|
||||
|
||||
-- 新增函数:更新物品模型边框颜色
|
||||
function SM_Collections:RefreshItemModelBorders(itemID, isObtained)
|
||||
if not SM_ItemCollectionUI then return end
|
||||
|
||||
-- 遍历所有显示中的物品模型
|
||||
local previewFrame = SM_ItemCollectionUI.previewFrame
|
||||
if not previewFrame then return end
|
||||
|
||||
for _, child in ipairs({previewFrame:GetChildren()}) do
|
||||
-- 检查是DressUpModel类型(3D模型)还是Frame类型(图标)
|
||||
local isModelFrame = child:IsObjectType("DressUpModel")
|
||||
local isIconFrame = child:IsObjectType("Frame") and not child:IsObjectType("DressUpModel")
|
||||
|
||||
if (isModelFrame or isIconFrame) and child.itemData and child.itemData.id == itemID then
|
||||
-- 更新物品数据
|
||||
child.itemData.obtained = isObtained
|
||||
|
||||
-- 更新边框颜色
|
||||
if child.Border then
|
||||
if isObtained then
|
||||
child.Border:SetVertexColor(0, 1, 0, 1) -- 绿色边框
|
||||
else
|
||||
child.Border:SetVertexColor(1, 0, 0, 1) -- 红色边框
|
||||
end
|
||||
end
|
||||
|
||||
-- 如果是新获得的物品且已获得,添加"NEW"标记
|
||||
if isObtained and self.NewItems and self.NewItems.item and self.NewItems.item[itemID] then
|
||||
-- 使用SM_ItemCollectionUI的统一处理函数
|
||||
if SM_ItemCollectionUI and SM_ItemCollectionUI.HandleNewItemIcon then
|
||||
SM_ItemCollectionUI:HandleNewItemIcon(child, itemID)
|
||||
end
|
||||
end
|
||||
|
||||
-- 对于图标类物品(颈部、戒指、饰品),更新图标灰度
|
||||
if isIconFrame then
|
||||
for _, texture in ipairs({child:GetRegions()}) do
|
||||
if texture:IsObjectType("Texture") and texture:GetDrawLayer() == "ARTWORK" then
|
||||
-- 这可能是物品图标
|
||||
if isObtained then
|
||||
texture:SetDesaturated(false)
|
||||
texture:SetVertexColor(1, 1, 1)
|
||||
else
|
||||
texture:SetDesaturated(true)
|
||||
texture:SetVertexColor(0.7, 0.7, 0.7)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 更新高光颜色
|
||||
local highlightTextures = { child:GetRegions() }
|
||||
for _, region in ipairs(highlightTextures) do
|
||||
if region:GetDrawLayer() == "HIGHLIGHT" then
|
||||
if isObtained then
|
||||
region:SetVertexColor(0, 1, 0, 0.7) -- 绿色高光
|
||||
else
|
||||
region:SetVertexColor(1, 0, 0, 0.7) -- 红色高光
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 如果此模型当前被选中,更新右侧面板
|
||||
if child.isSelected and SM_Collections.MainFrame and SM_Collections.MainFrame.RightSidePanel then
|
||||
-- 更新状态文本
|
||||
if SM_Collections.MainFrame.RightSidePanel.statusText then
|
||||
local statusText = isObtained and "|cFF00FF00已获得|r" or "|cFFFF0000未获得|r"
|
||||
SM_Collections.MainFrame.RightSidePanel.statusText:SetText(statusText)
|
||||
end
|
||||
|
||||
-- 更新属性文本颜色
|
||||
if SM_Collections.MainFrame.RightSidePanel.attributesContainer then
|
||||
for _, child in ipairs({SM_Collections.MainFrame.RightSidePanel.attributesContainer:GetChildren()}) do
|
||||
if child:IsObjectType("FontString") then
|
||||
child:SetTextColor(isObtained and 1 or 0.5, isObtained and 1 or 0.5, isObtained and 1 or 0.5)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 重新排序收藏按钮
|
||||
function SM_Collections:ResortCollectionButtons(scrollChild, itemType)
|
||||
if not scrollChild or not scrollChild.buttons then
|
||||
@ -1072,16 +1216,23 @@ function SM_Collections:ResortCollectionButtons(scrollChild, itemType)
|
||||
|
||||
local buttons = scrollChild.buttons
|
||||
|
||||
-- 按照已获得状态排序
|
||||
-- 按照已获得状态排序:已获得的排在前面
|
||||
table.sort(buttons, function(a, b)
|
||||
if a.itemData.obtained and not b.itemData.obtained then
|
||||
return true
|
||||
elseif not a.itemData.obtained and b.itemData.obtained then
|
||||
return false
|
||||
else
|
||||
-- 如果获得状态相同,按ID排序
|
||||
return a.itemData.id < b.itemData.id
|
||||
if a.itemData and b.itemData then
|
||||
if a.itemData.obtained and not b.itemData.obtained then
|
||||
return true -- a排在b前面
|
||||
elseif not a.itemData.obtained and b.itemData.obtained then
|
||||
return false -- b排在a前面
|
||||
else
|
||||
-- 如果获得状态相同,按名称或ID排序
|
||||
if a.itemData.name and b.itemData.name then
|
||||
return a.itemData.name < b.itemData.name
|
||||
else
|
||||
return a.itemData.id < b.itemData.id
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end)
|
||||
|
||||
-- 重新设置位置
|
||||
@ -1099,6 +1250,11 @@ function SM_Collections:ResortCollectionButtons(scrollChild, itemType)
|
||||
button:SetPoint("TOPLEFT", 30, -(i - 1) * (buttonHeight + spacing))
|
||||
end
|
||||
end
|
||||
|
||||
-- 强制滚动到顶部显示已获得的物品
|
||||
if scrollChild:GetParent() and scrollChild:GetParent().ScrollBar then
|
||||
scrollChild:GetParent().ScrollBar:SetValue(0)
|
||||
end
|
||||
end
|
||||
|
||||
-- 注册事件处理
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
#include "Common.h" // 基础类型定义(uint32, uint8等)
|
||||
#include "DatabaseEnv.h" // 数据库操作相关
|
||||
#include <unordered_map> // 哈希表容器,用于快速查找
|
||||
#include <set> // 集合容器,用于存储不重复的收藏项
|
||||
#include <set> // 集合容器,用于存储不重复的收藏项
|
||||
#include <SpellAuraDefines.h>
|
||||
|
||||
// 前向声明Player类,避免循环包含
|
||||
class Player;
|
||||
@ -34,58 +35,73 @@ enum CollectionCategory : uint8
|
||||
enum CollectionBonusType : uint8
|
||||
{
|
||||
// 基础类型
|
||||
BONUS_NONE = 0, // 空 - 无加成
|
||||
BONUS_NONE = 0, // 空 - 无加成
|
||||
|
||||
// 生命值相关
|
||||
BONUS_HEALTH = 1, // 生命值
|
||||
BONUS_HEALTH = 1, // 生命值
|
||||
|
||||
// 基础属性相关
|
||||
BONUS_ALL_STATS = 2, // 全属性
|
||||
BONUS_STRENGTH = 3, // 力量
|
||||
BONUS_AGILITY = 4, // 敏捷
|
||||
BONUS_STAMINA = 5, // 耐力
|
||||
BONUS_INTELLECT = 6, // 智力
|
||||
BONUS_SPIRIT = 7, // 精神
|
||||
BONUS_ALL_STATS = 2, // 全属性
|
||||
BONUS_STRENGTH = 3, // 力量
|
||||
BONUS_AGILITY = 4, // 敏捷
|
||||
BONUS_STAMINA = 5, // 耐力
|
||||
BONUS_INTELLECT = 6, // 智力
|
||||
BONUS_SPIRIT = 7, // 精神
|
||||
|
||||
// 攻击强度相关
|
||||
BONUS_MELEE_ATTACK_POWER = 8, // 近战攻击强度
|
||||
BONUS_RANGED_ATTACK_POWER = 9, // 远程攻击强度
|
||||
BONUS_MELEE_ATTACK_POWER = 8, // 近战攻击强度
|
||||
BONUS_RANGED_ATTACK_POWER = 9, // 远程攻击强度
|
||||
|
||||
// 攻击速度相关
|
||||
BONUS_CASTING_SPEED = 10, // 施法速度
|
||||
BONUS_MELEE_HASTE = 11, // 近战攻击速度
|
||||
BONUS_RANGED_HASTE = 12, // 远程攻击速度
|
||||
BONUS_CASTING_SPEED = 10, // 施法速度
|
||||
BONUS_MELEE_HASTE = 11, // 近战攻击速度
|
||||
BONUS_RANGED_HASTE = 12, // 远程攻击速度
|
||||
|
||||
// 法术强度相关
|
||||
BONUS_SPELL_POWER = 13, // 法术强度(通用)
|
||||
BONUS_ARCANE_SPELL_POWER = 14, // 奥术法术强度
|
||||
BONUS_FIRE_SPELL_POWER = 15, // 火焰法术强度
|
||||
BONUS_FROST_SPELL_POWER = 16, // 冰霜法术强度
|
||||
BONUS_HOLY_SPELL_POWER = 17, // 神圣法术强度
|
||||
BONUS_SHADOW_SPELL_POWER = 18, // 暗影法术强度
|
||||
BONUS_NATURE_SPELL_POWER = 19, // 自然法术强度
|
||||
BONUS_SPELL_POWER = 13, // 法术强度(通用)
|
||||
BONUS_ARCANE_SPELL_POWER = 14, // 奥术法术强度
|
||||
BONUS_FIRE_SPELL_POWER = 15, // 火焰法术强度
|
||||
BONUS_FROST_SPELL_POWER = 16, // 冰霜法术强度
|
||||
BONUS_HOLY_SPELL_POWER = 17, // 神圣法术强度
|
||||
BONUS_SHADOW_SPELL_POWER = 18, // 暗影法术强度
|
||||
BONUS_NATURE_SPELL_POWER = 19, // 自然法术强度
|
||||
|
||||
// 治疗效果
|
||||
BONUS_HEALING = 20, // 治疗效果
|
||||
BONUS_HEALING = 20, // 治疗效果
|
||||
|
||||
// 造成伤害相关
|
||||
BONUS_DAMAGE_ALL = 21, // 造成所有伤害
|
||||
BONUS_DAMAGE_PHYSICAL = 22, // 造成物理伤害
|
||||
BONUS_DAMAGE_MAGIC = 23, // 造成法术伤害
|
||||
BONUS_DAMAGE_ARCANE = 24, // 造成奥术伤害
|
||||
BONUS_DAMAGE_FIRE = 25, // 造成火焰伤害
|
||||
BONUS_DAMAGE_FROST = 26, // 造成冰霜伤害
|
||||
BONUS_DAMAGE_HOLY = 27, // 造成神圣伤害
|
||||
BONUS_DAMAGE_SHADOW = 28, // 造成暗影伤害
|
||||
BONUS_DAMAGE_NATURE = 29, // 造成自然伤害
|
||||
BONUS_DAMAGE_ALL = 21, // 造成所有伤害
|
||||
BONUS_DAMAGE_PHYSICAL = 22, // 造成物理伤害
|
||||
BONUS_DAMAGE_MAGIC = 23, // 造成法术伤害
|
||||
BONUS_DAMAGE_ARCANE = 24, // 造成奥术伤害
|
||||
BONUS_DAMAGE_FIRE = 25, // 造成火焰伤害
|
||||
BONUS_DAMAGE_FROST = 26, // 造成冰霜伤害
|
||||
BONUS_DAMAGE_HOLY = 27, // 造成神圣伤害
|
||||
BONUS_DAMAGE_SHADOW = 28, // 造成暗影伤害
|
||||
BONUS_DAMAGE_NATURE = 29, // 造成自然伤害
|
||||
|
||||
// 受到伤害相关
|
||||
BONUS_DAMAGE_TAKEN_ALL = 30, // 受到所有伤害(减伤)
|
||||
BONUS_DAMAGE_TAKEN_ALL = 30, // 受到所有伤害(减伤)
|
||||
|
||||
// 暴击相关
|
||||
BONUS_CRIT_DAMAGE = 31, // 造成暴击伤害
|
||||
BONUS_CRIT_DAMAGE = 31, // 造成暴击伤害
|
||||
|
||||
MAX_BONUS_TYPE // 最大值标记
|
||||
// 添加缺失的能量类型
|
||||
BONUS_MANA = 32, // 法力值上限
|
||||
BONUS_RAGE = 33, // 怒气值上限
|
||||
BONUS_FOCUS = 34, // 集中值上限
|
||||
BONUS_ENERGY = 35, // 能量值上限
|
||||
|
||||
// 添加抗性类型
|
||||
BONUS_ARMOR = 36, // 护甲值
|
||||
BONUS_HOLY_RESISTANCE = 37, // 神圣抗性
|
||||
BONUS_FIRE_RESISTANCE = 38, // 火焰抗性
|
||||
BONUS_NATURE_RESISTANCE = 39, // 自然抗性
|
||||
BONUS_FROST_RESISTANCE = 40, // 冰霜抗性
|
||||
BONUS_SHADOW_RESISTANCE = 41, // 暗影抗性
|
||||
BONUS_ARCANE_RESISTANCE = 42, // 奥术抗性
|
||||
|
||||
MAX_BONUS_TYPE // 最大值标记
|
||||
};
|
||||
|
||||
/**
|
||||
@ -269,6 +285,23 @@ public:
|
||||
*/
|
||||
void ApplyCollectionBonuses(Player* player);
|
||||
|
||||
/**
|
||||
* 为玩家应用或移除收藏物品的属性加成
|
||||
* @param player 玩家指针
|
||||
* @param config 收藏配置信息
|
||||
* @param apply true=应用属性加成,false=移除属性加成
|
||||
*/
|
||||
void ApplyCollectionBonus(Player* player, CollectionConfig const* config, bool apply = true);
|
||||
|
||||
/**
|
||||
* 从收藏中移除物品
|
||||
* @param player 玩家指针
|
||||
* @param category 收藏分类
|
||||
* @param itemId 物品ID
|
||||
* @return 是否成功移除
|
||||
*/
|
||||
bool RemoveFromCollection(Player* player, CollectionCategory category, uint32 itemId);
|
||||
|
||||
/**
|
||||
* 处理来自插件的消息
|
||||
* @param sender 发送消息的玩家
|
||||
@ -398,6 +431,13 @@ public:
|
||||
*/
|
||||
bool IsCardCreature(uint32 creatureId) const;
|
||||
|
||||
/**
|
||||
* 检查是否是物品收藏中的物品
|
||||
* @param itemId 物品EntryD
|
||||
* @return 是否是物品收藏中的物品
|
||||
*/
|
||||
bool IsCollectibleItem(uint32 itemId) const;
|
||||
|
||||
/**
|
||||
* 检查并更新所有收藏
|
||||
* @param player 玩家指针
|
||||
@ -409,20 +449,21 @@ public:
|
||||
*/
|
||||
void Initialize();
|
||||
|
||||
/**
|
||||
* 召唤坐骑(随机或指定)
|
||||
* @param player 玩家指针
|
||||
* @param mountId 如果为0,则随机召唤;否则召唤指定ID的坐骑
|
||||
* @return 是否成功召唤坐骑
|
||||
*/
|
||||
bool SummonMountLogic(Player* player, uint32 mountId = 0);
|
||||
|
||||
private:
|
||||
/**
|
||||
* 将收藏分类枚举转换为字符串
|
||||
* @param category 收藏分类枚举
|
||||
* @return 对应的中文字符串
|
||||
*/
|
||||
std::string GetCategoryString(CollectionCategory category) const;
|
||||
|
||||
/**
|
||||
* 为玩家应用单个收藏物品的属性加成
|
||||
* @param player 玩家指针
|
||||
* @param config 收藏配置信息
|
||||
*/
|
||||
void ApplyCollectionBonus(Player* player, CollectionConfig const* config);
|
||||
std::string GetCategoryString(CollectionCategory category) const;
|
||||
|
||||
// 存储所有收藏配置,key是(分类+物品ID)的组合,value是配置信息
|
||||
std::unordered_map<uint64, CollectionConfig> _collectionConfigs;
|
||||
@ -478,6 +519,29 @@ private:
|
||||
* @return 物品类型字符串
|
||||
*/
|
||||
std::string GetItemTypeString(CollectionItemType itemType) const;
|
||||
|
||||
/**
|
||||
* 为玩家应用收藏系统的 Aura 效果
|
||||
* @param player 目标玩家
|
||||
* @param auraType Aura 类型
|
||||
* @param value 属性值
|
||||
* @param misc MiscValue 参数
|
||||
* @param miscB MiscValueB 参数
|
||||
*/
|
||||
void ApplyCollectionAura(Player* player, AuraType auraType, float value, int32 misc, int32 miscB, bool apply);
|
||||
|
||||
/**
|
||||
* 移除玩家的所有收藏系统Aura
|
||||
* @param player 目标玩家
|
||||
*/
|
||||
void RemoveAllCollectionAuras(Player* player);
|
||||
|
||||
public:
|
||||
/**
|
||||
* 重新应用玩家的所有收藏属性加成
|
||||
* @param player 目标玩家
|
||||
*/
|
||||
void ReapplyAllCollectionBonuses(Player* player);
|
||||
};
|
||||
|
||||
// 定义全局访问宏,方便在其他地方调用收藏管理器
|
||||
|
||||
@ -95,10 +95,10 @@ void CollectionMgr::LoadCollectionConfigs()
|
||||
|
||||
_collectionConfigs.clear();
|
||||
|
||||
// 先加载属性加成表
|
||||
// 先加载属性加成表
|
||||
LoadAttributeBonuses();
|
||||
|
||||
// 再加载各个收藏配置表
|
||||
// 再加载各个收藏配置表
|
||||
LoadMountConfigs();
|
||||
LoadPetConfigs();
|
||||
LoadCardConfigs();
|
||||
@ -270,11 +270,11 @@ bool CollectionMgr::AddToCollection(Player* player, CollectionCategory category,
|
||||
// 添加收藏
|
||||
_playerCollections[playerGuid].collections.insert(std::make_pair(category, itemId));
|
||||
|
||||
// 应用属性加成
|
||||
auto configItr = _collectionConfigs.find(key);
|
||||
if (configItr != _collectionConfigs.end())
|
||||
// 应用属性加成 - 使用默认的 apply=true
|
||||
CollectionConfig const* config = GetCollectionConfig(category, itemId);
|
||||
if (config)
|
||||
{
|
||||
ApplyCollectionBonus(player, &configItr->second);
|
||||
ApplyCollectionBonus(player, config, true); // 明确指定 apply=true
|
||||
}
|
||||
|
||||
// 发送通知给客户端
|
||||
@ -303,7 +303,7 @@ bool CollectionMgr::AddToCollection(Player* player, CollectionCategory category,
|
||||
SendAddonMessageToPlayer(player, "SM_S_COLLECTION_UPDATE", message.str(), CHAT_MSG_WHISPER);
|
||||
|
||||
// 记录日志
|
||||
LOG_INFO("server.loading", "Player {} ({}) added item {} to collection category %u", player->GetName().c_str(), playerGuid, itemId, static_cast<uint32>(category));
|
||||
LOG_INFO("server.loading", "Player {} ({}) added item {} to collection category {}", player->GetName().c_str(), playerGuid, itemId, static_cast<uint32>(category));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -331,7 +331,7 @@ void CollectionMgr::SavePlayerCollections(Player* player)
|
||||
if (itr == _playerCollections.end())
|
||||
return;
|
||||
|
||||
// 删除现有数据
|
||||
// 删除现有数据
|
||||
std::string deleteQuery = "DELETE FROM 玩家收藏数据 WHERE 玩家GUID = {}";
|
||||
CharacterDatabase.Execute(deleteQuery.c_str(), playerGuid);
|
||||
|
||||
@ -344,47 +344,426 @@ void CollectionMgr::SavePlayerCollections(Player* player)
|
||||
}
|
||||
}
|
||||
|
||||
void CollectionMgr::ApplyCollectionBonus(Player* player, CollectionConfig const* config)
|
||||
/**
|
||||
* 为玩家应用或移除收藏物品的属性加成
|
||||
* @param player 玩家指针 - 只对玩家自己应用加成
|
||||
* @param config 收藏配置信息,包含属性加成数据
|
||||
* @param apply true=应用属性加成,false=移除属性加成
|
||||
*/
|
||||
void CollectionMgr::ApplyCollectionBonus(Player* player, CollectionConfig const* config, bool apply)
|
||||
{
|
||||
// 确保只对玩家应用加成
|
||||
if (!player || !player->IsPlayer())
|
||||
return;
|
||||
|
||||
// 遍历配置中的所有属性加成(最多5个)
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
{
|
||||
CollectionBonus const& bonus = config->bonuses[i];
|
||||
|
||||
// 跳过无效的属性加成
|
||||
if (bonus.type == BONUS_NONE || bonus.value == 0.0f)
|
||||
continue;
|
||||
|
||||
// 根据属性类型应用不同的修改器
|
||||
// 根据数值类型确定修饰符类型:百分比或固定值
|
||||
UnitModifierType modType = bonus.valueType == VALUE_PERCENTAGE ? BASE_PCT : BASE_VALUE;
|
||||
bool isPercentage = bonus.valueType == VALUE_PERCENTAGE;
|
||||
|
||||
switch (bonus.type)
|
||||
{
|
||||
// ========== 基础属性(通过 UnitMods 处理)==========
|
||||
case BONUS_HEALTH:
|
||||
if (bonus.valueType == VALUE_PERCENTAGE)
|
||||
player->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, bonus.value, true);
|
||||
else
|
||||
player->HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, bonus.value, true);
|
||||
// 生命值加成
|
||||
player->HandleStatModifier(UNIT_MOD_HEALTH, modType, bonus.value, apply);
|
||||
break;
|
||||
|
||||
case BONUS_ALL_STATS:
|
||||
// 全属性加成 - 对所有基础属性(力量、敏捷、耐力、智力、精神)生效
|
||||
for (int32 stat = STAT_STRENGTH; stat < MAX_STATS; ++stat)
|
||||
{
|
||||
if (bonus.valueType == VALUE_PERCENTAGE)
|
||||
player->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + stat), BASE_PCT, bonus.value, true);
|
||||
else
|
||||
player->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + stat), BASE_VALUE, bonus.value, true);
|
||||
player->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + stat), modType, bonus.value, apply);
|
||||
player->ApplyStatBuffMod(Stats(stat), bonus.value, apply);
|
||||
}
|
||||
break;
|
||||
|
||||
case BONUS_STRENGTH:
|
||||
if (bonus.valueType == VALUE_PERCENTAGE)
|
||||
player->HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_PCT, bonus.value, true);
|
||||
else
|
||||
player->HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, bonus.value, true);
|
||||
// 力量属性加成
|
||||
player->HandleStatModifier(UNIT_MOD_STAT_STRENGTH, modType, bonus.value, apply);
|
||||
player->ApplyStatBuffMod(STAT_STRENGTH, bonus.value, apply);
|
||||
break;
|
||||
|
||||
// 继续为其他属性类型添加实现...
|
||||
case BONUS_AGILITY:
|
||||
// 敏捷属性加成
|
||||
player->HandleStatModifier(UNIT_MOD_STAT_AGILITY, modType, bonus.value, apply);
|
||||
player->ApplyStatBuffMod(STAT_AGILITY, bonus.value, apply);
|
||||
break;
|
||||
|
||||
case BONUS_STAMINA:
|
||||
// 耐力属性加成
|
||||
player->HandleStatModifier(UNIT_MOD_STAT_STAMINA, modType, bonus.value, apply);
|
||||
player->ApplyStatBuffMod(STAT_STAMINA, bonus.value, apply);
|
||||
break;
|
||||
|
||||
case BONUS_INTELLECT:
|
||||
// 智力属性加成
|
||||
player->HandleStatModifier(UNIT_MOD_STAT_INTELLECT, modType, bonus.value, apply);
|
||||
player->ApplyStatBuffMod(STAT_INTELLECT, bonus.value, apply);
|
||||
break;
|
||||
|
||||
case BONUS_SPIRIT:
|
||||
// 精神属性加成
|
||||
player->HandleStatModifier(UNIT_MOD_STAT_SPIRIT, modType, bonus.value, apply);
|
||||
player->ApplyStatBuffMod(STAT_SPIRIT, bonus.value, apply);
|
||||
break;
|
||||
|
||||
case BONUS_MELEE_ATTACK_POWER:
|
||||
// 近战攻击强度加成
|
||||
player->HandleStatModifier(UNIT_MOD_ATTACK_POWER, modType, bonus.value, apply);
|
||||
break;
|
||||
|
||||
case BONUS_RANGED_ATTACK_POWER:
|
||||
// 远程攻击强度加成
|
||||
player->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, modType, bonus.value, apply);
|
||||
break;
|
||||
|
||||
// ========== 通过 Aura 系统处理的复杂属性 ==========
|
||||
case BONUS_CASTING_SPEED:
|
||||
// 施法速度加成 - 通过 Aura 系统
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK, bonus.value, 0, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_MELEE_HASTE:
|
||||
// 近战攻击速度加成 - 通过 Aura 系统
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_MELEE_HASTE, bonus.value, 0, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_RANGED_HASTE:
|
||||
// 远程攻击速度加成 - 通过 Aura 系统
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_RANGED_HASTE, bonus.value, 0, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_SPELL_POWER:
|
||||
// 法术强度加成 - 通过 Aura 系统
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT, bonus.value, SPELL_SCHOOL_MASK_MAGIC, -1000, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_MAGIC, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_ARCANE_SPELL_POWER:
|
||||
// 奥术法术强度加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT, bonus.value, SPELL_SCHOOL_MASK_ARCANE, -1000, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_ARCANE, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_FIRE_SPELL_POWER:
|
||||
// 火焰法术强度加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT, bonus.value, SPELL_SCHOOL_MASK_FIRE, -1000, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_FIRE, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_FROST_SPELL_POWER:
|
||||
// 冰霜法术强度加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT, bonus.value, SPELL_SCHOOL_MASK_FROST, -1000, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_FROST, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_HOLY_SPELL_POWER:
|
||||
// 神圣法术强度加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT, bonus.value, SPELL_SCHOOL_MASK_HOLY, -1000, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_HOLY, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_SHADOW_SPELL_POWER:
|
||||
// 暗影法术强度加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT, bonus.value, SPELL_SCHOOL_MASK_SHADOW, -1000, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_SHADOW, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_NATURE_SPELL_POWER:
|
||||
// 自然法术强度加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT, bonus.value, SPELL_SCHOOL_MASK_NATURE, -1000, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_NATURE, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_HEALING:
|
||||
// 治疗效果加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT, bonus.value, SPELL_SCHOOL_MASK_MAGIC, -1000, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_HEALING, bonus.value, SPELL_SCHOOL_MASK_MAGIC, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_ALL:
|
||||
// 造成所有伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, bonus.value, SPELL_SCHOOL_MASK_ALL, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_ALL, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_PHYSICAL:
|
||||
// 造成物理伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, bonus.value, SPELL_SCHOOL_MASK_NORMAL, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_NORMAL, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_MAGIC:
|
||||
// 造成法术伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, bonus.value, SPELL_SCHOOL_MASK_MAGIC, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_MAGIC, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_ARCANE:
|
||||
// 造成奥术伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, bonus.value, SPELL_SCHOOL_MASK_ARCANE, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_ARCANE, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_FIRE:
|
||||
// 造成火焰伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, bonus.value, SPELL_SCHOOL_MASK_FIRE, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_FIRE, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_FROST:
|
||||
// 造成冰霜伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, bonus.value, SPELL_SCHOOL_MASK_FROST, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_FROST, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_HOLY:
|
||||
// 造成神圣伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, bonus.value, SPELL_SCHOOL_MASK_HOLY, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_HOLY, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_SHADOW:
|
||||
// 造成暗影伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, bonus.value, SPELL_SCHOOL_MASK_SHADOW, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_SHADOW, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_NATURE:
|
||||
// 造成自然伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, bonus.value, SPELL_SCHOOL_MASK_NATURE, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_DONE, bonus.value, SPELL_SCHOOL_MASK_NATURE, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_DAMAGE_TAKEN_ALL:
|
||||
// 受到所有伤害加成
|
||||
if (isPercentage)
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, bonus.value, SPELL_SCHOOL_MASK_ALL, 0, apply);
|
||||
else
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_DAMAGE_TAKEN, bonus.value, SPELL_SCHOOL_MASK_ALL, 0, apply);
|
||||
break;
|
||||
|
||||
case BONUS_CRIT_DAMAGE:
|
||||
// 造成暴击伤害加成
|
||||
ApplyCollectionAura(player, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, bonus.value, SPELL_SCHOOL_MASK_ALL, 0, apply);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WARN("collection", "玩家 {} 遇到未知的属性加成类型: {}",
|
||||
player->GetName(), static_cast<uint32>(bonus.type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 应用所有属性加成后,更新玩家的统计信息
|
||||
player->UpdateAllStats();
|
||||
player->UpdateSpellDamageAndHealingBonus();
|
||||
|
||||
sLog->outMessage("server", LogLevel::LOG_LEVEL_INFO,
|
||||
"已为玩家 {} {} 收藏属性加成", player->GetName(), apply ? "应用" : "移除");
|
||||
}
|
||||
|
||||
/**
|
||||
* 从收藏中移除物品
|
||||
* @param player 玩家指针
|
||||
* @param category 收藏分类
|
||||
* @param itemId 物品ID
|
||||
* @return 是否成功移除
|
||||
*/
|
||||
bool CollectionMgr::RemoveFromCollection(Player* player, CollectionCategory category, uint32 itemId)
|
||||
{
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
uint32 playerGuid = player->GetGUID().GetCounter();
|
||||
|
||||
// 检查玩家数据是否存在
|
||||
auto playerItr = _playerCollections.find(playerGuid);
|
||||
if (playerItr == _playerCollections.end())
|
||||
return false;
|
||||
|
||||
// 检查是否在收藏中
|
||||
auto collectionPair = std::make_pair(category, itemId);
|
||||
auto collectionItr = playerItr->second.collections.find(collectionPair);
|
||||
if (collectionItr == playerItr->second.collections.end())
|
||||
return false;
|
||||
|
||||
// 从收藏中移除
|
||||
playerItr->second.collections.erase(collectionItr);
|
||||
|
||||
// 发送通知给客户端
|
||||
std::string itemType;
|
||||
switch (category)
|
||||
{
|
||||
case COLLECTION_MOUNT:
|
||||
itemType = "mount";
|
||||
break;
|
||||
case COLLECTION_PET:
|
||||
itemType = "companion";
|
||||
break;
|
||||
case COLLECTION_CARD:
|
||||
itemType = "card";
|
||||
break;
|
||||
case COLLECTION_ITEM:
|
||||
itemType = "item";
|
||||
break;
|
||||
default:
|
||||
itemType = "unknown";
|
||||
}
|
||||
|
||||
std::ostringstream message;
|
||||
message << itemType << "|" << itemId << "|0"; // 0表示移除
|
||||
SendAddonMessageToPlayer(player, "SM_S_COLLECTION_UPDATE", message.str(), CHAT_MSG_WHISPER);
|
||||
|
||||
// 记录日志
|
||||
LOG_INFO("server.loading", "Player {} ({}) removed item {} from collection category {}",
|
||||
player->GetName().c_str(), playerGuid, itemId, static_cast<uint32>(category));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为玩家应用或移除收藏系统的 Aura 效果
|
||||
* @param player 目标玩家
|
||||
* @param auraType Aura 类型
|
||||
* @param value 属性值
|
||||
* @param misc MiscValue 参数
|
||||
* @param miscB MiscValueB 参数
|
||||
* @param apply true=应用Aura,false=移除Aura
|
||||
*/
|
||||
void CollectionMgr::ApplyCollectionAura(Player* player, AuraType auraType, float value, int32 misc, int32 miscB, bool apply)
|
||||
{
|
||||
if (!player || !player->IsPlayer())
|
||||
return;
|
||||
|
||||
// 创建一个特殊的收藏系统法术ID
|
||||
uint32 collectionSpellId = 999999; // 使用一个不会与现有法术冲突的ID
|
||||
|
||||
if (apply)
|
||||
{
|
||||
// 获取或创建SpellInfo
|
||||
SpellInfo* spellInfo = const_cast<SpellInfo*>(sSpellMgr->GetSpellInfo(collectionSpellId));
|
||||
if (!spellInfo)
|
||||
{
|
||||
LOG_WARN("server.loading", "收藏系统Aura法术 {} 不存在,需要动态创建", collectionSpellId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 修改SpellInfo的效果来匹配我们需要的Aura
|
||||
spellInfo->Effects[0].Effect = SPELL_EFFECT_APPLY_AURA;
|
||||
spellInfo->Effects[0].ApplyAuraName = auraType;
|
||||
spellInfo->Effects[0].BasePoints = static_cast<int32>(value);
|
||||
spellInfo->Effects[0].MiscValue = misc;
|
||||
spellInfo->Effects[0].MiscValueB = miscB;
|
||||
|
||||
// 应用Aura到玩家
|
||||
if (Aura* aura = Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, player, player))
|
||||
{
|
||||
// 在这里设置持续时间
|
||||
aura->SetDuration(-1); // 永久持续
|
||||
aura->SetMaxDuration(-1);
|
||||
aura->ApplyForTargets();
|
||||
|
||||
LOG_DEBUG("server.loading", "为玩家 {} 应用收藏Aura: 类型={}, 数值={}",
|
||||
player->GetName(), static_cast<uint32>(auraType), value);
|
||||
}
|
||||
}
|
||||
else // 移除 Aura
|
||||
{
|
||||
// 移除特定类型的收藏Aura
|
||||
// 遍历玩家身上所有应用的光环
|
||||
for (Unit::AuraApplicationMap::iterator itr = player->GetAppliedAuras().begin(); itr != player->GetAppliedAuras().end(); ++itr)
|
||||
{
|
||||
AuraApplication* aurApp = itr->second;
|
||||
Aura* aura = aurApp->GetBase();
|
||||
// 检查是否是收藏系统创建的Aura,并且Aura类型匹配
|
||||
if (aura->GetId() == collectionSpellId && aura->GetSpellInfo()->Effects[0].ApplyAuraName == auraType)
|
||||
{
|
||||
player->RemoveAura(aurApp);
|
||||
LOG_DEBUG("server.loading", "从玩家 {} 移除收藏Aura: 类型={}, 数值={}",
|
||||
player->GetName(), static_cast<uint32>(auraType), value);
|
||||
return; // 假设每个类型只有一个Aura,找到并移除后即可返回
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除玩家的所有收藏系统Aura
|
||||
* @param player 目标玩家
|
||||
*/
|
||||
void CollectionMgr::RemoveAllCollectionAuras(Player* player)
|
||||
{
|
||||
if (!player || !player->IsPlayer())
|
||||
return;
|
||||
|
||||
// 移除所有收藏系统相关的Aura
|
||||
uint32 collectionSpellId = 999999;
|
||||
player->RemoveAurasDueToSpell(collectionSpellId);
|
||||
|
||||
LOG_DEBUG("server.loading", "已移除玩家 {} 的所有收藏系统Aura", player->GetName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新应用玩家的所有收藏属性加成
|
||||
* 当玩家的收藏发生变化时调用此方法
|
||||
* @param player 目标玩家
|
||||
*/
|
||||
void CollectionMgr::ReapplyAllCollectionBonuses(Player* player)
|
||||
{
|
||||
if (!player || !player->IsPlayer())
|
||||
return;
|
||||
|
||||
// 先移除所有现有的收藏Aura
|
||||
RemoveAllCollectionAuras(player);
|
||||
|
||||
// 重新应用所有收藏的属性加成
|
||||
ApplyCollectionBonuses(player);
|
||||
|
||||
LOG_DEBUG("server.loading", "已重新应用玩家 {} 的所有收藏属性加成", player->GetName());
|
||||
}
|
||||
|
||||
void CollectionMgr::LoadPlayerCollections(Player* player)
|
||||
@ -409,11 +788,11 @@ void CollectionMgr::LoadPlayerCollections(Player* player)
|
||||
uint32 itemId = fields[1].Get<uint32>();
|
||||
if (category >= MAX_COLLECTION_CATEGORY)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Player {} has invalid collection category, skipping.", playerGuid);
|
||||
LOG_ERROR("server.loading", "Player {} has invalid collection category, skipping.", playerGuid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查配置是否存在(使用新的配置结构)
|
||||
// 检查配置是否存在(使用新的配置结构)
|
||||
bool configExists = false;
|
||||
switch (category)
|
||||
{
|
||||
@ -433,7 +812,7 @@ void CollectionMgr::LoadPlayerCollections(Player* player)
|
||||
|
||||
if (!configExists)
|
||||
{
|
||||
LOG_WARN("sql.sql", "Player {} has collection item {} in category {} but no config exists, skipping.", playerGuid, itemId, uint32(category));
|
||||
LOG_WARN("server.loading", "Player {} has collection item {} in category {} but no config exists, skipping.", playerGuid, itemId, uint32(category));
|
||||
continue;
|
||||
}
|
||||
_playerCollections[playerGuid].collections.insert(std::make_pair(category, itemId));
|
||||
@ -549,7 +928,7 @@ CollectionBonusType CollectionMgr::GetBonusTypeFromString(std::string const& bon
|
||||
CollectionValueType CollectionMgr::GetValueTypeFromString(std::string const& valueStr) const
|
||||
{
|
||||
if (valueStr == "固定值") return VALUE_FIXED;
|
||||
if (valueStr == "百分比(加法叠加)") return VALUE_PERCENTAGE;
|
||||
if (valueStr == "百分比") return VALUE_PERCENTAGE;
|
||||
return VALUE_FIXED;
|
||||
}
|
||||
|
||||
@ -643,7 +1022,7 @@ void CollectionMgr::HandleAddonRequest(Player* player, const std::string& prefix
|
||||
}
|
||||
else if (command == "GET_ITEMS")
|
||||
{
|
||||
SendItemsData(player);
|
||||
SendItemsData(player); // 不要在插件中发送 改为玩家登录发送数据
|
||||
}
|
||||
else if (command == "GET_ATTRIBUTES")
|
||||
{
|
||||
@ -792,10 +1171,17 @@ void CollectionMgr::SendItemsData(Player* player)
|
||||
{
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
// 临时召唤 NPC 2334,持续 0.1 秒 (100 毫秒)
|
||||
if (TempSummon* summon = player->SummonCreature(2334, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 100))
|
||||
{
|
||||
// 召唤成功的处理逻辑(如果需要)
|
||||
}
|
||||
|
||||
std::ostringstream data;
|
||||
uint32 count = 0;
|
||||
|
||||
// 遍历物品配置
|
||||
// 遍历物品配置
|
||||
for (auto const& pair : _itemConfigs)
|
||||
{
|
||||
uint32 itemId = pair.first;
|
||||
@ -813,15 +1199,14 @@ void CollectionMgr::SendItemsData(Player* player)
|
||||
data << (hasCollected ? "1" : "0") << "|";
|
||||
data << itemTypeStr;
|
||||
count++;
|
||||
if (count % 10 == 0)
|
||||
{
|
||||
SendAddonMessageToPlayer(player, "SM_S_COLLECTIONS_ITEMS", data.str(), CHAT_MSG_WHISPER);
|
||||
|
||||
sLog->outMessage("server", LogLevel::LOG_LEVEL_INFO, "SM_S_COLLECTIONS_ITEMS1:{} ", data.str());
|
||||
SendAddonMessageToPlayer(player, "SM_S_COLLECTIONS_ITEMS", data.str(), CHAT_MSG_WHISPER);
|
||||
|
||||
sLog->outMessage("server", LogLevel::LOG_LEVEL_INFO, "SM_S_COLLECTIONS_ITEMS1:{} ", data.str());
|
||||
|
||||
data.str("");
|
||||
data.clear();
|
||||
|
||||
data.str("");
|
||||
data.clear();
|
||||
}
|
||||
}
|
||||
if (!data.str().empty())
|
||||
{
|
||||
@ -1164,6 +1549,12 @@ bool CollectionMgr::IsCardCreature(uint32 creatureId) const
|
||||
return _cardConfigs.find(creatureId) != _cardConfigs.end();
|
||||
}
|
||||
|
||||
//检查是否是物品收藏中的物品
|
||||
bool CollectionMgr::IsCollectibleItem(uint32 itemId) const
|
||||
{
|
||||
return _itemConfigs.find(itemId) != _itemConfigs.end();
|
||||
}
|
||||
|
||||
// 检查并更新所有收藏
|
||||
void CollectionMgr::CheckAndUpdateAllCollections(Player* player)
|
||||
{
|
||||
@ -1201,3 +1592,92 @@ void CollectionMgr::CheckAndUpdateAllCollections(Player* player)
|
||||
|
||||
// 在CollectionMgr的初始化函数中调用钩子注册
|
||||
void CollectionMgr::Initialize(){ }
|
||||
|
||||
bool CollectionMgr::SummonMountLogic(Player* player, uint32 mountId)
|
||||
{
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
uint32 mountSpellIdToSummon = 0;
|
||||
std::string summonType = "";
|
||||
|
||||
if (mountId == 0) // 随机召唤
|
||||
{
|
||||
summonType = "随机";
|
||||
std::vector<uint32> collectedMounts;
|
||||
// 遍历所有坐骑配置
|
||||
for (auto const& pair : _mountConfigs)
|
||||
{
|
||||
uint32 mountSpellId = pair.first;
|
||||
// 检查玩家是否已收集该坐骑
|
||||
if (HasInCollection(player, COLLECTION_MOUNT, mountSpellId))
|
||||
{
|
||||
collectedMounts.push_back(mountSpellId);
|
||||
}
|
||||
}
|
||||
|
||||
if (collectedMounts.empty())
|
||||
{
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("您还没有收集任何坐骑!");
|
||||
LOG_INFO("collection", "玩家 {} 尝试随机召唤坐骑,但没有已收集的坐骑。", player->GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 随机选择一个已收集的坐骑
|
||||
uint32 randomIndex = urand(0, collectedMounts.size() - 1);
|
||||
mountSpellIdToSummon = collectedMounts[randomIndex];
|
||||
}
|
||||
else // 召唤指定坐骑
|
||||
{
|
||||
summonType = "指定";
|
||||
mountSpellIdToSummon = mountId;
|
||||
// 检查玩家是否已收集该坐骑
|
||||
if (!HasInCollection(player, COLLECTION_MOUNT, mountSpellIdToSummon))
|
||||
{
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("您尚未收集该坐骑!");
|
||||
LOG_INFO("collection", "玩家 {} 尝试召唤坐骑 {},但未收集。", player->GetName(), mountSpellIdToSummon);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取坐骑的SpellInfo
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(mountSpellIdToSummon);
|
||||
if (!spellInfo)
|
||||
{
|
||||
LOG_ERROR("collection", "{}召唤坐骑失败:找不到法术ID {} 的SpellInfo", summonType, mountSpellIdToSummon);
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("召唤坐骑失败,请联系GM。");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查玩家当前是否已骑乘,如果已骑乘则先下马
|
||||
if (player->IsMounted())
|
||||
{
|
||||
player->Dismount();
|
||||
LOG_INFO("collection", "玩家 {} 已下马,准备{}召唤坐骑。", player->GetName(), summonType);
|
||||
}
|
||||
|
||||
// 移除所有现有的SPELL_AURA_MOUNTED光环
|
||||
// 这确保了旧的坐骑buff图标被清除,并且不会干扰新的坐骑光环应用
|
||||
player->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
||||
|
||||
// 召唤坐骑
|
||||
// 将 triggered 参数设置为 true,表示由服务器触发,忽略施法时间、冷却等限制。
|
||||
SpellCastResult castResult = player->CastSpell(player, mountSpellIdToSummon, false);
|
||||
|
||||
// 记录施法结果
|
||||
sLog->outMessage("server", LogLevel::LOG_LEVEL_INFO, "玩家 {} 尝试{}召唤坐骑 {},施法结果: {}",
|
||||
player->GetName(), summonType, mountSpellIdToSummon, static_cast<uint32>(castResult));
|
||||
|
||||
if (castResult == SPELL_CAST_OK)
|
||||
{
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("您{}召唤了坐骑: {}", summonType, spellInfo->SpellName[0]);
|
||||
LOG_INFO("collection", "玩家 {} 成功{}召唤了坐骑 {}", player->GetName(), summonType, mountSpellIdToSummon);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("{}召唤坐骑失败,施法结果: {}", summonType, static_cast<uint32>(castResult));
|
||||
LOG_ERROR("collection", "玩家 {} {}召唤坐骑 {} 失败,施法结果: {}", player->GetName(), summonType, mountSpellIdToSummon, static_cast<uint32>(castResult));
|
||||
}
|
||||
|
||||
return castResult == SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
@ -24,6 +24,9 @@ public:
|
||||
// 直接更新所有收藏类型,不使用延迟
|
||||
sCollectionMgr->CheckAndUpdateAllCollections(player);
|
||||
|
||||
// 发送物品数据
|
||||
sCollectionMgr->SendItemsData(player);
|
||||
|
||||
// 告知玩家收藏系统已加载
|
||||
// player->WhisperToSelf("收藏系统: 已加载您的收藏数据");
|
||||
}
|
||||
@ -67,6 +70,54 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// 忘却技能时移除坐骑和小伙伴收藏的属性加成
|
||||
void OnPlayerForgotSpell(Player* player, uint32 spellId) override
|
||||
{
|
||||
if (!player || !player->IsInWorld())
|
||||
return;
|
||||
|
||||
// 检查是否是坐骑技能
|
||||
if (sCollectionMgr->IsMountSpell(spellId))
|
||||
{
|
||||
// 获取配置并移除属性加成
|
||||
CollectionConfig const* config = sCollectionMgr->GetCollectionConfig(COLLECTION_MOUNT, spellId);
|
||||
if (config)
|
||||
{
|
||||
// 移除属性加成
|
||||
sCollectionMgr->ApplyCollectionBonus(player, config, false);
|
||||
}
|
||||
|
||||
// 从收藏数据中移除
|
||||
sCollectionMgr->RemoveFromCollection(player, COLLECTION_MOUNT, spellId);
|
||||
|
||||
// 发送更新数据到客户端
|
||||
sCollectionMgr->SendMountsData(player);
|
||||
|
||||
sLog->outMessage("server", LogLevel::LOG_LEVEL_INFO,
|
||||
"玩家 {} 忘却坐骑法术 {},已移除收藏和属性加成", player->GetName(), spellId);
|
||||
}
|
||||
// 检查是否是小伙伴技能
|
||||
else if (sCollectionMgr->IsCompanionSpell(spellId))
|
||||
{
|
||||
// 获取配置并移除属性加成
|
||||
CollectionConfig const* config = sCollectionMgr->GetCollectionConfig(COLLECTION_PET, spellId);
|
||||
if (config)
|
||||
{
|
||||
// 移除属性加成
|
||||
sCollectionMgr->ApplyCollectionBonus(player, config, false);
|
||||
}
|
||||
|
||||
// 从收藏数据中移除
|
||||
sCollectionMgr->RemoveFromCollection(player, COLLECTION_PET, spellId);
|
||||
|
||||
// 发送更新数据到客户端
|
||||
sCollectionMgr->SendCompanionsData(player);
|
||||
|
||||
sLog->outMessage("server", LogLevel::LOG_LEVEL_INFO,
|
||||
"玩家 {} 忘却小伙伴法术 {},已移除收藏和属性加成", player->GetName(), spellId);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when a player kills a creature
|
||||
void OnPlayerCreatureKill(Player* killer, Creature* killed) override
|
||||
{
|
||||
@ -104,6 +155,41 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 玩家获取物品时检查物品收藏
|
||||
void OnPlayerStoreNewItem(Player* player, Item* item, uint32 count) override
|
||||
{
|
||||
if (!player || !player->IsInWorld() || !item)
|
||||
return;
|
||||
|
||||
uint32 itemId = item->GetEntry();
|
||||
|
||||
// 检查是否是物品收藏
|
||||
if (sCollectionMgr->IsCollectibleItem(itemId)) // 您需要实现 CollectionMgr::IsCollectibleItem 方法
|
||||
{
|
||||
// 检查是否已经收藏
|
||||
bool alreadyCollected = sCollectionMgr->HasInCollection(player, COLLECTION_ITEM, itemId);
|
||||
bool added = sCollectionMgr->AddToCollection(player, COLLECTION_ITEM, itemId);
|
||||
|
||||
if (added && !alreadyCollected)
|
||||
{
|
||||
sLog->outMessage("server", LogLevel::LOG_LEVEL_INFO, "玩家 {} 获得新物品 {},已添加到物品收藏。", player->GetName(), itemId);
|
||||
|
||||
// 发送实时更新通知
|
||||
std::ostringstream updateMsg;
|
||||
updateMsg << "item|" << itemId << "|1";
|
||||
sCollectionMgr->SendAddonMessageToPlayer(player, "SM_S_COLLECTION_UPDATE", updateMsg.str(), CHAT_MSG_WHISPER);
|
||||
|
||||
// 通知玩家
|
||||
std::string itemName = item->GetTemplate()->Name1;
|
||||
std::string message = "您已收集到新物品: " + itemName;
|
||||
ChatHandler(player->GetSession()).SendNotification(message.c_str());
|
||||
|
||||
// 发送更新数据到客户端
|
||||
sCollectionMgr->SendItemsData(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class CollectionSystem_WorldScript : public WorldScript
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user