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() 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.allEquips = {} 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_hurt" then return cfg.extra_attr_add_3 elseif attrName == "attr_skill_hurt" then return cfg.extra_attr_add_4 end end --@endregion --@region 装备基础 function EquipData:addEquip(equip, itemGetType) if equip == nil then return end self.allEquips[equip.uid] = self:createEquipEntity(equip) if itemGetType then BIReport:postEquipGet(equip.uid, equip.cfg_id, itemGetType) end self:setDirty() 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(soltId, uids) for _, uid in ipairs(uids) do local equip = self:getEquipByUid(uid) local part = equip:getPart() if part then local oldUid = self.slots[soltId].parts[part].equip_uid for i,info in ipairs(self.slots) do if i ~= soltId then if info.parts[part].equip_uid == uid then info.parts[part].equip_uid = oldUid end end end self.slots[soltId].parts[part].equip_uid = uid end end self:setDirty() end function EquipData:getEquipMaxScore(soltId, part) local equip = nil local maxScore = 0 local useUid = self:getPartEquipUid(soltId, 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(soltId, upgraded) upgraded = upgraded or {} for part, lv in pairs(upgraded) do if self.slots[soltId].parts[part] then self.slots[soltId].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(soltId, part, info) local offset = 0 local refine = self:getPartRefine(soltId, part) if refine < info.refine then local refine = self.slots[soltId].parts[part].refine self.slots[soltId].parts[part].refine = refine + 1 self.slots[soltId].parts[part].refine_fail = 0 offset = offset + 1 -- self:addPlayEffectParts(part) self:setDirtyRefineSuccess() else local fail = self.slots[soltId].parts[part].refine_fail self.slots[soltId].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 attrNum = 0 local attrNextNum = 0 for i,v in ipairs(list) do if type == 1 or type == 3 then if v.parameter[1] <= value then lv = i attrNum = attrNum + v.attr[1].num else nextLv = v.parameter attrNextNum = attrNum + v.attr[1].num 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 attrNum = attrNum + v.attr[1].num else nextLv = v.parameter attrNextNum = attrNum + v.attr[1].num break end end end return lv, nextLv, attrNum / GConst.DEFAULT_FACTOR, attrNextNum / GConst.DEFAULT_FACTOR, 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 return EquipData