local EquipData = class("EquipData", BaseData) local EquipEntity = require "app/userdata/equip/equip_entity" local EquipCfg = ConfigManager:getConfig("equip") local EquipLevelCfg = ConfigManager:getConfig("equip_level") local EquipRefineCfg = ConfigManager:getConfig("equip_refine") local EquipResonateCfg = ConfigManager:getConfig("equip_resonate") function EquipData:setDirty() self.data.isDirty = not self.data.isDirty end function EquipData:setDirtyRefineSuccess() self.data.isDirtyRefineSuccess = not self.data.isDirtyRefineSuccess end function EquipData:setDirtyRefineFail() self.data.isDirtyRefineFail = not self.data.isDirtyRefineFail end function EquipData:setDirtyResolve() self.data.isDirtyResolve = not self.data.isDirtyResolve end function EquipData:ctor() self.data.isDirty = false self.data.isDirtyRefineSuccess = false self.data.isDirtyRefineFail = false end function EquipData:clear() self.allEquipsCount = 0 end function EquipData:init(data) data = data or GConst.EMPTY_TABLE if EDITOR_MODE then Logger.logHighlight("装备数据") Logger.printTable(data) end if not data.equips then return end self.slotIdRedPoint = {} self.allEquips = {} self.allEquipsCount = 0 if data.equips then for i, equip in pairs(data.equips) do self:addEquip(equip) end end -- int64 equip_uid = 1; -- int32 level = 2; -- int32 refine = 3; -- int64 refine_fail = 4; self.slots = data.slots or {} end -- 武器功能是否开启 function EquipData:isWeaponOpen(showToast) if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.EQUIP_WEAPON, not showToast) then return false end return true end --@region 配置 -- 获取配置 function EquipData:getConfig(id) if id then return EquipCfg[id] else return EquipCfg end end -- 获取强化配置 function EquipData:getLevelConfig(id) if id then return EquipLevelCfg[id] else return EquipLevelCfg end end -- 获取精炼配置 function EquipData:getRefineConfig(id) if id then return EquipRefineCfg[id] else return EquipRefineCfg end end -- 获取共鸣配置 function EquipData:getResonateConfig(id) if id then return EquipResonateCfg[id] else return EquipResonateCfg end end -- 部位 1-6分别对应头盔,护腕,衣服,裤子,鞋子,手套 function EquipData:getPart(id) return self:getConfig(id).type end -- 装备图标 function EquipData:getIconRes(id) return tostring(self:getConfig(id).icon) end -- 品质(颜色) function EquipData:getQlt(id) return self:getConfig(id).qlt end -- 星级 function EquipData:getStar(id) return self:getConfig(id).star end -- 基础属性 function EquipData:getBaseAttr(id) return self:getConfig(id).base_attr end -- 装备名字 function EquipData:getName(id) return I18N:getText("equip", id, "name") end --附加属性 function EquipData:getExtraAttr(id, index) return self:getConfig(id)["extra_attr_" .. index] end --精炼额外数值总和 function EquipData:getRefineAttrAdd(refine, attrName) local attrAll = {type = attrName, num = 0} for i = 1, refine do if i <= refine then local value = self:getRefineAttr(i, attrName) attrAll.num = attrAll.num + (value or 0) end end return attrAll end --对应精炼等级的额外数值 function EquipData:getRefineAttr(refine, attrName) local cfg = self:getRefineConfig(refine) if attrName == "attr_atk" then return cfg.extra_attr_add_1 elseif attrName == "attr_hp" then return cfg.extra_attr_add_2 elseif attrName == "attr_normal_hurtp" then return cfg.extra_attr_add_3 elseif attrName == "attr_skill_hurtp" then return cfg.extra_attr_add_4 end end --@endregion --@region 装备基础 function EquipData:addEquip(equip, itemGetType, noDirty) if equip == nil then return end if self.allEquips[equip.uid] == nil then self.allEquipsCount = self.allEquipsCount + 1 end self.allEquips[equip.uid] = self:createEquipEntity(equip) if itemGetType then BIReport:postEquipGet(equip.uid, equip.cfg_id, itemGetType) end if not noDirty then self:setDirty() end end function EquipData:createEquipEntity(equip) return EquipEntity:create(equip) end function EquipData:getAllEquips(part, qlt, star, useHeroId) local list = {} for _, v in pairs(self.allEquips) do local matchAll = true -- 默认全部匹配 -- 品质+星级筛选(必须同时满足) if qlt ~= nil then if qlt ~= 0 then -- 先判断品质,再判断星级 if not (v:getQlt() <= qlt and (v:getQlt() ~= qlt or v:getStar() <= star)) then matchAll = false end end end -- 部位筛选 if matchAll and part ~= nil and part ~= 0 then if v:getPart() ~= part then matchAll = false end end -- 使用状态筛选 if matchAll and useHeroId ~= nil then local heroId = self:getEquipUseHero(v:getUid()) if heroId and heroId == useHeroId then matchAll = false end end -- 只有全部条件满足才加入 if matchAll then table.insert(list, v) end end return list end -- 获取所有装备数据 function EquipData:getAllEquipsSort(part, qlt, star, useHeroId) local list = self:getAllEquips(part, qlt, star, useHeroId) return self:sortEquipsList(list) end --排序 function EquipData:sortEquipsList(list) for _, equip in ipairs(list) do equip._sort = equip:getPower() * 10000000 + (10000000 - equip:getUid()) end -- 先品质后等级排序 table.sort(list, function(equip1, equip2) -- 权重相同的情况下,再单独比较评分(从高到低) -- 评分也相同,则按UID排序 return equip1._sort > equip2._sort end) return list end function EquipData:getEquipByUid(uid) if self.allEquips[uid] then return self.allEquips[uid] end end function EquipData:getEquipByCfgId(equipId) if equipId == nil then return end local entity = EquipEntity:create({cfg_id = equipId, extra_attrs = {}}) return entity end --endregion --@region 穿戴 --装备穿戴 function EquipData:onWearSuccess(slotId, uids) for _, uid in ipairs(uids) do local equip = self:getEquipByUid(uid) local part = equip:getPart() if part then local oldUid = self.slots[slotId].parts[part].equip_uid for i,info in ipairs(self.slots) do if i ~= slotId then if info.parts[part].equip_uid == uid then info.parts[part].equip_uid = oldUid end end end self.slots[slotId].parts[part].equip_uid = uid end end self:setDirty() end function EquipData:getEquipMaxScore(slotId, part) local equip = nil local maxScore = 0 local useUid = self:getPartEquipUid(slotId, part) if useUid ~= 0 then local useEquip = self:getEquipByUid(useUid) maxScore = useEquip:getPower() end for i, v in pairs(self.allEquips) do if v:getPart() == part then local isEquip = false for k2, info in ipairs(self.slots) do if info.parts[part] and info.parts[part].equip_uid == v:getUid() then isEquip = true break end end if not isEquip then local score = v:getPower() if score > maxScore then equip = v maxScore = score end end end end return equip end --获取对应位置的装备Id function EquipData:getPartEquipUid(slotId, part) local parts = self.slots[slotId].parts if parts then if part == nil then return parts else local partInfo = parts[part] if partInfo then return partInfo.equip_uid end end end return 0 end --@endregion --@region 装备强化 function EquipData:getLevelCost(refine) local cfg = self:getLevelConfig(refine) if cfg then return cfg.cost end end -----获取强化等级 function EquipData:getPartLv(slotId, part) local parts = self.slots[slotId].parts if parts then local partInfo = parts[part] if partInfo then return partInfo.level end end return 0 end function EquipData:isPartLvMax(slotId, part) local lv = self:getPartLv(slotId, part) return lv >= #self:getLevelConfig() end --基础属性额外强化值 function EquipData:getBaseAttrLvAdd(attrType, lv) local baseAttrAdd = 0 for i = 1, lv do if attrType == "attr_atk" then baseAttrAdd = baseAttrAdd + self:getLevelConfig(i).base_attr_add[1] else baseAttrAdd = baseAttrAdd + self:getLevelConfig(i).base_attr_add[2] end end return baseAttrAdd end function EquipData:onUpgradeSuccess(slotId, upgraded) upgraded = upgraded or {} for part, lv in pairs(upgraded) do if self.slots[slotId].parts[part] then self.slots[slotId].parts[part].level = lv end end self:setDirty() end --@endregion --@region 精炼 function EquipData:getRefineCost(refine) local cfg = self:getRefineConfig(refine) if cfg then return cfg.cost end end function EquipData:getRefineNeedLevel(refine) local cfg = self:getRefineConfig(refine) if cfg then return cfg.equip_level end end --获取精炼等级 function EquipData:getPartRefine(slotId, part) local parts = self.slots[slotId].parts if parts then local partInfo = parts[part] if partInfo then return partInfo.refine end end return 0 end function EquipData:isRefineLvMax(slotId, part) local lv = self:getPartRefine(slotId, part) return lv >= #self:getRefineConfig() end -- 精炼成功概率 function EquipData:getPartRefineFailPro(slotId, part) local parts = self.slots[slotId].parts if parts then local partInfo = parts[part] if partInfo then local cfgRefine = self:getRefineConfig(partInfo.refine + 1) if cfgRefine then return (cfgRefine.base_chance + partInfo.refine_fail * cfgRefine.chance_fail) / 100 end end end return 0 end function EquipData:onRefineSuccess(slotId, part, info) local offset = 0 local refine = self:getPartRefine(slotId, part) if refine < info.refine then local refine = self.slots[slotId].parts[part].refine self.slots[slotId].parts[part].refine = refine + 1 self.slots[slotId].parts[part].refine_fail = 0 offset = offset + 1 -- self:addPlayEffectParts(part) self:setDirtyRefineSuccess() else local fail = self.slots[slotId].parts[part].refine_fail self.slots[slotId].parts[part].refine_fail = fail + 1 self:setDirtyRefineFail() end end -- function EquipData:addPlayEffectParts(part) -- if self.lvUpSuccess == nil then -- self.lvUpSuccess = {} -- end -- table.insert(self.lvUpSuccess, part) -- end -- function EquipData:getPlayEffectParts() -- return table.refCopy(self.lvUpSuccess or {}) -- end -- function EquipData:clearPlayEffectParts() -- self.lvUpSuccess = {} -- end --@endregion --@region 套装 共鸣 function EquipData:getResonateList(type) if self.listResonate == nil then self.listResonate = {} local list = self:getResonateConfig() for i,v in pairs(list) do if self.listResonate[v.type] == nil then self.listResonate[v.type] = {} end v.id = i table.insert(self.listResonate[v.type], v) end for _,l in ipairs(self.listResonate) do table.sort(l, function (a, b) return a.id < b.id end) end end if self.listResonate[type] then return self.listResonate[type] end end function EquipData:getSlotAllAttr(slotId) local attr = {} for part = 1, 6 do local level = self:getPartLv(slotId, part) local refine = self:getPartRefine(slotId, part) for i = 1, level do local cfg = self:getLevelConfig(i) if attr[cfg.base_attr_add.type] then attr[cfg.base_attr_add.type] = attr[cfg.base_attr_add.type] + cfg.base_attr_add.num else attr[cfg.base_attr_add.type] = cfg.base_attr_add.num end end local uid = self:getPartEquipUid(slotId, part) if uid ~= 0 then local equipEntity = self:getEquipByUid(uid) local equipAttrs = equipEntity:getExtraMap() local baseAttrs = equipEntity:getBaseAttr() if attr[baseAttrs.type] then attr[baseAttrs.type] = attr[baseAttrs.type] + baseAttrs.num else attr[baseAttrs.type] = baseAttrs.num end for i,extraAttr in pairs(equipAttrs) do local name = GFunc.getAttrNameById(extraAttr.id) if attr[name] then attr[name] = attr[name] + extraAttr.value else attr[name] = extraAttr.value end local nowAttr = self:getRefineAttrAdd(refine, extraAttr.id) if nowAttr then if attr[nowAttr.type] then attr[nowAttr.type] = attr[nowAttr.type] + nowAttr.num else attr[nowAttr.type] = nowAttr.num end end end end end local resonateLevel = self:getResonateLevel(1, slotId) local list = self:getResonateList(1) for i,v in ipairs(list) do if i <= resonateLevel then if attr[v.attr.type] then attr[v.attr.type] = attr[v.attr.type] + v.attr.num else attr[v.attr.type] = v.attr.num end else break end end local resonateQlt = self:getResonateLevel(2, slotId) list = self:getResonateList(2) for i,v in ipairs(list) do if i <= resonateQlt then if attr[v.attr.type] then attr[v.attr.type] = attr[v.attr.type] + v.attr.num else attr[v.attr.type] = v.attr.num end else break end end local resonateRefine = self:getResonateLevel(3, slotId) list = self:getResonateList(3) for i,v in ipairs(list) do if i <= resonateRefine then if attr[v.attr.type] then attr[v.attr.type] = attr[v.type] + v.attr.num else attr[v.attr.type] = v.attr.num end else break end end return attr end function EquipData:getResonateMaxLevel(type) local list = self:getResonateList(type) return list and #list or 0 end function EquipData:getResonateLevelValue(type, value, value2) local list = self:getResonateList(type) local lv = 0 local nextLv = 0 local attrs = {} local attrNexts = {} for i,v in ipairs(list) do if type == 1 or type == 3 then if v.parameter[1] <= value then lv = i for _, vv in ipairs(v.attr) do attrs[vv.type] = (attrs[vv.type] or 0) + vv.num end else nextLv = v.parameter for _, vv in ipairs(v.attr) do attrNexts[vv.type] = (attrNexts[vv.type] or 0) + vv.num end break end elseif type == 2 then local isTrue = false if v.parameter[1] < value then isTrue = true elseif v.parameter[1] == value and v.parameter[2] <= value2 then isTrue = true end if isTrue then lv = i for _, vv in ipairs(v.attr) do attrs[vv.type] = (attrs[vv.type] or 0) + vv.num end else nextLv = v.parameter for _, vv in ipairs(v.attr) do attrNexts[vv.type] = (attrNexts[vv.type] or 0) + vv.num end break end end end return lv, nextLv, attrs, attrNexts, table.nums(list) end function EquipData:getResonateLevel(type, slotId) if type == 1 then local minLv = 999 for i = 1, 6 do local level = self:getPartLv(slotId, i) if level < minLv then minLv = level end end return self:getResonateLevelValue(type, minLv) elseif type == 2 then local qlt = 99 local star = 99 for i = 1, 6 do local uid = self:getPartEquipUid(slotId, i) local equip = self:getEquipByUid(uid) if equip == nil then qlt = 0 star = 0 break end local q = equip:getQlt() local s = equip:getStar() if qlt > q then qlt = q star = s elseif qlt == q then if star > s then qlt = q star = s end end end return self:getResonateLevelValue(type, qlt, star) elseif type == 3 then local minRefine = 999 for i = 1, 6 do local refine = self:getPartRefine(slotId, i) if refine < minRefine then minRefine = refine end end return self:getResonateLevelValue(type, minRefine) end end function EquipData:getEquipUseHero(uid) local equip = self:getEquipByUid(uid) local formation = DataManager.FormationData:getStageFormation() local part = equip:getPart() for i,info in ipairs(self.slots) do if info.parts[part] and info.parts[part].equip_uid and info.parts[part].equip_uid == uid then return formation[i] end end end --@endregion --@region 装备分解 -- 分解额外返还 function EquipData:getResolveReward(id) return self:getConfig(id).decompose end function EquipData:getAllEquipsSortInverted(part, qlt, star, use) local list = self:getAllEquips(part, qlt, star, use) return self:reverseTableInPlace(self:sortEquipsList(list)) end function EquipData:reverseTableInPlace(t) local i, j = 1, #t while i < j do t[i], t[j] = t[j], t[i] -- 交换元素 i = i + 1 j = j - 1 end return t end function EquipData:onResolveSuccess(uids) for i, uid in ipairs(uids) do if self.allEquips[uid] then self.allEquips[uid] = nil self.allEquipsCount = self.allEquipsCount - 1 end end self:setDirtyResolve() self:setDirty() end function EquipData:getLowestFiveGradeEquips() -- 1. 使用三重结构避免重复 local gradeMap = {} -- { [qlt] = { [star] = {equips} } } local gradeSet = {} -- 用于去重 { ["qlt-star"] = true } local gradeList = {} -- 最终排序列表 for _, equip in pairs(self.allEquips) do local qlt = equip:getQlt() local star = equip:getStar() local key = qlt.."-"..star -- 去重key -- 初始化数据结构 if not gradeMap[qlt] then gradeMap[qlt] = {} end if not gradeMap[qlt][star] then gradeMap[qlt][star] = {equips = {}} -- 只有首次遇到该组合时才加入排序列表 if not gradeSet[key] then gradeSet[key] = true table.insert(gradeList, {qlt = qlt, star = star}) end end table.insert(gradeMap[qlt][star].equips, equip) end -- 2. 排序(保持不变) table.sort(gradeList, function(a, b) return a.qlt < b.qlt or (a.qlt == b.qlt and a.star < b.star) end) -- 3. 构建结果 local gradeGroups = {} local allEquips = {} for i = 1, math.min(5, #gradeList) do local qlt = gradeList[i].qlt local star = gradeList[i].star local validEquips = {} -- 筛选未使用的装备 for _, equip in ipairs(gradeMap[qlt][star].equips) do if not self:getEquipUseHero(equip:getUid()) then table.insert(validEquips, equip) table.insert(allEquips, equip) end end -- 只有存在有效装备时才加入结果 if #validEquips > 0 then table.insert(gradeGroups, { qlt = qlt, star = star, equips = validEquips }) end end return gradeGroups, allEquips end --@endregion --region 红点 --装备可穿戴红点 function EquipData:hasEquipRedPoint(slotId) if not self:isOpen() then return false end return self:hasEquipRedPointBySlotId(slotId) end function EquipData:hasEquipRedPointBySlotId(slotId) if slotId == nil then return false end local redPoint = self.slotIdRedPoint[slotId] if redPoint ~= nil then return redPoint end if self:hasEquipWearRedPoint(slotId) then redPoint = true elseif self:hasEquipGrowthRedPointBySlotId(slotId) then redPoint = true else redPoint = false end self.slotIdRedPoint[slotId] = redPoint self.slotIdRedPointDirty = true return redPoint end function EquipData:isOpen(showToast) if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.HERO_EQUIP, not showToast) then return false end return true end function EquipData:hasEquipWearRedPointById(slotId) if not self:isOpen() then return false end return self:hasEquipWearRedPoint(slotId) end function EquipData:hasEquipWearRedPointByPart(slotId, part) if not self:isOpen() then return false end if self.allEquipsCount <= 0 then return false end if self:getEquipMaxScore(slotId, part) then return true elseif self:hasEquipEnhanceRedPoint(slotId, part) then return true elseif self:hasEquipRefineRedPoint(slotId, part) then return true end return false end function EquipData:hasEquipWearRedPoint(slotId) if self.allEquipsCount <= 0 then return false end if slotId then for i = 1, 6 do if self:getEquipMaxScore(slotId, i) then return true end end end return false end --装备养成红点 function EquipData:hasEquipGrowthRedPoint(slotId) if self.allEquipsCount <= 0 then return false end return self:hasEquipGrowthRedPointBySlotId(slotId) end function EquipData:hasEquipGrowthRedPointBySlotId(slotId) if slotId == nil then return false end for part = 1, 6 do if self:hasEquipEnhanceRedPoint(slotId, part) then return true elseif self:hasEquipRefineRedPoint(slotId, part) then return true end end return false end function EquipData:hasEquipGrowthRedPointBySlotIdAndPartId(slotId, part) if slotId == nil then return false end if self:hasEquipEnhanceRedPoint(slotId, part) then return true elseif self:hasEquipRefineRedPoint(slotId, part) then return true end return false end -- --强化红点 -- function EquipData:hasEquipGrowthEnhanceRedPoint(heroId) -- local heroEntity = DataManager.HeroData:getHeroById(heroId) -- local slotId = heroEntity:getMatchType() -- if slotId then -- for part = 1, 6 do -- if self:hasEquipEnhanceRedPoint(slotId, part) then -- return true -- end -- end -- end -- return false -- end -- --精炼红点 -- function EquipData:hasEquipGrowthRefineRedPoint(heroId) -- local heroEntity = DataManager.HeroData:getHeroById(heroId) -- local slotId = heroEntity:getMatchType() -- if slotId then -- for part = 1, 6 do -- if self:hasEquipRefineRedPoint(slotId, part) then -- return true -- end -- end -- end -- return false -- end --装备升级红点 function EquipData:hasEquipEnhanceRedPoint(slotId, part) if self.allEquipsCount <= 0 then return false end local level = self:getPartLv(slotId, part) local itemCost = self:getLevelCost(level + 1) if itemCost ~= nil then local costId = GFunc.getRewardId(itemCost) local costNum = GFunc.getRewardNum(itemCost) local count = DataManager.BagData.ItemData:getItemNumById(costId) if costNum <= count then return true end end return false end function EquipData:hasEquipRefineRedPoint(slotId, part) if self.allEquipsCount <= 0 then return false end local refine = self:getPartRefine(slotId, part) local needLevel = self:getRefineNeedLevel(refine + 1) if needLevel == nil or needLevel > self:getPartLv(slotId, part) then return false end local itemCost = self:getRefineCost(refine + 1) if itemCost ~= nil then local costId = GFunc.getRewardId(itemCost) local costNum = GFunc.getRewardNum(itemCost) local count = DataManager.BagData.ItemData:getItemNumById(costId) if costNum <= count then return true end end return false end -- --未穿戴装备有五十件以上的红点 -- function EquipData:hasEquipUnWearRedPoint() -- local wearList = {} -- for slotId = 1, 6 do -- for part = 1, 6 do -- local uid = self:getPartEquipUid(slotId, part) -- if uid ~= 0 then -- wearList[uid] = true -- end -- end -- end -- local count = 0 -- for _, equip in pairs(self.allEquips) do -- if wearList[equip:getUid()] == nil then -- count = count + 1 -- if count >= 50 then -- return true -- end -- end -- end -- return false -- end --endregion --@region 属性 function EquipData:getEquipAttrBySlotId(heroId, slotId) if not self.slots[slotId] or not self.slots[slotId].parts then return {} end local curFormation = DataManager.FormationData:getStageFormation() if curFormation[slotId] ~= heroId then return {} end local allAttr = {} for part, info in ipairs(self.slots[slotId].parts) do if info.equip_uid > 0 then local equip = self:getEquipByUid(info.equip_uid) if equip then local attr = equip:getAllAttr() for k, v in pairs(attr) do allAttr[k] = (allAttr[k] or 0) + v end -- 升级属性 local level = self:getPartLv(slotId, part) local baseType = equip:getBaseAttr().type allAttr[baseType] = (attr[baseType] or 0) + self:getBaseAttrLvAdd(baseType, level) -- for i = 1, level do -- local cfg = self:getLevelConfig(i) -- allAttr[cfg.base_attr_add.type] = (attr[cfg.base_attr_add.type] or 0) + self:getBaseAttrLvAdd(cfg.base_attr_add.type, level) -- self:getBaseAttrLvAdd(attrType, lv) -- end -- 精炼属性 local equipAttrs = equip:getExtraMap() local refine = self:getPartRefine(slotId, part) if refine > 0 then for _, extraAttr in pairs(equipAttrs) do local attrName = GFunc.getAttrNameById(extraAttr.id) -- allAttr[attrName] = (allAttr[attrName] or 0) + extraAttr.value local nowAttr = self:getRefineAttrAdd(refine, attrName) allAttr[attrName] = (allAttr[attrName] or 0) + nowAttr.num end end end end end -- 共鸣 for i = 1, 3 do local lv = self:getResonateLevel(i, slotId) local list = self:getResonateList(i) for ii, vv in ipairs(list) do if ii <= lv then for _, vvv in ipairs(vv.attr or {}) do allAttr[vvv.type] = (allAttr[vvv.type] or 0) + vvv.num end else break end end end return allAttr end --@endregion return EquipData