local CharInfoUtils = {} local CharUtils = CS.Beyond.Gameplay.CharUtils function CharInfoUtils.openCharInfoBestWay(arg) if PhaseManager:IsOpen(PhaseId.CharInfo) then PhaseManager:ExitPhaseFast(PhaseId.CharInfo) PhaseManager:OpenPhase(PhaseId.CharInfo, arg) else PhaseManager:OpenPhase(PhaseId.CharInfo, arg) end end function CharInfoUtils.openWeaponInfoBestWay(arg) if PhaseManager:IsOpen(PhaseId.WeaponInfo) then PhaseManager:ExitPhaseFast(PhaseId.WeaponInfo) PhaseManager:OpenPhase(PhaseId.WeaponInfo, arg) else PhaseManager:OpenPhase(PhaseId.WeaponInfo, arg) end end function CharInfoUtils.isEndmin(charTemplateId) return string.find(charTemplateId, "endmin") ~= nil end function CharInfoUtils.isCharDevAvailable(instId) if not Utils.isInMainScope() then return false end return CharInfoUtils.checkIsCardInTrail(instId) == false end function CharInfoUtils.checkIsCardInTrail(instId) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(instId) local isTrail = charInst ~= nil and charInst.charType == GEnums.CharType.Trial return isTrail end function CharInfoUtils.checkIsWeaponInTrail(weaponInstId) return GameUtil.IsClientSpawned(weaponInstId) end function CharInfoUtils.getDefExtraHint(charInstId) local allAttribute = CharInfoUtils.getCharFinalAttributes(charInstId) local finalDef = allAttribute[GEnums.AttributeType.Def] local efficiencyOfDEF = Tables.battleConst.efficiencyOfDEF local damagePrevent = (1 / (1 + efficiencyOfDEF * finalDef) ) local showInfo = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.PhysicalDamageTakenScalar, damagePrevent, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }) if showInfo then return string.format(Language.LUA_CHAR_INFO_DEF_EXTRA_HINT_FORMAT, showInfo.showValue) end end local REACH_SHOW_VALUE = 100 function CharInfoUtils.getCharRelationShowValue(relation) local reachCount = 0 for i = 2, #Tables.SpaceshipCharRelationLevelTable do local relationCfg = Tables.SpaceshipCharRelationLevelTable:GetValue(i) if relation >= relationCfg.favorability then reachCount = reachCount + 1 else local lastRelationCfg = Tables.SpaceshipCharRelationLevelTable:GetValue(i - 1) local gap = relationCfg.favorability - lastRelationCfg.favorability local rate = math.floor((relation - lastRelationCfg.favorability) / gap * REACH_SHOW_VALUE) return reachCount * REACH_SHOW_VALUE + rate end end return reachCount * REACH_SHOW_VALUE end function CharInfoUtils.generateCharInfoBasicAttrShowInfo(charInstId) local allAttribute = CharInfoUtils.getCharFinalAttributes(charInstId) local fcAttrInfoList = CharInfoUtils.generateFCAttrShowInfoList(allAttribute, false, UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR) local scMainAttrInfoList = CharInfoUtils.generateSCMainAttrShowInfoList(allAttribute, false, UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR) local scSubAttrInfoList = CharInfoUtils.generateSCSubAttrShowInfoList(allAttribute, false, UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR) return fcAttrInfoList, scMainAttrInfoList, scSubAttrInfoList end function CharInfoUtils._innerGenerateAttrShowInfoListBlack(arg) local allAttributes = arg.allAttributes local blackMap = arg.blackMap local isAttributeDiff = arg.isAttributeDiff == true local fromSpecificSystem = arg.fromSpecificSystem local showInfoList = {} for attributeIndex = 1, GEnums.AttributeType.Enum:ToInt() - 1 do local attributeType = GEnums.AttributeType.__CastFrom(attributeIndex) if attributeType then local attr = allAttributes[attributeType] if not CharInfoUtils._checkIfAttributeInBlackMap(attributeType, attr, blackMap) then local attributeShowInfo = CharInfoUtils._innerGenerateAttrShowInfo(attr, attributeType, isAttributeDiff, fromSpecificSystem) if attributeShowInfo then table.insert(showInfoList, attributeShowInfo) end end end end table.sort(showInfoList, function(a, b) return a.sortOrder < b.sortOrder end) return showInfoList end function CharInfoUtils._checkIfAttributeInBlackMap(attrType, attr, blackMap) if not blackMap then return false end local blackCfg = blackMap[attrType] if not blackCfg then return false end if blackCfg.forbidAllModifier then return true end local _, attrModifier, _ = AttributeUtils.extractAttrData(attr) if attrModifier ~= nil then if blackCfg.forbidModifiers[attrModifier] then return true end end return false end function CharInfoUtils._innerGenerateAttrShowInfoList(allAttributes, showOrder, isAttributeDiff, noSort, fromSpecificSystem) local showInfoList = {} if not showOrder then for attrType, attr in pairs(allAttributes) do local attributeShowInfo = CharInfoUtils._innerGenerateAttrShowInfo(attr, attrType, isAttributeDiff, fromSpecificSystem) if attributeShowInfo then table.insert(showInfoList, attributeShowInfo) end end elseif type(showOrder) == "table" then for _, attributeType in ipairs(showOrder) do local attr = allAttributes[attributeType] local attributeShowInfo = CharInfoUtils._innerGenerateAttrShowInfo(attr, attributeType, isAttributeDiff, fromSpecificSystem) if attributeShowInfo then table.insert(showInfoList, attributeShowInfo) end end elseif type(showOrder) == "userdata" then for i = 1, showOrder.Count do local attributeType = showOrder[CSIndex(i)] local attr = allAttributes[attributeType] local attributeShowInfo = CharInfoUtils._innerGenerateAttrShowInfo(attr, attributeType, isAttributeDiff, fromSpecificSystem) if attributeShowInfo then table.insert(showInfoList, attributeShowInfo) end end end if noSort ~= true then table.sort(showInfoList, function(a, b) return a.sortOrder < b.sortOrder end) end return showInfoList end function CharInfoUtils._innerGenerateAttrShowInfo(attr, attrType, isAttributeDiff, fromSpecificSystem) if not attr or not attrType then return end local attrValue, attrModifier, enhancedAttrIndex, enhanceGuaranteeTimesRuleId = AttributeUtils.extractAttrData(attr) if attrValue then local attributeShowInfo = AttributeUtils.generateAttributeShowInfo(attrType, attrValue,{ isAttributeDiff = isAttributeDiff, attrModifier = attrModifier, enhancedAttrIndex = enhancedAttrIndex, enhanceGuaranteeTimesRuleId = enhanceGuaranteeTimesRuleId, fromSpecificSystem = fromSpecificSystem, }) if attributeShowInfo then return attributeShowInfo end end end function CharInfoUtils.generateCompositeAttributeShowInfoList(allAttributes, fromSpecificSystem) return CharInfoUtils._innerGenerateAttrShowInfoList(allAttributes, nil, false, false, fromSpecificSystem) end function CharInfoUtils.generateFCAttrShowInfoList(allAttributes, isAttrDiff, fromSpecificSystem) return CharInfoUtils._innerGenerateAttrShowInfoList(allAttributes, UIConst.CHAR_INFO_FIRST_CLASS_ATTRIBUTE_SHOW_ORDER, isAttrDiff, false, fromSpecificSystem) end function CharInfoUtils.generateSCMainAttrShowInfoList(allAttributes, isAttrDiff, fromSpecificSystem) return CharInfoUtils._innerGenerateAttrShowInfoList(allAttributes, UIConst.CHAR_INFO_SECOND_CLASS_MAIN_ATTRIBUTE_SHOW_ORDER, isAttrDiff, true, fromSpecificSystem) end function CharInfoUtils.generateSCSubAttrShowInfoList(allAttributes, isAttrDiff, fromSpecificSystem) return CharInfoUtils._innerGenerateAttrShowInfoListBlack({ allAttributes = allAttributes, blackMap = UIConst.CHAR_INFO_FULL_ATTR_BLACK_MAP, isAttrDiff = isAttrDiff, fromSpecificSystem = fromSpecificSystem, }) end function CharInfoUtils.generateBasicAttributeShowInfoList(allAttributes, isAttributeDiff) local showInfoList = {} for _, attributeType in ipairs(UIConst.CHAR_INFO_BASIC_ATTRIBUTE_SHOW_ORDER) do local attr = allAttributes[attributeType] local attributeShowInfo = CharInfoUtils._innerGenerateAttrShowInfo({ attrValue = attr, modifierType = GEnums.ModifierType.BaseAddition }, attributeType, isAttributeDiff) if attributeShowInfo then table.insert(showInfoList, attributeShowInfo) end end return showInfoList end function CharInfoUtils.generateUpgradeAttributeShowInfoList(allAttributes, isAttributeDiff) local showInfoList = {} for _, attributeType in ipairs(UIConst.CHAR_INFO_UPGRADE_ATTRIBUTE_SHOW_ORDER) do local attr = allAttributes[attributeType] local attributeShowInfo = CharInfoUtils._innerGenerateAttrShowInfo({ attrValue = attr, modifierType = GEnums.ModifierType.BaseAddition }, attributeType, isAttributeDiff) if attributeShowInfo then table.insert(showInfoList, attributeShowInfo) end end return showInfoList end function CharInfoUtils.checkIsCardInSlot(instId) local curSquadSlot = GameInstance.player.squadManager:GetSlotInCurSquad(instId) return curSquadSlot ~= nil end function CharInfoUtils.getPlayerBreakInfoList() local breakData = Tables.charBreakTable local breakInfoList = {} for i = 1, Tables.characterConst.maxBreak do local breakCfg = breakData[i] local breakStatus = breakCfg.breakStatus table.insert(breakInfoList, { isHide = breakStatus == 0, isBigBreak = breakStatus == 1, }) end return breakInfoList end function CharInfoUtils.getPlayerCharInfoByTemplateId(templateId, charType) local charBag = GameInstance.player.charBag return charBag:GetCharInfoByTemplateId(templateId, charType) end function CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local charBag = GameInstance.player.charBag return charBag:GetCharInfo(charInstId) end function CharInfoUtils.getPlayerCharInfoByPresetId(presetId) local charBag = GameInstance.player.charBag return charBag:GetCharInfoByPresetId(presetId) end CharInfoUtils.CHAR_INFO_PAGE_TYPE = { OVERVIEW = 1, WEAPON = 2, EQUIP = 3, TALENT = 5, PROFILE = 6, UPGRADE = 7, PROFILE_SHOW = 10, POTENTIAL = 11, } function CharInfoUtils.getCharInfoTitle(charTemplateId, pageType) local charCfg = Tables.characterTable[charTemplateId] if pageType == UIConst.CHAR_INFO_PAGE_TYPE.OVERVIEW then return string.format(Language.LUA_CHAR_INFO_TITLE_FORMAT, charCfg.name, Language.LUA_CHAR_INFO_TITLE_OVERVIEW) elseif pageType == UIConst.CHAR_INFO_PAGE_TYPE.EQUIP then return string.format(Language.LUA_CHAR_INFO_TITLE_FORMAT, charCfg.name, Language.LUA_CHAR_INFO_TITLE_EQUIP) elseif pageType == UIConst.CHAR_INFO_PAGE_TYPE.TALENT then return string.format(Language.LUA_CHAR_INFO_TITLE_FORMAT, charCfg.name, Language.LUA_CHAR_INFO_TITLE_TALENT) elseif pageType == UIConst.CHAR_INFO_PAGE_TYPE.PROFILE then return string.format(Language.LUA_CHAR_INFO_TITLE_FORMAT, charCfg.name, Language.LUA_CHAR_INFO_TITLE_PROFILE) elseif pageType == UIConst.CHAR_INFO_PAGE_TYPE.UPGRADE then return string.format(Language.LUA_CHAR_INFO_TITLE_FORMAT, charCfg.name, Language.LUA_CHAR_INFO_TITLE_UPGRADE) elseif pageType == UIConst.CHAR_INFO_PAGE_TYPE.PROFILE_SHOW then elseif pageType == UIConst.CHAR_INFO_PAGE_TYPE.POTENTIAL then return string.format(Language.LUA_CHAR_INFO_TITLE_FORMAT, charCfg.name, Language.LUA_CHAR_INFO_TITLE_POTENTIAL) elseif pageType == UIConst.CHAR_INFO_PAGE_TYPE.WEAPON then return string.format(Language.LUA_CHAR_INFO_TITLE_FORMAT, charCfg.name, Language.LUA_CHAR_INFO_TITLE_WEAPON) end return "" end function CharInfoUtils.checkIfCharMaxLv(charInstId) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) return charInst.level >= Tables.characterConst.maxLevel end function CharInfoUtils.getCharPassiveSkillCount(charTemplateId) local charGrowthCfg = CharInfoUtils.getCharGrowthData(charTemplateId) local talentNodeMap = charGrowthCfg.talentNodeMap local skillIdDict = {} for _, talentNode in pairs(talentNodeMap) do if talentNode.nodeType == GEnums.TalentNodeType.PassiveSkill then local skillId = talentNode.passiveSkillNodeInfo.skillId if skillIdDict[skillId] == nil then skillIdDict[skillId] = true end end end local passiveSkillCount = lume.count(skillIdDict) return passiveSkillCount end function CharInfoUtils.getCharExpInfo(charInstId) local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local breakStage = charInfo.breakStage local breakCfg = Tables.charBreakTable[breakStage] local stageLv = breakCfg.maxLevel local availableExpItems = breakCfg.availableExpItems local curLevel = charInfo.level local curExp = charInfo.exp local levelUpExp = Tables.charLevelUpTable[curLevel].exp return curExp, levelUpExp, curLevel, stageLv, availableExpItems end function CharInfoUtils.getSkillGroupSubDescList(charTemplateId, skillGroupId, skillGroupLv) local skillGroupCfg = CharInfoUtils.getSkillGroupCfg(charTemplateId, skillGroupId) local skillIdList = skillGroupCfg.skillIdList local isEndmin = CharUtils.IsEndminTemplateId(charTemplateId) local skillDescList = {} local skillDescNameList = {} for i = 1, #skillIdList do local skillId = skillIdList[CSIndex(i)] local skillCfg = CharInfoUtils.getSkillCfg(skillId, skillGroupLv) local isValid = true if isEndmin and not string.startWith(skillId, CharUtils.curEndminCharTemplateId) then isValid = false end if skillCfg and isValid then if i == 1 or isEndmin then local skillExtraInfoList = CharInfoUtils.getSkillExtraInfoList(skillCfg.skillId, skillCfg.level) for _, extraInfo in ipairs(skillExtraInfoList) do table.insert(skillDescNameList, extraInfo.name) table.insert(skillDescList, extraInfo.value) end end for j = 1, #skillCfg.subDescNameList do local descName = skillCfg.subDescNameList[CSIndex(j)] if descName == nil or string.isEmpty(descName) then break end table.insert(skillDescNameList, skillCfg.subDescNameList[CSIndex(j)]) end for j = 1, #skillCfg.subDescList do local desc = skillCfg.subDescList[CSIndex(j)] if desc == nil or string.isEmpty(desc) then break end table.insert(skillDescList, skillCfg.subDescList[CSIndex(j)]) end end end return skillDescNameList, skillDescList end function CharInfoUtils.getEquipByInstId(equipInstId) if not equipInstId then return end local _, equipInst = GameInstance.player.inventory:TryGetEquipInst(Utils.getCurrentScope(), equipInstId) if not equipInst then return end local equipInstanceData = equipInst.instData return equipInstanceData end function CharInfoUtils.getEquipMinWearLv(tierLv) local hasTier, tierCfg = Tables.equipTierLevelTable:TryGetValue(tierLv) if not hasTier then return -1 end return tierCfg.equiplevel end function CharInfoUtils.getCharAllEquipAttributeShowInfos(charInstId) local mainAttrShowInfos = {} local extraAttrShowInfos = {} local defAttr, mainAttrs, extraAttrs = CharInfoUtils.getCharAllEquipAttributes(charInstId) local defAttrShowInfo = AttributeUtils.generateAttributeShowInfo(defAttr.attrType, defAttr.attrValue, { attrModifier = defAttr.attrModifier, }) for _, attr in ipairs(mainAttrs) do local attributeShowInfo = AttributeUtils.generateAttributeShowInfo(attr.attrType, attr.attrValue, { attrModifier = attr.attrModifier, }) table.insert(mainAttrShowInfos, attributeShowInfo) end table.sort(mainAttrShowInfos, function(a, b) return a.sortOrder < b.sortOrder end) for _, attr in ipairs(extraAttrs) do local attributeShowInfo = AttributeUtils.generateAttributeShowInfo(attr.attrType, attr.attrValue, { attrModifier = attr.attrModifier, }) table.insert(extraAttrShowInfos, attributeShowInfo) end table.sort(extraAttrShowInfos, function(a, b) return a.sortOrder < b.sortOrder end) return defAttrShowInfo, mainAttrShowInfos, extraAttrShowInfos end local ATTR_MODIFIER_MERGE_RULE = { ADD = 1, MULTIPLY = 2, } local DEFAULT_MERGE_RULE = ATTR_MODIFIER_MERGE_RULE.ADD local EQUIP_ATTR_MODIFIER_TYPE_MERGE_RULE = { [GEnums.ModifierType.FinalMultiplier] = ATTR_MODIFIER_MERGE_RULE.MULTIPLY, [GEnums.ModifierType.BaseFinalMultiplier] = ATTR_MODIFIER_MERGE_RULE.MULTIPLY, } function CharInfoUtils.getCharAllEquipAttributes(charInstId) local defAttr = { attrType = GEnums.AttributeType.Def, attrValue = 0, attrModifier = GEnums.ModifierType.BaseAddition, } local attrType2ModifierDict = {} local attrModifierDataList = CharInfoUtils.getAllEquipInstAttributes(charInstId) for _, attr in ipairs(attrModifierDataList) do local keyAttrType = attr.keyAttrType local modifierType = attr.modifierType local attrValue = attr.attrValue if modifierType == GEnums.ModifierType.BaseAddition and keyAttrType == GEnums.AttributeType.Def then if defAttr == nil then defAttr = { attrValue = 0, attrType = GEnums.AttributeType.Def, attrModifier = modifierType, } end defAttr.attrValue = defAttr.attrValue + attrValue else if attrType2ModifierDict[keyAttrType] == nil then attrType2ModifierDict[keyAttrType] = {} end local modifierDict = attrType2ModifierDict[keyAttrType] if modifierDict[modifierType] == nil then modifierDict[modifierType] = attrValue else if EQUIP_ATTR_MODIFIER_TYPE_MERGE_RULE[modifierType] == ATTR_MODIFIER_MERGE_RULE.MULTIPLY then modifierDict[modifierType] = modifierDict[modifierType] * attrValue else modifierDict[modifierType] = modifierDict[modifierType] + attrValue end end end end local mainAttrs = {} for attrType, modifierDict in pairs(attrType2ModifierDict) do for modifierType, mergedAttrValue in pairs(modifierDict) do table.insert(mainAttrs, { attrValue = mergedAttrValue, attrType = attrType, attrModifier = modifierType, }) end end return defAttr, mainAttrs, {} end function CharInfoUtils.getAllEquipInstAttributes(charInstId) local attrTypeDataList = {} local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) for slotIndex, equipInstId in pairs(charInst.equipCol) do local baseAttr, attrs = CharInfoUtils.getEquipInstAttributes(equipInstId) table.insert(attrTypeDataList, baseAttr) for _, attr in ipairs(attrs) do table.insert(attrTypeDataList, attr) end end return attrTypeDataList end function CharInfoUtils.getEquipShowAttributes(instId) local equipInst = CharInfoUtils.getEquipByInstId(instId) return CharInfoUtils._genEquipShowAttributes(equipInst.templateId, CharInfoUtils.getEquipInstAttributes(instId)) end function CharInfoUtils.getEquipTemplateShowAttributes(equipTemplateId) return CharInfoUtils._genEquipShowAttributes(equipTemplateId, CharInfoUtils.getEquipTemplateAttributes(equipTemplateId)) end local EQUIP_MAIN_ATTR_INDEX = 2 function CharInfoUtils._genEquipShowAttributes(templateId, equipAttr, attrs) local defAttrShowInfo = AttributeUtils.generateAttributeShowInfo(equipAttr.keyAttrType, equipAttr.attrValue, { attrModifier = equipAttr.modifierType, }) local mainAttrShowList = {} local extraAttrShowList = {} for index, attrDisplayInfo in ipairs(attrs) do local attrShowInfo = AttributeUtils.generateAttributeShowInfo(attrDisplayInfo.keyAttrType, attrDisplayInfo.attrValue, { attrModifier = attrDisplayInfo.modifierType, enhancedAttrIndex = attrDisplayInfo.enhancedAttrIndex, enhanceGuaranteeTimesRuleId = attrDisplayInfo.enhanceGuaranteeTimesRuleId, }) if attrDisplayInfo.attrIndex <= EQUIP_MAIN_ATTR_INDEX then table.insert(mainAttrShowList, attrShowInfo) else table.insert(extraAttrShowList, attrShowInfo) end end mainAttrShowList = lume.sort(mainAttrShowList, function(a, b) return a.enhancedAttrIndex < b.enhancedAttrIndex end) extraAttrShowList = lume.sort(extraAttrShowList, function(a, b) return a.enhancedAttrIndex < b.enhancedAttrIndex end) return defAttrShowInfo, mainAttrShowList, extraAttrShowList end function CharInfoUtils.getEquipTemplateAttributes(templateId) local _, equipData = Tables.equipTable:TryGetValue(templateId) if not equipData then return end local attrs = {} for i = 1, equipData.displayAttrModifiers.Count do local attrModifier = equipData.displayAttrModifiers[CSIndex(i)] local attrInfo = { attrType = attrModifier.attrType, attrValue = attrModifier.attrValue, modifierType = attrModifier.modifierType, attrIndex = attrModifier.attrIndex, enhancedAttrIndex = attrModifier.enhancedAttrIndex, enhancedAttrValues = attrModifier.enhancedAttrValues, enhanceGuaranteeTimesRuleId = attrModifier.enhanceGuaranteeTimesRuleId, } if string.isEmpty(attrModifier.compositeAttr) then attrInfo.keyAttrType = attrModifier.attrType else attrInfo.keyAttrType = attrModifier.compositeAttr end table.insert(attrs, attrInfo) end local displayEquipAttrModifier = equipData.displayBaseAttrModifier local baseAttr = { keyAttrType = displayEquipAttrModifier.attrType, attrType = displayEquipAttrModifier.attrType, attrValue = displayEquipAttrModifier.attrValue, modifierType = displayEquipAttrModifier.modifierType, attrIndex = displayEquipAttrModifier.attrIndex, enhancedAttrIndex = displayEquipAttrModifier.enhancedAttrIndex, enhancedAttrValues = displayEquipAttrModifier.enhancedAttrValues, } return baseAttr, attrs end function CharInfoUtils.getEquipInstAttributes(instId) local equipInstData = CharInfoUtils.getEquipByInstId(instId) local baseAttr, attrs = CharInfoUtils.getEquipTemplateAttributes(equipInstData.templateId) for _, attrInfo in ipairs(attrs) do attrInfo.attrValue = EquipTechUtils.getEnhancedAttrValue(attrInfo, equipInstData) end return baseAttr, attrs end function CharInfoUtils.getCharSuitInfoList(instId, focusSuitId) local suitInfoList = {} local charEntityInfo = CharInfoUtils.getPlayerCharInfoByInstId(instId) local equipCol = charEntityInfo.equipCol local suitTable = {} local suit2Slots = {} for slotIndex, equipInstId in pairs(equipCol) do local equipInstanceData = CharInfoUtils.getEquipByInstId(equipInstId) local templateId = equipInstanceData.templateId local _, equipData = Tables.equipTable:TryGetValue(templateId) local suitId = equipData.suitID if not suit2Slots[suitId] then suit2Slots[suitId] = {} end if not focusSuitId or focusSuitId == suitId then suitTable[suitId] = suitTable[suitId] and suitTable[suitId] + 1 or 1 suit2Slots[suitId][slotIndex] = true end end for suitId, suitCount in pairs(suitTable) do table.insert(suitInfoList, { suitId = suitId, suitCount = suitCount, }) end suitInfoList = lume.sort(suitInfoList, function(a, b) return a.suitCount > b.suitCount end) return suitInfoList, suit2Slots end function CharInfoUtils.getCharTableData(charTemplateId) local tableData = nil local characterData = CharInfoUtils.getCharGrowthData(charTemplateId) if characterData then tableData = characterData end return tableData end function CharInfoUtils.getCharBaseAttributes(instId, baseTypeMask) local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(instId) return CharInfoUtils._getSlotBaseAttributes(charInfo, baseTypeMask) end function CharInfoUtils.getCharArmedAttributes(instId, armedTypeMask, baseTypeMask) local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(instId) return CharInfoUtils._getSlotArmedAttributes(charInfo, armedTypeMask, baseTypeMask) end function CharInfoUtils.getCharFinalAttributes(instId) local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(instId) return CharInfoUtils.getCharFinalAttributesFromSpecificCache(charInfo.attributes) end function CharInfoUtils.getCharFinalAttributesFromSpecificCache(allAttributes) local attributes = {} for i = 1, GEnums.AttributeType.Enum:ToInt() - 1 do local attributeType = GEnums.AttributeType.__CastFrom(i) if attributeType then attributes[attributeType] = allAttributes:GetValue(attributeType) end end return attributes end function CharInfoUtils.getQualifiedEquipBreakNodeIdByEquipTierLimit(equipTierLimit) for nodeId, nodeCfg in pairs(Tables.charBreakNodeTable) do if nodeCfg.equipTierLimit == equipTierLimit and nodeCfg.talentNodeType == GEnums.TalentNodeType.EquipBreak then return nodeId end end end function CharInfoUtils.checkCharInTeam(charInstId, teamIndex) if not teamIndex or teamIndex <= 0 then return -1 end local teamInfo = GameInstance.player.charBag.teamList[CSIndex(teamIndex)] local memberList = teamInfo.memberList for index = 1, memberList.Count do local instId = memberList[CSIndex(index)] if instId == charInstId then return index end end return -1 end function CharInfoUtils.getAllCharInfoList() local charBag = GameInstance.player.charBag local charInfoList = {} local playerChars = charBag.charInfos for _, charInfo in cs_pairs(playerChars) do local isClientOnly = GameUtil.IsRuntimeClientId(charInfo.instId) if not isClientOnly then local templateId = charInfo.templateId local charData = CharInfoUtils.getCharTableData(templateId) local item = { instId = charInfo.instId, templateId = templateId, ownTime = charInfo.ownTime, level = charInfo.level, rarity = charData.rarity, slotIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM + 1, slotReverseIndex = -1, } table.insert(charInfoList, item) end end return charInfoList end function CharInfoUtils.getCurScopeCharInfoList(csTeamIndex) local charBag = GameInstance.player.charBag local charInfoList = {} local playerChars = charBag.charInfos local scopeCharList = charBag.charList if csTeamIndex == nil then csTeamIndex = charBag.curTeamIndex end local teamInfo = charBag.teamList[csTeamIndex] local memberList = teamInfo.memberList for i = 1, memberList.Count do local instId = memberList[CSIndex(i)] local charInfo = playerChars[instId] local templateId = charInfo.templateId local charCfg = Tables.characterTable:GetValue(templateId) local item = { instId = instId, templateId = charInfo.templateId, level = charInfo.level, ownTime = charInfo.ownTime, rarity = charCfg.rarity, slotIndex = i, slotReverseIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM - i, sortOrder = charCfg.sortOrder, singleSelect = true, } table.insert(charInfoList, item) end for i = 1, scopeCharList.Count do local charInfo = scopeCharList[CSIndex(i)] local instId = charInfo.instId local isClientOnly = GameUtil.IsRuntimeClientId(instId) if (not isClientOnly) and (CharInfoUtils.checkCharInTeam(instId, LuaIndex(csTeamIndex)) <= 0) then local templateId = charInfo.templateId local charCfg = Tables.characterTable:GetValue(templateId) local item = { instId = instId, templateId = templateId, ownTime = charInfo.ownTime, level = charInfo.level, rarity = charCfg.rarity, slotIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM + 1, slotReverseIndex = -1, sortOrder = charCfg.sortOrder, } table.insert(charInfoList, item) end end charInfoList = lume.sort(charInfoList, Utils.genSortFunction(UIConst.CHAR_FORMATION_LIST_SORT_OPTION[1].reverseKeys)) return charInfoList end function CharInfoUtils.getCharInfoList(csTeamIndex) local charBag = GameInstance.player.charBag local charInfoList = {} local playerChars = charBag.charInfos if csTeamIndex == nil then csTeamIndex = charBag.curTeamIndex end local teamInfo = charBag.teamList[csTeamIndex] local memberList = teamInfo.memberList for i = 1, memberList.Count do local instId = memberList[CSIndex(i)] local charInfo = playerChars[instId] local templateId = charInfo.templateId local charCfg = Tables.characterTable:GetValue(templateId) local item = { instId = instId, templateId = charInfo.templateId, level = charInfo.level, ownTime = charInfo.ownTime, rarity = charCfg.rarity, slotIndex = i, slotReverseIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM - i, sortOrder = charCfg.sortOrder, singleSelect = true, } table.insert(charInfoList, item) end for instId, charInfo in pairs(playerChars) do local isClientOnly = GameUtil.IsRuntimeClientId(instId) if (not isClientOnly) and (CharInfoUtils.checkCharInTeam(instId, LuaIndex(csTeamIndex)) <= 0) then local templateId = charInfo.templateId local charCfg = Tables.characterTable:GetValue(templateId) local item = { instId = instId, templateId = templateId, ownTime = charInfo.ownTime, level = charInfo.level, rarity = charCfg.rarity, slotIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM + 1, slotReverseIndex = -1, sortOrder = charCfg.sortOrder, } table.insert(charInfoList, item) end end charInfoList = lume.sort(charInfoList, Utils.genSortFunction(UIConst.CHAR_FORMATION_LIST_SORT_OPTION[1].reverseKeys)) return charInfoList end function CharInfoUtils.getSingleCharInfoList(charInstId) return CharInfoUtils.getCharInfoListByInstIdList({charInstId}) end function CharInfoUtils.getCharInfoListByInstIdList(charInstIdList, isShowPreview) local charInfoList = {} for _, charInstId in pairs(charInstIdList) do local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local charData = CharInfoUtils.getCharTableData(charInfo.templateId) local item = { instId = charInstId, templateId = charInfo.templateId, level = charInfo.level, ownTime = charInfo.ownTime, rarity = charData.rarity, slotIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM + 1, slotReverseIndex = -1, isShowPreview = isShowPreview or false, } table.insert(charInfoList, item) end return charInfoList end function CharInfoUtils.checkCharInLockedTeam(charInfo, lockedTeamData) local isLocked = false local isReplaceable = false local isInLockedTeam = false for _, char in ipairs(lockedTeamData.chars) do if char.charInstId == charInfo.instId then isInLockedTeam = true break end if char.isReplaceable and char.charId == charInfo.templateId then isLocked = true isReplaceable = true end end return isInLockedTeam, isLocked, isReplaceable end function CharInfoUtils.getCharInfoListWithLockedTeamData(lockedTeamData) local charBag = GameInstance.player.charBag local charInfoList = {} local playerChars = charBag.charInfos local allCount = 0 if lockedTeamData then for i, char in ipairs(lockedTeamData.chars) do local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(char.charInstId) local charData = CharInfoUtils.getCharTableData(char.charId) local item = { instId = char.charInstId, templateId = char.charId, level = charInfo.level, ownTime = charInfo.ownTime, rarity = charData.rarity, slotIndex = i, slotReverseIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM - i, isLocked = char.isLocked, isTrail = char.isTrail, isReplaceable = char.isReplaceable, } table.insert(charInfoList, item) allCount = allCount + 1 end if lockedTeamData.lockedTeamMemberCount == lockedTeamData.maxTeamMemberCount and not lockedTeamData.hasReplaceable then return charInfoList, allCount end end for instId, charInfo in pairs(playerChars) do local isClientOnly = GameUtil.IsRuntimeClientId(instId) local isInLockedTeam, isLock, isReplaceable = CharInfoUtils.checkCharInLockedTeam(charInfo, lockedTeamData) if not isInLockedTeam and not isClientOnly then local templateId = charInfo.templateId local charData = CharInfoUtils.getCharTableData(templateId) local item = { instId = instId, templateId = templateId, ownTime = charInfo.ownTime, level = charInfo.level, rarity = charData.rarity, slotIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM + 1, slotReverseIndex = -1, isLocked = isLock, isReplaceable = isReplaceable, } table.insert(charInfoList, item) if not isReplaceable and not charInfo.isDead then allCount = allCount + 1 end end end local hasValue local charTeamData hasValue, charTeamData = Tables.charTeamTable:TryGetValue(lockedTeamData.teamConfigId) if hasValue then for _, charPresetId in pairs(charTeamData.presetCharList) do local charPresetData hasValue, charPresetData = Tables.charPresetTable:TryGetValue(charPresetId) if hasValue then local charInfo = CharInfoUtils.getPlayerCharInfoByPresetId(charPresetId) local isInLockedTeam, isLock, isReplaceable = CharInfoUtils.checkCharInLockedTeam(charInfo, lockedTeamData) if not isInLockedTeam then local charData = CharInfoUtils.getCharTableData(charInfo.templateId) local item = { instId = charInfo.instId, templateId = charInfo.templateId, level = charInfo.level, ownTime = charInfo.ownTime, rarity = charData.rarity, slotIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM + 1, slotReverseIndex = -1, isTrail = true, isLocked = isLock, isReplaceable = isReplaceable, } table.insert(charInfoList, item) if not isReplaceable then allCount = allCount + 1 end end end end end return charInfoList, allCount end function CharInfoUtils.getLeaderCharInfo() local leaderIndex = GameInstance.player.squadManager.leaderIndex local curSquad = GameInstance.player.squadManager.curSquad local slot = curSquad.slots[leaderIndex] local charInstId = slot.charInstId local isClientOnly = GameUtil.IsRuntimeClientId(charInstId) if isClientOnly then local firstAvailableChar = CharInfoUtils.getServerEndmin() return firstAvailableChar end local playerChar = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) if playerChar ~= nil then local charInfo = { instId = playerChar.instId, templateId = playerChar.templateId, } return charInfo else return nil end end function CharInfoUtils.getServerEndmin() local charBag = GameInstance.player.charBag local playerChars = charBag.charInfos for instId, charInfo in pairs(playerChars) do local isClientOnly = GameUtil.IsRuntimeClientId(instId) if (not isClientOnly) and CharInfoUtils.isEndmin(charInfo.templateId) then return{ instId = instId, templateId = charInfo.templateId } end end end function CharInfoUtils.getCharDisplayData(templateId) local data local res, displayData = DataManager.characterDisplayConfig.data:TryGetValue(templateId) if res then data = displayData end return data end function CharInfoUtils.getCharHeightData(charHeight) local res, displayData = DataManager.characterHeightConfig.heightDataDict:TryGetValue(charHeight) if not res then return end return displayData end function CharInfoUtils.getCharHeadSpriteName(templateId) return UIConst.UI_SPRITE_CHAR_HEAD, UIConst.UI_CHAR_HEAD_PREFIX .. templateId end function CharInfoUtils.getCharHeadSquareSpriteName(templateId) return UIConst.UI_SPRITE_CHAR_HEAD_SQUARE, UIConst.UI_CHAR_HEAD_PREFIX .. templateId end function CharInfoUtils.getCharPaperAttributes(templateId, level, breakStage) local attributes = {} local _, attributesWithStringKey = DataManager.characterAttributeTable:TryGetData(templateId, level, breakStage) return attributesWithStringKey end function CharInfoUtils._getSlotBaseAttributes(charInfo, typeMask) if typeMask == nil then typeMask = UIConst.CHAR_INFO_ATTRIBUTE_ALL_FILTER_MASK end local attributes = {} for i = 1, GEnums.AttributeType.Enum:ToInt() - 1 do local attributeType = GEnums.AttributeType.__CastFrom(i) if attributeType then attributes[attributeType] = charInfo.attributes:GetBaseValue(attributeType, typeMask) end end return attributes end function CharInfoUtils._getSlotArmedAttributes(charInfo, armedTypeMask, baseTypeMask) if armedTypeMask == nil then armedTypeMask = UIConst.CHAR_INFO_ATTRIBUTE_ALL_FILTER_MASK end if baseTypeMask == nil then baseTypeMask = UIConst.CHAR_INFO_ATTRIBUTE_ALL_FILTER_MASK end local attributes = {} for i = 1, GEnums.AttributeType.Enum:ToInt() - 1 do local attributeType = GEnums.AttributeType.__CastFrom(i) if attributeType then attributes[attributeType] = charInfo.attributes:GetArmedValue(attributeType, armedTypeMask, baseTypeMask) end end return attributes end function CharInfoUtils._getSlotFinalAttributes(charInfo) local attributes = {} if charInfo.attributes == nil then logger.error("CharInfoUtils->Can't get char attributes, charTemplateId:" .. charInfo.templateId) return attributes end local attributes = {} for i = 1, GEnums.AttributeType.Enum:ToInt() - 1 do local attributeType = GEnums.AttributeType.__CastFrom(i) if attributeType then attributes[attributeType] = charInfo.attributes:GetValue(attributeType) end end return attributes end function CharInfoUtils.getCharGrowthData(charTemplateId) charTemplateId = CharUtils.GetVirtualCharTemplateId(charTemplateId) local _, charGrowthData = Tables.charGrowthTable:TryGetValue(charTemplateId) return charGrowthData end function CharInfoUtils.getCharProfessionIconName(profession, isSmall) local iconName = '' local _, professionData = Tables.charProfessionTable:TryGetValue(profession) if professionData then iconName = professionData.iconId if isSmall then iconName = iconName .. UIConst.UI_CHAR_PROFESSION_SMALL_SUFFIX end end return iconName end function CharInfoUtils.getAllWeaponList(weaponType) local weaponList = {} local res, weaponInstDict = GameInstance.player.inventory:TryGetAllWeaponInstItems(Utils.getCurrentScope()) if res then for weaponInstId, itemBundle in pairs(weaponInstDict) do local instInfo = CharInfoUtils.getWeaponInstInfo(weaponInstId) local weaponInfo = FilterUtils.processWeapon(instInfo.weaponTemplateId, instInfo.weaponInstId) weaponInfo.instInfo = instInfo if not weaponType or instInfo.weaponCfg.weaponType == weaponType then table.insert(weaponList, weaponInfo) end end end return weaponList end function CharInfoUtils.getWeaponInstInfo(weaponInstId) local res, itemBundle = GameInstance.player.inventory:TryGetWeaponInst(Utils.getCurrentScope(), weaponInstId) if not res then return end local weaponInst = itemBundle.instData local weaponTemplateId = weaponInst.templateId local _, itemCfg = Tables.itemTable:TryGetValue(weaponTemplateId) local weaponExhibitInfo = CharInfoUtils.getWeaponExhibitBasicInfo(weaponTemplateId, weaponInstId) local mainAttributeList, subAttributeList = CharInfoUtils.getWeaponShowAttributes(weaponInstId) local _, weaponCfg = Tables.weaponBasicTable:TryGetValue(weaponTemplateId) local data = { weaponInst = weaponInst, weaponInstId = weaponInst.instId, weaponTemplateId = weaponTemplateId, weaponExhibitInfo = weaponExhibitInfo, mainAttributeList = mainAttributeList, subAttributeList = subAttributeList, itemCfg = itemCfg, weaponCfg = weaponCfg, } return data end function CharInfoUtils.getCharCurWeapon(charInstId) local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local weaponInstId = charInfo.weaponInstId return CharInfoUtils.getWeaponInstInfo(weaponInstId) end function CharInfoUtils.getWeaponByInstId(weaponInstId) local _, weaponInst = GameInstance.player.inventory:TryGetWeaponInst(Utils.getCurrentScope(), weaponInstId) if not weaponInst then return end local equipInstanceData = weaponInst.instData return equipInstanceData end function CharInfoUtils.getGemByInstId(gemInstId, logError) local _, getInst = GameInstance.player.inventory:TryGetGemInst(Utils.getCurrentScope(), gemInstId) if not getInst then if logError then logger.error("CharInfoUtils->Can't get gem inst from inventory, gemInstId: " .. tostring(gemInstId)) end return end local gemInstData = getInst.instData return gemInstData end function CharInfoUtils.isGemTermEnhanceMax(termId, level) local _, termCfg = Tables.gemTable:TryGetValue(termId) if not termCfg then logger.error("CharInfoUtils->Can't get gem term config, termId: " .. termId) return false end local isMax = true local _, gemEnhanceDataList = Tables.gemEnhanceTable:TryGetValue(termCfg.termType) if gemEnhanceDataList then local maxEnhanceData = gemEnhanceDataList.list[#gemEnhanceDataList.list - 1] if maxEnhanceData then isMax = level >= maxEnhanceData.termCost end end return isMax end function CharInfoUtils.getGemLeadSkillTermId(gemInstId) local gemInst = CharInfoUtils.getGemByInstId(gemInstId) if not gemInst then return end local maxCost = -1 local maxCostTermId for _, skillTerm in pairs(gemInst.termList) do local challengerCfg = Tables.gemTable:GetValue(skillTerm.termId) if challengerCfg.isSkillTerm then if skillTerm.cost > maxCost then maxCost = skillTerm.cost maxCostTermId = skillTerm.termId elseif skillTerm.cost == maxCost then local curMaxTermCfg = Tables.gemTable:GetValue(maxCostTermId) local challengerCfg = Tables.gemTable:GetValue(skillTerm.termId) if challengerCfg and curMaxTermCfg then if challengerCfg.sortOrder > curMaxTermCfg.sortOrder then maxCost = skillTerm.cost maxCostTermId = skillTerm.termId end end end end end return maxCostTermId end function CharInfoUtils.getWeaponBreakthroughInfo(weaponInstId, breakthroughLevel) local _, weaponInst = GameInstance.player.inventory:TryGetWeaponInst(Utils.getCurrentScope(), weaponInstId) local weaponInstData = weaponInst.instData if not weaponInstData then logger.error("CharInfoUtils->Can't get weapon inst from inventory, weaponInstId: " .. weaponInstId) return end if not breakthroughLevel then breakthroughLevel = weaponInstData.breakthroughLv end local weaponTemplateId = weaponInst.id local _, weaponCfg = Tables.weaponBasicTable:TryGetValue(weaponTemplateId) if not weaponCfg then logger.error("CharInfoUtils->Can't get weapon basic info, templateId: " .. weaponTemplateId) return end local breakthroughTemplateId = weaponCfg.breakthroughTemplateId local _, breakthroughTemplateCfg = Tables.weaponBreakThroughTemplateTable:TryGetValue(breakthroughTemplateId) if not breakthroughTemplateCfg then logger.error("CharInfoUtils->Can't get weapon breakthrough info, breakthroughTemplateId: " .. breakthroughTemplateId) return end for i, templateCfg in pairs(breakthroughTemplateCfg.list) do if templateCfg.breakthroughShowLv == breakthroughLevel then return templateCfg end end end function CharInfoUtils.getWeaponExhibitBasicInfo(weaponTemplateId, weaponInstId) local _, weaponCfg = Tables.weaponBasicTable:TryGetValue(weaponTemplateId) if not weaponCfg then logger.error("CharInfoUtils->Can't get weapon basic info, templateId: " .. weaponTemplateId) return end local _, weaponItemCfg = Tables.itemTable:TryGetValue(weaponTemplateId) if not weaponItemCfg then logger.error("CharInfoUtils->Can't get weapon item info, templateId: " .. weaponTemplateId) return end local weaponInst = CharInfoUtils.getWeaponByInstId(weaponInstId) local weaponExhibitInfo = {} local gemItemCfg local gemInst if weaponInst.attachedGemInstId and weaponInst.attachedGemInstId > 0 then gemInst = CharInfoUtils.getGemByInstId(weaponInst.attachedGemInstId) local gemTemplateId = gemInst.templateId gemItemCfg = Tables.itemTable:GetValue(gemTemplateId) end weaponExhibitInfo.weaponInst = weaponInst weaponExhibitInfo.weaponCfg = weaponCfg weaponExhibitInfo.itemCfg = weaponItemCfg weaponExhibitInfo.gemItemCfg = gemItemCfg weaponExhibitInfo.gemInst = gemInst local expInfo = CharInfoUtils.getWeaponExpInfo(weaponInstId) if not expInfo then logger.error("CharInfoUtils->Can't get weapon exp info, weaponInstId: " .. weaponInstId) return weaponExhibitInfo end weaponExhibitInfo.breakthroughGold = expInfo.breakthroughGold weaponExhibitInfo.curBreakthroughLv = expInfo.curBreakthroughLv weaponExhibitInfo.maxBreakthroughLv = expInfo.maxBreakthroughLv weaponExhibitInfo.breakthroughTemplateCfg = expInfo.breakthroughTemplateCfg weaponExhibitInfo.breakthroughInfoList = expInfo.breakthroughInfoList weaponExhibitInfo.curLv = expInfo.curLv weaponExhibitInfo.maxLv = expInfo.maxLv weaponExhibitInfo.stageLv = expInfo.stageLv weaponExhibitInfo.nextLvGold = expInfo.nextLvGold weaponExhibitInfo.nextLvExp = expInfo.nextLvExp weaponExhibitInfo.curExp = expInfo.curExp return weaponExhibitInfo end function CharInfoUtils.getWeaponExpInfo(weaponInstId, targetBreakLv) local expInfo = {} local weaponInst = CharInfoUtils.getWeaponByInstId(weaponInstId) local _, weaponCfg = Tables.weaponBasicTable:TryGetValue(weaponInst.templateId) if not weaponCfg then logger.error("CharInfoUtils->Can't get weapon basic info, templateId: " .. weaponInst.templateId) return end local breakthroughTemplateId = weaponCfg.breakthroughTemplateId local _, breakthroughTemplateCfg = Tables.weaponBreakThroughTemplateTable:TryGetValue(breakthroughTemplateId) if not breakthroughTemplateCfg then logger.error("CharInfoUtils->Can't get weapon breakthrough info, breakthroughTemplateId: " .. breakthroughTemplateId) return end local weaponInst = CharInfoUtils.getWeaponByInstId(weaponInstId) local levelUpTemplateId = weaponCfg.levelTemplateId local hasLevelUpCfg, levelUpCfg = Tables.weaponUpgradeTemplateTable:TryGetValue(levelUpTemplateId) if not hasLevelUpCfg then logger.error("CharInfoUtils->Can't get weapon level up info, levelUpTemplateId: " .. levelUpTemplateId) return end local nextLvExp = -1 local nextLvGold = -1 if levelUpCfg.list.Count >= CSIndex(weaponInst.weaponLv + 1) then nextLvExp = levelUpCfg.list[CSIndex(weaponInst.weaponLv)].lvUpExp nextLvGold = levelUpCfg.list[CSIndex(weaponInst.weaponLv)].lvUpGold end local maxLv = weaponCfg.maxLv if targetBreakLv == nil then targetBreakLv = weaponInst.breakthroughLv end local maxBreak, breakLv2StageLv = CharInfoUtils.getWeaponBreakLv2StageLv(weaponInst.templateId) local stageLv = breakLv2StageLv[targetBreakLv] expInfo.curBreakthroughLv = weaponInst.breakthroughLv expInfo.maxBreakthroughLv = maxBreak expInfo.breakthroughTemplateCfg = breakthroughTemplateCfg expInfo.curLv = weaponInst.weaponLv expInfo.maxLv = maxLv expInfo.stageLv = stageLv expInfo.nextLvGold = nextLvGold expInfo.nextLvExp = nextLvExp expInfo.curExp = weaponInst.exp return expInfo end function CharInfoUtils.getWeaponBreakLv2StageLv(templateId) local _, weaponCfg = Tables.weaponBasicTable:TryGetValue(templateId) if not weaponCfg then logger.error("CharInfoUtils->Can't get weapon basic info, templateId: " .. templateId) return end local breakLv2StageLv = {} local breakthroughTemplateId = weaponCfg.breakthroughTemplateId local _, breakthroughTemplateCfg = Tables.weaponBreakThroughTemplateTable:TryGetValue(breakthroughTemplateId) local maxLv = weaponCfg.maxLv local maxStageLv = 1 local maxBreak = 0 for i = 1, breakthroughTemplateCfg.list.Count - 1 do local breakCfg = breakthroughTemplateCfg.list[CSIndex(i)] local nextBreakCfg = breakthroughTemplateCfg.list[CSIndex(i + 1)] if maxLv > nextBreakCfg.breakthroughShowLv then breakLv2StageLv[breakCfg.breakthroughShowLv] = nextBreakCfg.breakthroughLv maxBreak = nextBreakCfg.breakthroughShowLv maxStageLv = math.max(maxStageLv, nextBreakCfg.breakthroughShowLv) end end if maxStageLv < maxLv then breakLv2StageLv[maxBreak] = maxLv end return maxBreak, breakLv2StageLv end function CharInfoUtils.getWeaponShowAttributes(instanceId, level) if level == nil then local weaponInst = CharInfoUtils.getWeaponByInstId(instanceId) level = weaponInst.weaponLv end local mainAttrDict, subAttrDict = CharInfoUtils.getWeaponShowAttributeDict(instanceId, level) local mainAttrShowAttributes = AttributeUtils.generateAttributeShowInfoListByModifierGroup(mainAttrDict) local subAttrShowAttributes = AttributeUtils.generateAttributeShowInfoListByModifierGroup(subAttrDict) return mainAttrShowAttributes, subAttrShowAttributes end function CharInfoUtils.getWeaponShowAttributesByTemplateId(templateId, level) local hasValue, mainAttributeTuple = CS.Beyond.Gameplay.WeaponUtil.TryGetWeaponAttrModifierData(templateId, level) if hasValue then local mainAttrShowAttributes = AttributeUtils.generateAttributeShowInfoListByModifierGroup(CharInfoUtils._generateWeaponAttrDict(mainAttributeTuple)) return mainAttrShowAttributes end end function CharInfoUtils.getWeaponShowAttributesByTemplateIdWithBasicLevel(templateId) return CharInfoUtils.getWeaponShowAttributesByTemplateId(templateId, 1) end function CharInfoUtils.getWeaponShowAttributesByTemplateIdWithMaxLevel(templateId) local hasValue, basicData = Tables.weaponBasicTable:TryGetValue(templateId) if hasValue then return CharInfoUtils.getWeaponShowAttributesByTemplateId(templateId, basicData.maxLv) end end function CharInfoUtils.getWeaponShowAttributeDict(instanceId, level) local hasValue, attrTupleList = CS.Beyond.Gameplay.WeaponUtil.TryGetWeaponAttrModifierData(Utils.getCurrentScope(), instanceId, level) if not hasValue then logger.error("CharInfoUtils->Can't get weapon attributes, instanceId:" .. instanceId) return end local mainAttrDict = {} for i, attrTuple in pairs(attrTupleList) do local attrShowInfo = CharInfoUtils._generateWeaponAttributeData(attrTuple) mainAttrDict[attrShowInfo.attrType] = { [attrShowInfo.modifierType] = attrShowInfo, } end return mainAttrDict, {} end function CharInfoUtils._generateWeaponAttrDict(attrTupleList) local attrDict = {} for _, attrTuple in pairs(attrTupleList) do local attrShowInfo = CharInfoUtils._generateWeaponAttributeData(attrTuple) attrDict[attrShowInfo.attrType] = { [attrShowInfo.modifierType] = attrShowInfo, } end return attrDict end function CharInfoUtils._generateWeaponAttributeData(attrTuple) local attrData = {} local attrType, modifierType, attrValue = attrTuple.Item1, attrTuple.Item2, attrTuple.Item3 attrData.attrType = attrType attrData.modifierType = modifierType attrData.attrValue = attrValue return attrData end function CharInfoUtils.getCharTalentInTable(templateId, breakStage) local charData = CharInfoUtils.getCharTableData(templateId) local talentDataBundle = charData.talentDataBundle local talents = {} for _, talentData in pairs(talentDataBundle) do local talentBreakStage = talentData.breakStage if talentBreakStage <= breakStage then table.insert(talents, talentData) end end return talents end function CharInfoUtils.getCharBreakStageTalents(templateId, breakStage, targetBreakStage, needCurrent) local talents = CharInfoUtils.getCharActiveTalent(templateId, breakStage) local targetTalents = CharInfoUtils.getCharTalentInTable(templateId, targetBreakStage) local unlockTalents = {} local enhancedTalents = {} local tmpUnlockTalents = {} local tmpEnhancedTalents = {} for _, targetTalent in pairs(targetTalents) do local tmpBreakStage = targetTalent.breakStage local targetIndex = targetTalent.talentIndex local tmpUnlockTalent = tmpUnlockTalents[targetIndex] local tmpEnhancedTalent = tmpEnhancedTalents[targetIndex] if not talents[targetIndex] ~= nil then if not tmpUnlockTalent then tmpUnlockTalents[targetIndex] = targetTalent elseif tmpUnlockTalent.breakStage > tmpBreakStage then tmpUnlockTalents[targetIndex] = targetTalent end elseif talents[targetIndex].breakStage < targetTalent.breakStage or needCurrent then if not tmpEnhancedTalent then tmpEnhancedTalents[targetIndex] = targetTalent elseif tmpEnhancedTalent.breakStage == talents[targetIndex].breakStage then tmpEnhancedTalents[targetIndex] = targetTalent elseif targetTalent.breakStage ~= talents[targetIndex].breakStage and tmpEnhancedTalent.breakStage > targetTalent.breakStage then tmpEnhancedTalents[targetIndex] = targetTalent end end end for _, talent in pairs(tmpUnlockTalents) do table.insert(unlockTalents, { talentData = talent }) end for targetIndex, talent in pairs(tmpEnhancedTalents) do table.insert(enhancedTalents, { talentData = needCurrent and talents[targetIndex] or talent, nextBreakStage = talent.breakStage, }) end local resTalents = { unlockTalents = unlockTalents, enhancedTalents = enhancedTalents, } return resTalents end function CharInfoUtils.getCharActiveTalent(templateId, breakStage) local talents = {} return talents end function CharInfoUtils.getTalentSkillData(talentData) local skillDatas = {} for _, talentEffect in pairs(talentData.talentEffects) do if talentEffect.talentEffectType == GEnums.TalentEffectType.AddPassiveSkill then local skillId = talentEffect.passiveSkillId local level = talentEffect.passiveSkillLevel local res, skillPatchData = DataManager:TryGetSkillPatchData(skillId, level) if res then table.insert(skillDatas, skillPatchData) end end end return skillDatas end function CharInfoUtils.getTalentMaxBreakStage(templateId, talentIndex) local characterData = CharInfoUtils.getCharTableData(templateId) local maxBreakStage = -1 local talentDataBundle = characterData.talentDataBundle for luaIndex = 1, talentDataBundle.Count do local talent = talentDataBundle[CSIndex(luaIndex)] if talent.talentIndex == talentIndex then maxBreakStage = math.max(maxBreakStage, talent.breakStage) end end return maxBreakStage end function CharInfoUtils.checkIfSkillElite(skillId, skillLv) end function CharInfoUtils.getCharCurTalentNodes(charInstId) local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local templateId = charInfo.templateId local potentialLevel = 0 local skillNodeList = CharInfoUtils._getCharSkillNodeList(templateId, potentialLevel) local attributeNodeList = {} local passiveNodeATable = {} local passiveNodeBTable = {} local breakNodeTable = {} end function CharInfoUtils._getCharSkillNodeList(templateId, potentialLevel) local charGrowthData = CharInfoUtils.getCharGrowthData(templateId) local skillId2LevelNode = {} for _, skillLevelData in ipairs(charGrowthData.skillLevelUp) do local skillId = skillLevelData.skillId if not skillId2LevelNode[skillId] then skillId2LevelNode[skillId] = {} end local skillLevelList = skillId2LevelNode[skillId] table.insert(skillLevelList, skillLevelData) end return skillId2LevelNode end function CharInfoUtils.classifyMainSkillUpgradeNodes(instId, potentialLevel) local mainSkills = {} local showOrderList = {} local charInst = CharInfoUtils.getPlayerCharInfoByInstId(instId) local charGrowthData = CharInfoUtils.getCharGrowthData(charInst.templateId) local allSkillNode = charGrowthData.skillLevelUp for i, skillNode in pairs(allSkillNode) do local skillGroupId = skillNode.skillGroupId local skillGroupCfg = CharInfoUtils.getSkillGroupCfg(charInst.templateId, skillGroupId) if mainSkills[skillGroupId] == nil then mainSkills[skillGroupId] = {} for index, skillGroupType in ipairs(UIConst.CHAR_INFO_SKILL_SHOW_ORDER) do if skillGroupCfg.skillGroupType == skillGroupType then showOrderList[index] = skillGroupId end end end end for i, skillUpgradeList in pairs(mainSkills) do table.sort(skillUpgradeList, function(a, b) return a.level < b.level end) end return mainSkills, showOrderList end function CharInfoUtils.getCharSpaceshipSkillUpgradeList(templateId) local shipSkills = {} local charSpaceShipSkillList = Tables.spaceshipCharSkillTable[templateId].skillList for _, charSkillCfg in pairs(charSpaceShipSkillList) do local skillIndex = charSkillCfg.skillIndex if shipSkills[skillIndex] == nil then shipSkills[skillIndex] = {} end local skillCfg = Tables.spaceshipSkillTable[charSkillCfg.skillId] table.insert(shipSkills[skillIndex], { charSkillCfg = charSkillCfg, skillCfg = skillCfg }) end for i, shipSkillList in pairs(shipSkills) do table.sort(shipSkillList, function(a, b) return a.skillCfg.level < b.skillCfg.level end) end return shipSkills end function CharInfoUtils.classifyTalentNode(templateId, potentialLevel) local attrNodeList = {} local passiveSkillNodes = {} local shipSkills = {} local charGrowthData = CharInfoUtils.getCharGrowthData(templateId) local allTalentNode = charGrowthData.talentNodeMap for nodeId, nodeInfo in pairs(allTalentNode) do local nodeType = nodeInfo.nodeType if nodeType == GEnums.TalentNodeType.PassiveSkill then local index = nodeInfo.passiveSkillNodeInfo.index if passiveSkillNodes[index] == nil then passiveSkillNodes[index] = {} end table.insert(passiveSkillNodes[index], nodeInfo) elseif nodeType == GEnums.TalentNodeType.Attr then table.insert(attrNodeList, nodeInfo) elseif nodeType == GEnums.TalentNodeType.FactorySkill then local shipSkillId = nodeInfo.nodeId local skillIndex = nodeInfo.factorySkillNodeInfo.index if shipSkills[skillIndex] == nil then shipSkills[skillIndex] = {} end table.insert(shipSkills[skillIndex], nodeInfo) end end table.sort(attrNodeList, function(a, b) if a.attributeNodeInfo.breakStage ~= b.attributeNodeInfo.breakStage then return a.attributeNodeInfo.breakStage < b.attributeNodeInfo.breakStage else local attrTypeA = a.attributeNodeInfo.attributeModifier.attrType local attrTypeB = b.attributeNodeInfo.attributeModifier.attrType return attrTypeA:ToInt() < attrTypeB:ToInt() end end) for index, skillNodeList in pairs(passiveSkillNodes) do table.sort(skillNodeList, function(a, b) return a.passiveSkillNodeInfo.breakStage < b.passiveSkillNodeInfo.breakStage end) end for i, shipSkillNodeList in pairs(shipSkills) do table.sort(shipSkillNodeList, function(a, b) return a.factorySkillNodeInfo.breakStage < b.factorySkillNodeInfo.breakStage end) end local passiveSkillNodeList = {} for index, nodeList in pairs(passiveSkillNodes) do local nodeIndex = nodeList[1].passiveSkillNodeInfo.index passiveSkillNodeList[nodeIndex] = nodeList end local facSkillNodeList = {} for skillIndex, nodeList in pairs(shipSkills) do table.insert(facSkillNodeList, { skillIndex = skillIndex, nodeList = nodeList, }) end return attrNodeList, passiveSkillNodeList, facSkillNodeList end function CharInfoUtils.getSkillType(templateId, skillId) local res, skillTable = Tables.skillLockTable:TryGetValue(templateId) if res then local bundleData = skillTable.BundleData for _, skillData in pairs(bundleData) do if skillData.skillId == skillId then return skillData.skillType end end end return nil end function CharInfoUtils.getPlayerCharSkillByTypeUnlock(charInstId, templateId, skillType, level, teamIndex) return CharInfoUtils.getPlayerCharSkillByType(charInstId, templateId, skillType, level, true, teamIndex) end function CharInfoUtils.getSkillDataById(skillId, level) local get, skillPatchData = DataManager:TryGetSkillPatchData(skillId, level) if not get then skillPatchData = nil end local skillData = { patchData = skillPatchData, level = level, } return skillData end function CharInfoUtils.getPlayerCharSkillByType(charInstId, templateId, skillGroupType, level, onlyUnlock) local charInfo if charInstId ~= nil and not templateId then charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) templateId = charInfo.templateId end local charGrowthData = CharInfoUtils.getCharGrowthData(templateId) local skillGroupData if charGrowthData then for _, data in pairs(charGrowthData.skillGroupMap) do if data.skillGroupType == skillGroupType then skillGroupData = data end end end local skills = {} local skillLevelUpData = CharInfoUtils.getCharSkillLevelData(templateId) if charGrowthData and skillGroupData then local maxLevel local inUse = true local skillId = skillGroupData.skillId local skillGroupId = skillGroupData.skillGroupId local res, skillInfo = CS.Beyond.Gameplay.SkillUtil.TryGetCharSkillGroupInfo(charInstId, skillGroupId) local unlock = true if res then if not level then level = skillInfo.level end maxLevel = skillInfo.maxLevel else if not level then level = 1 end maxLevel = level end local realMaxLevel = skillLevelUpData[skillGroupId] and skillLevelUpData[skillGroupId].realMaxLevel or maxLevel local find, skillData = Tables.skillPatchTable:TryGetValue(skillId) if find and skillData then local _, skillPatchData = DataManager:TryGetSkillPatchData(skillId, level) local btnSkillInfo = { skillId = skillId, patchData = skillPatchData, bundleData = skillGroupData, level = level, maxLevel = maxLevel, inUse = inUse, unlock = unlock, realMaxLevel = realMaxLevel, breakStage = 0, } if not onlyUnlock or (onlyUnlock and unlock) then table.insert(skills, btnSkillInfo) end end end table.sort(skills, Utils.genSortFunction({ "breakStage" }, true)) return skills end function CharInfoUtils.getPlayerCharCurSkills(charInstId) local skills = {} for skillType, btnIndex in pairs(UIConst.SKILL_TYPE_2_BTN_INDEX) do local skillList = CharInfoUtils.getPlayerCharSkillByType(charInstId, nil, skillType, nil, nil) skills[btnIndex] = skillList end return skills end function CharInfoUtils.getCharInfoSkillGroupBgColor(skillGroupCfg, isBattle) local firstSkillId = skillGroupCfg.skillIdList[0] local firstSkillCfg = CharInfoUtils.getSkillCfg(firstSkillId, 1) local iconBgType = firstSkillCfg.iconBgType if iconBgType == CS.Beyond.GEnums.DamageType.Fire then return Color(1, 0.384, 0.239) elseif iconBgType == CS.Beyond.GEnums.DamageType.Pulse then return Color(1, 0.753, 0) elseif iconBgType == CS.Beyond.GEnums.DamageType.Cryst then return Color(0.129, 0.776, 0.816) elseif iconBgType == CS.Beyond.GEnums.DamageType.Natural then return Color(0.671, 0.749, 0) else return isBattle and Color(0.647, 0.647, 0.647) or Color(0.373, 0.373, 0.373) end end function CharInfoUtils.getCharSkillGroupCfgByType(templateId, skillGroupType) local charGrowthData = CharInfoUtils.getCharGrowthData(templateId) if not charGrowthData then return nil end for _, data in pairs(charGrowthData.skillGroupMap) do if data.skillGroupType == skillGroupType and #data.skillIdList > 0 then return data end end return nil end function CharInfoUtils.getCharFirstSkillIdByType(templateId, skillGroupType) local charGrowthData = CharInfoUtils.getCharGrowthData(templateId) if not charGrowthData then return nil end for _, data in pairs(charGrowthData.skillGroupMap) do if data.skillGroupType == skillGroupType and #data.skillIdList > 0 then return data.skillIdList[0] end end return nil end function CharInfoUtils.getCharSkillLevelData(templateId) local data = {} local charData = CharInfoUtils.getCharTableData(templateId) local skillLevelUp = charData.skillLevelUp for _, skillLevelData in pairs(skillLevelUp) do local skillGroupId = skillLevelData.skillGroupId local level = skillLevelData.level if not data[skillGroupId] then data[skillGroupId] = { realMaxLevel = 1, } end data[skillGroupId][level] = skillLevelData data[skillGroupId].realMaxLevel = math.max(data[skillGroupId].realMaxLevel, level) end return data end function CharInfoUtils.getSkillTypeName(skillType) local skillTypeText if skillType == Const.SkillTypeEnum.NormalSkill then skillTypeText = Language.LUA_NORMAL_SKILL elseif skillType == Const.SkillTypeEnum.UltimateSkill then skillTypeText = Language.LUA_ULTIMATE_SKILL else skillTypeText = Language.LUA_NORMAL_ATTACK end return skillTypeText end function CharInfoUtils.getBreakStageUnlockSkills(templateId, breakStage) local charTable = CharInfoUtils.getCharTableData(templateId) local skills = {} local res, breakStageEffectData = charTable.breakStageEffect:TryGetValue(breakStage) if res then skills = breakStageEffectData.skillUnlock end return skills end function CharInfoUtils.getCharSkillUpgradeNextBreakStage(templateId, breakStage, skillType) local targetBreakStage local charTable = CharInfoUtils.getCharTableData(templateId) local maxBreakStage = Tables.characterConst.maxBreak if maxBreakStage == breakStage then return targetBreakStage end for i = breakStage + 1, maxBreakStage do local res, breakStageEffectData = charTable.breakStageEffect:TryGetValue(i) if res then for _, data in pairs(breakStageEffectData.skillEffect) do if data.skillType == skillType then targetBreakStage = i break end end end if targetBreakStage then break end end return targetBreakStage end function CharInfoUtils.getCharSkillLevelInfo(charInfo, skillGroupId) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInfo.instId) local skillGroupList = charInst.skillGroupLevelInfoList for _, skillGroupInfo in pairs(skillGroupList) do if skillGroupInfo.skillGroupId == skillGroupId then return skillGroupInfo end end logger.error(string.format("角色养成->角色templateId[%s]缺少技能组[%s]", charInst.templateId, skillGroupId)) return nil end function CharInfoUtils.getCharSkillLevelByType(templateId, skillGroupType) local skillInfo = CharInfoUtils.getCharSkillLevelInfoByType(templateId, skillGroupType) if skillInfo == nil then return 1 end return skillInfo.level end function CharInfoUtils.getCharSkillLevelInfoByType(charInfo, skillGroupType) local templateId = charInfo.templateId local charGrowthData = CharInfoUtils.getCharGrowthData(templateId) if not charGrowthData then return nil end local skillGroupId for _, data in pairs(charGrowthData.skillGroupMap) do if data.skillGroupType == skillGroupType then skillGroupId = data.skillGroupId break end end if skillGroupId == nil then return nil end local skillLevelInfo = CharInfoUtils.getCharSkillLevelInfo(charInfo, skillGroupId) if skillLevelInfo == nil then return nil end return skillLevelInfo end function CharInfoUtils.getSkillCfg(skillId, skillLv) local get, talentSkillCfg = Tables.SkillPatchTable:TryGetValue(skillId) if not get then logger.error("CharInfoTalentCtrl->_RefreshPassiveSkillCell: skillId not found in SkillPatchTable, skillId = " .. tostring(skillId)) return end local exactSkillCfg for i, skillCfg in pairs(talentSkillCfg.SkillPatchDataBundle) do if skillCfg.level == skillLv then exactSkillCfg = skillCfg break end end return exactSkillCfg end function CharInfoUtils.getShipSkillCfg(skillId) local get, skillCfg = Tables.spaceshipSkillTable:TryGetValue(skillId) if not get then logger.error("CharInfoTalentCtrl->_RefreshPassiveSkillCell: skillId not found in spaceshipSkillTable, skillId = " .. tostring(skillId)) return end return skillCfg end function CharInfoUtils.getSkillGroupCfg(charId, skillGroupId) local charGrowthData = CharInfoUtils.getCharGrowthData(charId) local get, skillGroupData = charGrowthData.skillGroupMap:TryGetValue(skillGroupId) return skillGroupData end function CharInfoUtils.getTalentNodeCfg(charTemplateId, nodeId) local charGrowthCfg = CharInfoUtils.getCharGrowthData(charTemplateId) local success, nodeCfg = charGrowthCfg.talentNodeMap:TryGetValue(nodeId) if success then return nodeCfg end end function CharInfoUtils.getCharSpaceshipSkillIndex(templateId, skillId) local charSpaceShipSkillList = Tables.spaceshipCharSkillTable[templateId].skillList for _, skillCfg in pairs(charSpaceShipSkillList) do if skillCfg.skillId == skillId then return skillCfg.skillIndex end end end function CharInfoUtils.getSkillTalentNodeBySkillId(charTemplateId, skillGroupId, skillLv) local charGrowthCfg = CharInfoUtils.getCharGrowthData(charTemplateId) local skillUpgradeList = charGrowthCfg.skillLevelUp for _, skillUpgradeCfg in pairs(skillUpgradeList) do if skillUpgradeCfg.skillGroupId == skillGroupId and skillUpgradeCfg.level == skillLv then return skillUpgradeCfg end end end function CharInfoUtils.getPassiveSkillTalentNodeByIndex(charTemplateId, nodeIndex, nodeLevel) local foundNodeList = CharInfoUtils.getAllPassiveSkillTalentNodeByIndex(charTemplateId, nodeIndex) if nodeLevel then for i, talentNode in pairs(foundNodeList) do if talentNode.passiveSkillNodeInfo.level == nodeLevel then return talentNode end end end end function CharInfoUtils.getShipSkillIdByTalentNodeId(charTemplateId, nodeId) local charGrowthCfg = CharInfoUtils.getCharGrowthData(charTemplateId) local talentNodeMap = charGrowthCfg.talentNodeMap local talentNode = talentNodeMap[nodeId] if talentNode.nodeType ~= GEnums.TalentNodeType.FactorySkill then return end local index = talentNode.factorySkillNodeInfo.index local level = talentNode.factorySkillNodeInfo.level local shipSkillList = Tables.spaceshipCharSkillTable[charTemplateId].skillList for _, shipSkill in pairs(shipSkillList) do if shipSkill.skillIndex == index then local shipSkillCfg = Tables.spaceshipSkillTable[shipSkill.skillId] if shipSkillCfg.level == level then return shipSkill.skillId end end end end function CharInfoUtils.getAllPassiveSkillTalentNodeByIndex(charTemplateId, nodeIndex) local charGrowthCfg = CharInfoUtils.getCharGrowthData(charTemplateId) local talentNodeMap = charGrowthCfg.talentNodeMap local foundNodeList = {} for _, talentNode in pairs(talentNodeMap) do local passiveSkillNodeInfo = talentNode.passiveSkillNodeInfo if talentNode.nodeType == GEnums.TalentNodeType.PassiveSkill and passiveSkillNodeInfo.index == nodeIndex then table.insert(foundNodeList, talentNode) end end table.sort(foundNodeList, function(a, b) return a.passiveSkillNodeInfo.breakStage < b.passiveSkillNodeInfo.breakStage end) return foundNodeList end function CharInfoUtils.getShipSkillTalentNodeBySkillId(charTemplateId, skillId) local shipSkillCfg = Tables.spaceshipSkillTable[skillId] local skillLevel = shipSkillCfg.level local charShipSkillList = Tables.spaceshipCharSkillTable[charTemplateId].skillList for _, shipSkill in pairs(charShipSkillList) do if shipSkill.skillId == skillId then local skillIndex = shipSkill.skillIndex local charGrowthCfg = CharInfoUtils.getCharGrowthData(charTemplateId) local talentNodeMap = charGrowthCfg.talentNodeMap for _, talentNode in pairs(talentNodeMap) do if talentNode.nodeType == GEnums.TalentNodeType.FactorySkill and talentNode.factorySkillNodeInfo.index == skillIndex and talentNode.factorySkillNodeInfo.level == skillLevel then return talentNode end end end end end function CharInfoUtils.getAttributeNodeStatus(charInstId, attrNodeId) local lockText local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local attrNodeCfg = CharInfoUtils.getTalentNodeCfg(charInst.templateId, attrNodeId) local friendshipValue = CSPlayerDataUtil.GetCharFriendshipByInstId(charInst.instId) local isBelowFriendshipValue = friendshipValue < attrNodeCfg.attributeNodeInfo.favorability local isBelowBreakStage = attrNodeCfg.attributeNodeInfo.breakStage > charInst.breakStage if isBelowFriendshipValue then lockText = Language.LUA_CHAR_INFO_TALENT_BELOW_FRIENDSHIP_TOAST end if isBelowBreakStage then lockText = string.format(Language.LUA_CHAR_INFO_TALENT_UPGRADE_BREAK_LOCK_HINT, attrNodeCfg.attributeNodeInfo.breakStage) end local isLock = isBelowBreakStage or (friendshipValue < attrNodeCfg.attributeNodeInfo.favorability) local isActive = charInst.talentInfo.attributeNodes:Contains(attrNodeId) return isActive, isLock, lockText end function CharInfoUtils.getCharBreakNodeFromStageAndEquipTier(breakStage, equipTierLimit) for nodeId, nodeCfg in pairs(Tables.charBreakNodeTable) do if nodeCfg.breakStage == breakStage and nodeCfg.equipTierLimit == equipTierLimit then return nodeId end end end function CharInfoUtils.getExactSkillIdInSkillGroup(skillGroupData, skillLv) for _, skillData in pairs(skillGroupData.skillIdList) do if skillData.level == skillLv then return skillData.skillId end end end function CharInfoUtils.getCharBreakNodeStatus(charInstId, nodeId) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local charBreakCostMap = CharInfoUtils.getCharGrowthData(charInst.templateId).charBreakCostMap local breakCfg = charBreakCostMap[nodeId] local isLockByLv = false local isLockByEquipTier = breakCfg.equipTierLimit > charInst.equipTierLimit local isLockByBreakStage = breakCfg.breakStage - 1 > charInst.breakStage if charInst.breakStage == breakCfg.breakStage - 1 and (not isLockByEquipTier) then local breakStageCfg = Tables.charBreakStageTable[breakCfg.breakStage - 1] isLockByLv = breakStageCfg.maxCharLevel > charInst.level end local isLock = isLockByEquipTier or isLockByBreakStage or isLockByLv local isActive = charInst.breakStage >= breakCfg.breakStage return isActive, isLock, { isLockByLv = isLockByLv, } end function CharInfoUtils.getEquipBreakNodeStatus(charInstId, nodeId) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local charBreakCostMap = CharInfoUtils.getCharGrowthData(charInst.templateId).charBreakCostMap local breakCfg = charBreakCostMap[nodeId] local isActive = false if breakCfg.breakStage < charInst.breakStage then isActive = true elseif breakCfg.breakStage == charInst.breakStage then isActive = breakCfg.nodeId == charInst.talentInfo.latestBreakNode end local isLock = breakCfg.breakStage > charInst.breakStage return isActive, isLock, { } end function CharInfoUtils.getPassiveSkillNodeStatus(charInstId, nodeId) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local nodeCfg = CharInfoUtils.getTalentNodeCfg(charInst.templateId, nodeId) local passiveSkillNodeInfo = nodeCfg.passiveSkillNodeInfo local isActive, isLock, lockText = CharInfoUtils._innerGetPassiveSkillNodeStatus(charInstId, nodeId) if isActive or isLock then return isActive, isLock, lockText end local foundNodeList = CharInfoUtils.getAllPassiveSkillTalentNodeByIndex(charInst.templateId, passiveSkillNodeInfo.index) table.sort(foundNodeList, function(a,b) return a.passiveSkillNodeInfo.level < b.passiveSkillNodeInfo.level end) for i = passiveSkillNodeInfo.level + 1, #foundNodeList do local nextNodeCfg = foundNodeList[i] if nextNodeCfg then local nextActive = CharInfoUtils._innerGetPassiveSkillNodeStatus(charInstId, nextNodeCfg.nodeId) if nextActive then return true, false end end end if passiveSkillNodeInfo.level > 1 then local previousNodeCfg = foundNodeList[passiveSkillNodeInfo.level - 1] if previousNodeCfg then local lastActive, lastLock = CharInfoUtils._innerGetPassiveSkillNodeStatus(charInstId, previousNodeCfg.nodeId) if not lastActive then return false, true, Language.LUA_CHAR_INFO_TALENT_PREVIOUS_SKILL_INACTIVE end end end return false, false end function CharInfoUtils._innerGetPassiveSkillNodeStatus(charInstId, nodeId) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local nodeCfg = CharInfoUtils.getTalentNodeCfg(charInst.templateId, nodeId) local passiveSkillNodeInfo = nodeCfg.passiveSkillNodeInfo local isActive = charInst.talentInfo.latestPassiveSkillNodes:Contains(nodeId) if isActive then return true, false end local isLock = passiveSkillNodeInfo.breakStage > charInst.breakStage if isLock then local lockText = string.format(Language.LUA_CHAR_INFO_TALENT_UPGRADE_BREAK_LOCK_HINT, passiveSkillNodeInfo.breakStage) return false, true, lockText end return false, false end function CharInfoUtils.getShipSkillTalentNodeByIndex(charTemplateId, index, level) local charGrowthCfg = CharInfoUtils.getCharGrowthData(charTemplateId) local talentNodeMap = charGrowthCfg.talentNodeMap for nodeId, nodeCfg in pairs(talentNodeMap) do if nodeCfg.nodeType == GEnums.TalentNodeType.FactorySkill then local factorySkillNodeInfo = nodeCfg.factorySkillNodeInfo if factorySkillNodeInfo.index == index and factorySkillNodeInfo.level == level then return nodeCfg end end end end function CharInfoUtils.getShipSkillNodeStatus(charInstId, nodeId) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local nodeCfg = CharInfoUtils.getTalentNodeCfg(charInst.templateId, nodeId) local factorySkillNodeInfo = nodeCfg.factorySkillNodeInfo local isActive, isLock, lockText = CharInfoUtils._innerGetFacSkillNodeStatus(charInstId, nodeId) if isActive or isLock then return isActive, isLock, lockText end local foundNodeList = CharInfoUtils.getAllFactorySkillTalentNodeByIndex(charInst.templateId, factorySkillNodeInfo.index) table.sort(foundNodeList, function(a,b) return a.factorySkillNodeInfo.level < b.factorySkillNodeInfo.level end) local nextNodeCfg = foundNodeList[factorySkillNodeInfo.level + 1] if nextNodeCfg then local nextActive = CharInfoUtils._innerGetFacSkillNodeStatus(charInstId, nextNodeCfg.nodeId) if nextActive then return true, false end end if factorySkillNodeInfo.level > 1 then local previousNodeCfg = foundNodeList[factorySkillNodeInfo.level - 1] if previousNodeCfg then local lastActive, lastLock = CharInfoUtils._innerGetFacSkillNodeStatus(charInstId, previousNodeCfg.nodeId) if not lastActive then return false, true, Language.LUA_CHAR_INFO_TALENT_PREVIOUS_SKILL_INACTIVE end end end return false, false end function CharInfoUtils.getAllFactorySkillTalentNodeByIndex(templateId, index) local foundNodeList = {} local charGrowthCfg = CharInfoUtils.getCharGrowthData(templateId) local talentNodeMap = charGrowthCfg.talentNodeMap for i, nodeCfg in pairs(talentNodeMap) do if nodeCfg.nodeType == GEnums.TalentNodeType.FactorySkill then local factorySkillNodeInfo = nodeCfg.factorySkillNodeInfo if factorySkillNodeInfo.index == index then table.insert(foundNodeList, nodeCfg) end end end return foundNodeList end function CharInfoUtils._innerGetFacSkillNodeStatus(charInstId, nodeId) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInstId) local nodeCfg = CharInfoUtils.getTalentNodeCfg(charInst.templateId, nodeId) local factorySkillNodeInfo = nodeCfg.factorySkillNodeInfo local isActive = charInst.talentInfo.latestFactorySkillNodes:Contains(nodeId) if isActive then return true, false end local isLock = factorySkillNodeInfo.breakStage > charInst.breakStage if isLock then local lockText = string.format(Language.LUA_CHAR_INFO_TALENT_UPGRADE_BREAK_LOCK_HINT, factorySkillNodeInfo.breakStage) return false, true, lockText end return false, false end function CharInfoUtils.getSkillCanUpgradeLv(skillGroupType, breakStage) local stageCfg = Tables.charBreakStageTable[breakStage] local canUpgradeLv = 0 if skillGroupType == GEnums.SkillGroupType.NormalAttack then canUpgradeLv = stageCfg.normalAttackSkillLevel elseif skillGroupType == GEnums.SkillGroupType.NormalSkill then canUpgradeLv = stageCfg.normalSkillLevel elseif skillGroupType == GEnums.SkillGroupType.UltimateSkill then canUpgradeLv = stageCfg.ultimateSkillLevel elseif skillGroupType == GEnums.SkillGroupType.ComboSkill then canUpgradeLv = stageCfg.comboSkillLevel else logger.error("CharInfoTalentCtrl->getSkillCanUpgradeLv: skillType can't upgrade !!!!, skillType = " .. tostring(skillGroupType)) end return canUpgradeLv end function CharInfoUtils.getSkillDesc(skillId, skillLv) local skillDesc = Utils.SkillUtil.GetSkillDescription(skillId, skillLv) return skillDesc end function CharInfoUtils.getGroupSkillExtraInfoList(skillGroupId, skillLv) end function CharInfoUtils.getSkillExtraInfoList(skillId, skillLv) local skillExtraInfoList = {} local _, skillPatchData = DataManager:TryGetSkillPatchData(skillId, skillLv) local cooldownTime = skillPatchData.coolDown local costType = skillPatchData.costType local costValue = skillPatchData.costValue local hasUspCost = false if costType == GEnums.CostType.Atb then if costValue > 0 and math.abs(costValue) > 0.01 then local roundedValue = lume.round(costValue) table.insert(skillExtraInfoList, { name = Language.LUA_CHAR_INFO_SKILL_COST_ATB, value = roundedValue, }) end end if costType == GEnums.CostType.UltimateSp then if costValue > 0 and math.abs(costValue) > 0.01 then local roundedValue = lume.round(costValue) table.insert(skillExtraInfoList, { name = Language.LUA_CHAR_INFO_SKILL_COST_SP, value = roundedValue, }) hasUspCost = true end end if cooldownTime and cooldownTime > 0 and math.abs(cooldownTime) > 0.01 then local roundedValue = lume.round(cooldownTime * 10) / 10 if (roundedValue * 10) % 10 == 0 then roundedValue = math.floor(roundedValue) end table.insert(skillExtraInfoList, { name = Language.LUA_CHAR_INFO_SKILL_DURATION, value = string.format(Language.LUA_CHAR_INFO_SKILL_DURATION_FORMAT, roundedValue), }) end return skillExtraInfoList end function CharInfoUtils.isCharBreakCostEnough(templateId, nodeId) local charGrowthData = CharInfoUtils.getCharGrowthData(templateId) if not charGrowthData then return false end local _, charBreakDetailData = charGrowthData.charBreakCostMap:TryGetValue(nodeId) if not charBreakDetailData then return false end for _, itemBundle in pairs(charBreakDetailData.requiredItem) do if Utils.getItemCount(itemBundle.id, true) < itemBundle.count then return false end end return true end function CharInfoUtils.isCharTalentCostEnough(templateId, nodeId) local charGrowthData = CharInfoUtils.getCharGrowthData(templateId) if not charGrowthData then return false end local _, talentNode = charGrowthData.talentNodeMap:TryGetValue(nodeId) if not talentNode then return false end for _, itemBundle in pairs(talentNode.requiredItem) do if Utils.getItemCount(itemBundle.id, true) < itemBundle.count then return false end end return true end function CharInfoUtils.isSkillGroupLevelUpCostEnough(templateId, skillGroupId, skillLv) local skillLevelUpData = CharInfoUtils.getSkillTalentNodeBySkillId(templateId, skillGroupId, skillLv) if not skillLevelUpData then return false end if skillLevelUpData.goldCost > 0 then if Utils.getItemCount(UIConst.INVENTORY_MONEY_IDS[1], true) < skillLevelUpData.goldCost then return false end end for _, itemBundle in pairs(skillLevelUpData.itemBundle) do if Utils.getItemCount(itemBundle.id, true) < itemBundle.count then return false end end return true end function CharInfoUtils.getCharInfoProfile(templateId) local profile = {} local charData = Tables.characterTable[templateId] if charData then profile = { profileVoice = charData.profileVoice, profileRecord = charData.profileRecord, } end return profile end function CharInfoUtils.IsFullLockedTeam() local formationData if FocusModeUtils.isInFocusMode then local curFocusModeInstId = GameInstance.mode.instId if string.isEmpty(curFocusModeInstId) then return false end local _, focusModeData = GameInstance.dataManager.focusModeInstDataTable:TryGetValue(curFocusModeInstId) if not focusModeData then return false end local formulaData = CharInfoUtils.getLockedFormationData(focusModeData.presetTeamId, false) if not formulaData then return false end return true, formulaData end local curDungeonId = GameInstance.dungeonManager.curDungeonId local _, subGameData = DataManager.subGameInstDataTable:TryGetValue(curDungeonId) if subGameData and not string.isEmpty(subGameData.teamConfigId) then formationData = CharInfoUtils.getLockedFormationData(subGameData.teamConfigId, false) if formationData and formationData.lockedTeamMemberCount == formationData.maxTeamMemberCount and not formationData.hasReplaceable then return true, formationData end end return false, formationData end function CharInfoUtils.IsFocusModeFullLockedTeam(focusModeInstId) local curFocusModeInstId = focusModeInstId if not curFocusModeInstId and FocusModeUtils.isInFocusMode then curFocusModeInstId = GameInstance.mode.instId end if string.isEmpty(curFocusModeInstId) then return false end local _, focusModeData = GameInstance.dataManager.focusModeInstDataTable:TryGetValue(curFocusModeInstId) if not focusModeData then return false end local formulaData = CharInfoUtils.getLockedFormationData(focusModeData.presetTeamId, false) if not formulaData then return false end return true, formulaData end function CharInfoUtils.getLockedFormationData(teamConfigId, createClientCharInfo) if string.isEmpty(teamConfigId) then return nil end local hasValue local charTeamData hasValue, charTeamData = Tables.charTeamTable:TryGetValue(teamConfigId) if not hasValue then return nil end local shouldShowTrailTips = #charTeamData.presetCharList > 0 if createClientCharInfo then for _, charPresetId in pairs(charTeamData.presetCharList) do GameInstance.player.charBag:CreateClientCharInfo(charPresetId, ScopeUtil.GetCurrentScope()) end end local lockedTeamData = {} lockedTeamData.teamConfigId = teamConfigId lockedTeamData.maxTeamMemberCount = charTeamData.maxMemberCount local chars = {} for _, charPresetId in pairs(charTeamData.presetTeam) do local charPresetData hasValue, charPresetData = Tables.charPresetTable:TryGetValue(charPresetId) if hasValue then local charInfo = { charId = CharUtils.GetCharTemplateId(charPresetData.charId), charPresetId = charPresetId, isLocked = true, isTrail = true, isReplaceable = false, } if createClientCharInfo then local csCharInfo = CharInfoUtils.getPlayerCharInfoByPresetId(charPresetId) charInfo.charInstId = csCharInfo.instId charInfo.charId = csCharInfo.templateId end table.insert(chars, charInfo) end shouldShowTrailTips = false end local hasReplaceable = false for _, charId in pairs(charTeamData.requireCharTids) do charId = CharUtils.GetCharTemplateId(charId) local found = false for _, charInfo in ipairs(chars) do if charInfo.charId == charId then charInfo.isReplaceable = true found = true hasReplaceable = true break end end if not found then if createClientCharInfo then local foundCharInfo local trailCharInfos = GameInstance.player.charBag.clientCharInfos for _, trailCharInfo in cs_pairs(trailCharInfos) do if trailCharInfo.templateId == charId then foundCharInfo = trailCharInfo break end end if not foundCharInfo then foundCharInfo = CharInfoUtils.getPlayerCharInfoByTemplateId(charId, GEnums.CharType.Default) end local charInfo = { charId = charId, charInstId = foundCharInfo.instId, isLocked = true, isTrail = foundCharInfo.charType == GEnums.CharType.Trial, isReplaceable = true, } table.insert(chars, charInfo) else local isTrail = false local presetId for _, charPresetId in pairs(charTeamData.presetCharList) do local charPresetData hasValue, charPresetData = Tables.charPresetTable:TryGetValue(charPresetId) if hasValue and CharUtils.GetCharTemplateId(charPresetData.charId) == charId then isTrail = true presetId = charPresetId break end end local charInfo = { charId = charId, charPresetId = presetId, isLocked = true, isTrail = isTrail, isReplaceable = true, } table.insert(chars, charInfo) end hasReplaceable = true end shouldShowTrailTips = false end lockedTeamData.chars = chars lockedTeamData.lockedTeamMemberCount = #chars lockedTeamData.hasReplaceable = hasReplaceable lockedTeamData.shouldShowTrailTips = shouldShowTrailTips return lockedTeamData end function CharInfoUtils.getLockedFormationCharTipsShow(charInfo) local isShowFixed = charInfo.isLocked == true and not charInfo.isReplaceable local isShowTrail = charInfo.isTrail and not isShowFixed return isShowFixed, isShowTrail end function CharInfoUtils.getHpBase(charInfo) return CharInfoUtils.getAttrBaseDefault(charInfo.instId, GEnums.AttributeType.MaxHp) end function CharInfoUtils.getAtkBase(charInfo) return CharInfoUtils.getAttrBaseDefault(charInfo.instId, GEnums.AttributeType.Atk) end function CharInfoUtils.getAtkTotalBase(charInfo) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInfo.instId) local atkValue = charInst.attributes:GetValue(GEnums.AttributeType.Atk) local _, atkScalar = CharInfoUtils.getAtkScalar(charInfo) local attrValue = atkValue / (1 + atkScalar) local attrShowInfo = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, attrValue, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }) return attrShowInfo.showValue, attrShowInfo.attributeValue end function CharInfoUtils.getAtkScalar(charInfo) local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInfo.instId) local attributes = charInst.attributes local strScalar = attributes:GetAtkFinalScalarFromStr() local agiScalar = attributes:GetAtkFinalScalarFromAgi() local wisdScalar = attributes:GetAtkFinalScalarFromWisd() local willScalar = attributes:GetAtkFinalScalarFromWill() local mainAttrScalarShowInfo = AttributeUtils.generateAttributeShowInfo( GEnums.AttributeType.Atk, strScalar + agiScalar + wisdScalar + willScalar, { forceShowPercent = UIConst.ATTRIBUTE_GENERATE_FORCE_PERCENT.HAS_PERCENT, fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR, } ) return "+" .. mainAttrScalarShowInfo.showValue, mainAttrScalarShowInfo.attributeValue end function CharInfoUtils.getDefBase(charInfo) return CharInfoUtils.getAttrBaseDefault(charInfo.instId, GEnums.AttributeType.Def) end function CharInfoUtils.getAttrBaseDefault(charInstId, attrType) local attrShowInfo = AttributeUtils.generateAttributeShowInfo(attrType, CharInfoUtils.getCharBaseAttributes(charInstId)[attrType], { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }) return attrShowInfo.showValue, attrShowInfo.attributeValue end function CharInfoUtils.getHpDetailList(charInfo, finalValue) local detailList = {} local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInfo.instId) local attributes = charInst.attributes local rawHp = attributes:GetRawValue(GEnums.AttributeType.MaxHp) local rawHpShowValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.MaxHp, rawHp, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue table.insert(detailList, { showName = Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_HP_RAW, showValue = rawHpShowValue, }) local hpByStr = attributes:GetHpBaseAddFromStrAttribute() local hpByStrShowValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.MaxHp, hpByStr, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue table.insert(detailList, { showName = Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_HP_BY_STR, showValue = hpByStrShowValue, }) local baseHp = attributes:GetBaseValue(GEnums.AttributeType.MaxHp, UIConst.CHAR_INFO_ATTRIBUTE_ALL_FILTER_MASK) local otherBaseHp = baseHp - rawHp - hpByStr if math.abs(otherBaseHp) < 0.001 then return detailList end return detailList end function CharInfoUtils.getAtkBaseDetailList(charInfo, finalValue) local detailList = {} local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInfo.instId) local attributes = charInst.attributes local baseAtkWeapon = 0 local weaponInstId = charInst.weaponInstId local _, itemBundle = GameInstance.player.inventory:TryGetWeaponInst(Utils.getCurrentScope(), weaponInstId) local weaponInst = itemBundle.instData local weaponAttrDict = CharInfoUtils.getWeaponShowAttributeDict(weaponInst.instId, weaponInst.weaponLv) if weaponAttrDict[GEnums.AttributeType.Atk] then for modifierType, attrInfo in pairs(weaponAttrDict[GEnums.AttributeType.Atk]) do if modifierType == GEnums.ModifierType.BaseAddition then baseAtkWeapon = attrInfo.attrValue end end end table.insert(detailList, { showName = Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_ATK_WEAPON, showValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, baseAtkWeapon, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue }) local baseAtkChar = attributes:GetBaseValue(GEnums.AttributeType.Atk, UIConst.CHAR_INFO_ATTRIBUTE_NONE_FILTER_MASK) table.insert(detailList, { showName = Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_ATK_CHAR, showValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, baseAtkChar, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue }) local baseAtk = attributes:GetBaseValue(GEnums.AttributeType.Atk, UIConst.CHAR_INFO_ATTRIBUTE_ALL_FILTER_MASK) local baseAtkOther = baseAtk - baseAtkWeapon - baseAtkChar if math.abs(baseAtkOther) < 0.001 then return detailList end local baseAtkOtherShowValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, baseAtkOther, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue table.insert(detailList, { showName = Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_OTHER, showValue = baseAtkOtherShowValue, }) return detailList end function CharInfoUtils.getAtkTotalBaseDetailList(charInfo, finalValue) local detailList = {} local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInfo.instId) local attributes = charInst.attributes local atkBase = attributes:GetBaseValue(GEnums.AttributeType.Atk) local atkBaseChar = attributes:GetBaseValue(GEnums.AttributeType.Atk, UIConst.CHAR_INFO_ATTRIBUTE_NONE_FILTER_MASK) local subDetailList = {} local atkBaseWeapon = atkBase - atkBaseChar table.insert(subDetailList, { showName = Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_ATK_WEAPON, showValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, atkBaseWeapon, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue, }) table.insert(subDetailList, { showName = Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_ATK_CHAR, showValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, atkBaseChar, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue, }) table.insert(detailList, { showName = Language.LUA_CHAR_INFO_ATTR_ATK_DETAIL_BASE, showValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, atkBase, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue, subDetailList = subDetailList, }) local _, atkBaseMulValue, atkBaseAddValue = attributes:GetBaseFinalAdditionValueForLua(GEnums.AttributeType.Atk) local atkAddition = atkBaseMulValue + atkBaseAddValue local subDetailList = {} if atkBaseAddValue > 0 then table.insert(subDetailList, { showName = Language.LUA_CHAR_INFO_ATTR_ATK_DETAIL_ADDITION_FIXED, showValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, atkBaseAddValue, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue, }) end if atkBaseMulValue > 0 then local atkBaseMulPercentText = string.format("%.1f%%", atkBaseMulValue / atkBase * 100) table.insert(subDetailList, { showName = Language.LUA_CHAR_INFO_ATTR_ATK_DETAIL_ADDITION_PERCENT, showValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, atkBaseMulValue, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue, hintInfo = { title = Language.LUA_CHAR_INFO_ATTR_ATK_DETAIL_ADDITION_PERCENT, mainHint = string.format(Language.LUA_CHAR_INFO_ATTR_ATK_DETAIL_ADDITION_PERCENT_HINT_FORMAT, atkBaseMulPercentText) }, }) end table.insert(detailList, { showName = Language.LUA_CHAR_INFO_ATTR_ATK_DETAIL_ADDITION, showValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, atkAddition, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue, subDetailList = subDetailList, }) local atkSpecialAddition = finalValue - atkBase - atkAddition local atkSpecialAdditionShowInfo = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, atkSpecialAddition, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }) if atkSpecialAdditionShowInfo.modifiedValue > 0 then table.insert(detailList, { showName = Language.LUA_CHAR_INFO_ATTR_ATK_DETAIL_SPECIAL_ADDITION, showValue = atkSpecialAdditionShowInfo.showValue, }) end return detailList end function CharInfoUtils.getAtkScalarDetailList(charInfo, finalValue) local detailList = {} local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInfo.instId) local attributes = charInst.attributes local function getDetail(attrType, attrValue) local attrShowCfg, attrShowInfo attrShowCfg = AttributeUtils.getAttributeShowCfg(attrType) attrShowInfo = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Atk, attrValue, { forceShowPercent = UIConst.ATTRIBUTE_GENERATE_FORCE_PERCENT.HAS_PERCENT, fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }) return { showName = string.format(Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_ATK_SCALAR_FORMAT, attrShowCfg.name), showValue = "+" .. attrShowInfo.showValue, } end local attrValue attrValue = attributes:GetAtkFinalScalarFromStr() if attrValue > 0 then table.insert(detailList, getDetail(GEnums.AttributeType.Str, attrValue)) end attrValue = attributes:GetAtkFinalScalarFromAgi() if attrValue > 0 then table.insert(detailList, getDetail(GEnums.AttributeType.Agi, attrValue)) end attrValue = attributes:GetAtkFinalScalarFromWisd() if attrValue > 0 then table.insert(detailList, getDetail(GEnums.AttributeType.Wisd, attrValue)) end attrValue = attributes:GetAtkFinalScalarFromWill() if attrValue > 0 then table.insert(detailList, getDetail(GEnums.AttributeType.Will, attrValue)) end return detailList end function CharInfoUtils.GetAllCharPotentialInfos() local charPotentialIndex2Infos = {} local charPotentialPicId2Index = {} local charInfos = CharInfoUtils.getCharInfoList() local index = 1 for i, info in pairs(charInfos) do local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(info.instId) local level = charInfo.potentialLevel local success, characterPotentialList = Tables.characterPotentialTable:TryGetValue(info.templateId) if success then local photoCount = 0 for j = CSIndex(1), CSIndex(characterPotentialList.potentialUnlockBundle.Count) do if j >= level then break end local potentialData = characterPotentialList.potentialUnlockBundle[j] local hasPhoto = potentialData.unlockCharPictureItemList and potentialData.unlockCharPictureItemList.Count > 0 if hasPhoto then photoCount = photoCount + 1 end end for j = CSIndex(1), CSIndex(characterPotentialList.potentialUnlockBundle.Count) do if j >= level then break end local potentialData = characterPotentialList.potentialUnlockBundle[j] local hasPhoto = potentialData.unlockCharPictureItemList and potentialData.unlockCharPictureItemList.Count > 0 if hasPhoto then for innerIndex, itemId in pairs(potentialData.unlockCharPictureItemList) do local _, posterId = Tables.pictureItemTable:TryGetValue(itemId) local _, posterData = Tables.pictureTable:TryGetValue(posterId) local _, charCfg = Tables.characterTable:TryGetValue(charInfo.templateId) local posterInfo = { posterData = posterData, charInfo = charInfo, charSortOrder = charCfg.sortOrder, charSortOrderReversal = math.maxinteger - charCfg.sortOrder, charRarity = charCfg.rarity, charRarityReversal = math.maxinteger - charCfg.rarity, charPhotoCount = photoCount, charPhotoCountReversal = math.maxinteger - photoCount, photoLevel = LuaIndex(j), photoLevelReversal = math.maxinteger - LuaIndex(j), innerIndex = innerIndex, innerIndexReversal = math.maxinteger - innerIndex, } table.insert(charPotentialIndex2Infos, posterInfo) charPotentialPicId2Index[posterId] = index index = index + 1 end end end end end return charPotentialIndex2Infos, charPotentialPicId2Index end function CharInfoUtils.getDefDetailList(charInfo, finalAttr) local detailList = {} local charInst = CharInfoUtils.getPlayerCharInfoByInstId(charInfo.instId) local attributes = charInst.attributes local equipDef = attributes:GetBaseValue(GEnums.AttributeType.Def, UIConst.CHAR_INFO_ATTRIBUTE_EQUIP_FILTER_MASK) local equipDefShowValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Def, equipDef, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue table.insert(detailList, { showName = Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_DEF_BASE, showValue = equipDefShowValue, }) local baseDef = attributes:GetBaseValue(GEnums.AttributeType.Def, UIConst.CHAR_INFO_ATTRIBUTE_ALL_FILTER_MASK) local extraBaseDef = baseDef - equipDef if math.abs(extraBaseDef) < 0.001 then return detailList end local extraBaseDefShowValue = AttributeUtils.generateAttributeShowInfo(GEnums.AttributeType.Def, extraBaseDef, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }).showValue table.insert(detailList, { showName = Language.LUA_CHAR_INFO_FULL_ATTRIBUTE_DEF_OTHER, showValue = extraBaseDefShowValue, }) return detailList end function CharInfoUtils.getHpExtra(charInfo) return CharInfoUtils.getAttrExtraDefault(charInfo.instId, GEnums.AttributeType.MaxHp) end function CharInfoUtils.getDefExtra(charInfo) return CharInfoUtils.getAttrExtraDefault(charInfo.instId, GEnums.AttributeType.Def) end function CharInfoUtils.getAttrExtraDefault(charInstId, attrType) local finalAttr = CharInfoUtils.getCharFinalAttributes(charInstId)[attrType] local baseAttr = CharInfoUtils.getCharBaseAttributes(charInstId)[attrType] local attrShowInfo = AttributeUtils.generateAttributeShowInfo(attrType, finalAttr - baseAttr, { fromSpecificSystem = UIConst.CHAR_INFO_ATTRIBUTE_SPECIFIC_SYSTEM.CHAR_FULL_ATTR }) return attrShowInfo.showValue, finalAttr - baseAttr end _G.CharInfoUtils = CharInfoUtils return CharInfoUtils