/** * 体力系统 */ import { HERO_SYSTEM_TYPE, ABI_TYPE, HERO_CE_RATIO, LINEUP_NUM } from '../consts'; import { cal, deepCopy, getAllAttrStage, reduceCe } from './util'; import { HeroModel, HeroType, HeroUpdate, CeAttrData, EPlace, Stone } from '../db/Hero'; import { RoleModel, RoleType, RoleUpdate, CeAttrDataRole } from '../db/Role'; import { AttributeCal } from '../domain/roleField/attribute'; import { ABI_STAGE, SEID_TYPE } from '../consts'; import { gameData, getJobByGradeAndClass, getHeroWakeByQuality, getHeroStarByQuality, getFriendShipById, getSchoolRateByStar, getScollByStar, getTeraph, getEquipQualityIdByEquipIdAndPoint, getEquipStarIdByEquipId, getEquipSuitByHero, getEquipStarMainAttrByStage, getJewelConditionByLvAndSeId } from './data'; import { DicSe } from './dictionary/DicSe'; import { DicRandomEffectPool } from './dictionary/DicRandomEffectPool'; import { SchoolModel } from '../db/School'; import { ABI_TYPE_MAIN, ABI_JOB_STAGE, ABI_STAGE_TO_TYPE } from '../consts/constModules/abilityConst' import { PvpDefenseModel } from '../db/PvpDefense'; import { findIndex } from 'underscore'; import { GuildModel } from '../db/Guild'; import { DicJob } from './dictionary/DicJob'; import { saveCeChangeLog } from './logUtil'; import { JewelType } from '../db/Jewel'; // 修改并下发战力 export async function calPlayerCeAndSave(type: number, roleId: string, originHero: HeroType, update: HeroUpdate, args?: Array, params?: any) { let role = await RoleModel.findByRoleId(roleId); let { attr: roleAttrs = [], serverId } = role; let heroAttrs = await calPlayerCe(originHero, update, type, args, params); // 根据操作计算attr的增加 let newAttr = new AttributeCal(); newAttr.setLv(update.lv||originHero.lv); newAttr.setByDbData(roleAttrs, heroAttrs); let heroCe = newAttr.calCe(); // 计算最终战力 let incCe = heroCe - originHero.ce; // 更新到武将 update.attr = heroAttrs; update.ce = heroCe; if (originHero.historyCe < heroCe) update.historyCe = heroCe; let hero = await HeroModel.updateHeroInfo(roleId, originHero.hid, update, null, true); // 更新武将 返回是战力缩过的 // 更新到角色 let { topLineup, topLineupCe } = await calculatetopLineup(role, originHero.hid, heroCe, originHero._id); // 计算更新最强五人战力 role = await RoleModel.updateRoleInfo(roleId, { ce: role.ce + incCe, topLineup, topLineupCe }); await PvpDefenseModel.updateCe(roleId, originHero.hid, reduceCe(incCe)); // 更新pvp防守阵战力 let guild = await GuildModel.updateCe(roleId, incCe); // 公会更新战力 let pushHeros = new Array<{ hid: number, ce: number, incHeroCe: number }>(); pushHeros.push({ hid: originHero.hid, ce: reduceCe(heroCe), incHeroCe: reduceCe(incCe), }); saveCeChangeLog(role, incCe, role.ce, type, [originHero.hid]); return { pushHeros, role, topLineupCe, hero, guild, serverId } } //全局属性加成 export async function reCalAllHeroCe(type: number, roleId: string, update: RoleUpdate, args?: Array) { let role = await RoleModel.findByRoleId(roleId); let heros = await HeroModel.findByRole(roleId); let roleAttrs = await reCalRoleAttr(type, heros, role, update, args); if(!roleAttrs) return {role, pushHeros: [], ce: role.ce, topLineupCe: role.topLineupCe, serverId: role.serverId, heros }; // 无加成 let pushHeros = new Array<{ hid: number, ce: number, incHeroCe: number }>(); let allIncCe = 0; for (let hero of heros) { let { attr: heroAttrs, lv } = hero; let newAttr = new AttributeCal(); newAttr.setLv(lv); newAttr.setByDbData(roleAttrs, heroAttrs); let heroCe = newAttr.calCe(); // 计算最终战力 if(heroCe != hero.ce) { let incHeroCe = heroCe - hero.ce; allIncCe += incHeroCe; pushHeros.push({ hid: hero.hid, ce: reduceCe(heroCe), incHeroCe: reduceCe(incHeroCe) }); await HeroModel.updateHeroInfo(roleId, hero.hid, { ce: heroCe }); await PvpDefenseModel.updateCe(roleId, hero.hid, reduceCe(incHeroCe)); // 更新pvp防守阵战力 } } let { topLineup, topLineupCe } = await calculatetopLineup(role); // 计算更新最强五人战力 if(allIncCe != 0) { update.attr = roleAttrs; update.topLineup = topLineup; update.topLineupCe = topLineupCe; } // console.log('************ roleAttr', update.attr) role = await RoleModel.incRoleInfo(roleId, { ce: allIncCe },update); let guild = await GuildModel.updateCe(roleId, allIncCe); // 公会更新战力 saveCeChangeLog(role, allIncCe, role.ce, type, args); return { role, pushHeros, ce: role.ce, topLineupCe: role.topLineupCe, guild, serverId: role.serverId, heros } } // 计算武将全局战力 async function reCalRoleAttr(type: number, heros: Array, role: RoleType, update: RoleUpdate, args: Array) { let { attr: roleAttrs } = role; switch (type) { case HERO_SYSTEM_TYPE.ADD_SKIN: roleAttrs = calHeroAddSkin(role, args); break; case HERO_SYSTEM_TYPE.SCHOOL: roleAttrs = calSchoolAddAttr(role, heros, args[0], args[1], args[2]); break; case HERO_SYSTEM_TYPE.SCROLL: roleAttrs = calScrollAddAttr(role, heros, args[0]); break; case HERO_SYSTEM_TYPE.STAR: case HERO_SYSTEM_TYPE.COLORSTAR: case HERO_SYSTEM_TYPE.QUALITY: roleAttrs = await calSchoolStarIncAttr(role, heros, type, args[0], args[1]); break; case HERO_SYSTEM_TYPE.TITLE: roleAttrs = calTitle(role, update); break; case HERO_SYSTEM_TYPE.TERAPH: roleAttrs = calTeraphMainAttr(role, update, args[0]); break; case HERO_SYSTEM_TYPE.TERAPH_UP: roleAttrs = calTeraphAssistAttr(role, update, args[0]); break; } return roleAttrs; } // 计算单个武将战力 export async function calPlayerCe(hero: HeroType, update: HeroUpdate, type: number, args: Array = [], params) { let heroAttrs: CeAttrData[] = []; // {"hp": {"base": number, "fixUp": number, "ratioUp": number}} let addSeidList = new Array(); let removeSeidList = new Array(); switch (type) { case HERO_SYSTEM_TYPE.STAR: case HERO_SYSTEM_TYPE.LVUP: case HERO_SYSTEM_TYPE.COLORSTAR: case HERO_SYSTEM_TYPE.QUALITY: heroAttrs = calHeroStarIncAttr(hero, update, type, addSeidList, removeSeidList); // args: 升的星盘 break; case HERO_SYSTEM_TYPE.TRAIN: heroAttrs = calHeroTrainIncAttr(hero, update); break; case HERO_SYSTEM_TYPE.STAGEUP: heroAttrs = calHeroJobStageUpIncAttr(hero, update, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.SKIN: heroAttrs = calHeroWearSkinIncAttr(hero, update, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.FAVOUR: heroAttrs = calHeroFavourUpIncAttr(hero, update); break; case HERO_SYSTEM_TYPE.CONNECT: heroAttrs = calHeroConectIncAttr(hero, update, args[0]); break; case HERO_SYSTEM_TYPE.COMPOSE_EQUIP: heroAttrs = calComposeEquipIncAttr(hero, update, args[0]); break; case HERO_SYSTEM_TYPE.EQUIP_STRENGTH: heroAttrs = calEquipStrengthIncAttr(hero, update, args); break; case HERO_SYSTEM_TYPE.EQUIP_QUALITY: heroAttrs = calEquipQualityIncAttr(hero, update, args); break; case HERO_SYSTEM_TYPE.EQUIP_STAR: heroAttrs = calEquipStarIncAttr(hero, update, args, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.EQUIP_JEWEL: heroAttrs = calEquipPutOnOrOffJewelIncAttr(hero, update, args, params, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.EQUIP_STONE: heroAttrs = calEquipPutOnOrOffStoneIncAttr(hero, update, args, params, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.JEWEL_RESET_RANDSE: case HERO_SYSTEM_TYPE.JEWEL_QUENCH: heroAttrs = calJewelResetRandSeIncAttr(hero, args, params, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.EQUIP: // heroAttrs = calEquipPutOnOffIncAttr(hero, args, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.EQUIP_BASE: // heroAttrs = calHeroEquipIncAttr(hero); break; case HERO_SYSTEM_TYPE.RESTRENGTHEN: // heroAttrs = calRestrengthenIncAttr(hero, args.shift(), args, addSeidList, removeSeidList); break; case HERO_SYSTEM_TYPE.JEWEL_ON: // heroAttrs = calHeroCeWhenJewelOnOrOff(hero, args[0], args[1]); break; case HERO_SYSTEM_TYPE.JEWEL_OFF: // heroAttrs = calHeroCeWhenJewelOnOrOff(hero, 0, args[0]); break; case HERO_SYSTEM_TYPE.SCROLL: heroAttrs = calHeroCeScrollIncAttr(hero, update); break; default: break; } addSeidEffect(heroAttrs, addSeidList, removeSeidList); // 处理加值 return heroAttrs; } /** * 计算最强阵容战力 * @param role * @param hid * @param ce * @param heroId */ export async function calculatetopLineup(role: RoleType, hid?: number, ce?: number, heroId?: string) { let topLineup = role?.topLineup || new Array(); if(!hid) { // 直接重新排 let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); } else { topLineup.sort((a, b) => { return b.ce - a.ce }); // 0-6,最大-最小 let index = topLineup.findIndex(cur => cur.hid == hid); if(index != -1 && !heroId) { let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); } else { if (index == -1) { // 不在最强列表 if (topLineup.length < LINEUP_NUM) { // 不满6人 topLineup.push({ hid, ce, hero: heroId }); } else if (topLineup.length == LINEUP_NUM) { if (ce > topLineup[topLineup.length - 1].ce) { // 跻身最强6人 topLineup.pop(); topLineup.push({ hid, ce, hero: heroId }); } } else { topLineup.splice(LINEUP_NUM, topLineup.length - LINEUP_NUM); } } else { // 原来就是最强6人 if (ce < topLineup[topLineup.length - 1].ce) { // 滑出最强 let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); } else { topLineup[index].ce = ce; } } } } let topLineupCe = topLineup.reduce((pre, cur) => { return pre + cur.ce }, 0); return { topLineup, topLineupCe }; } /** * 添加皮肤全局加成 * @param args * @param ceAttr */ function calHeroAddSkin(role: RoleType, skinIds: Array) { let { attr: roleAttrs } = role; for (let id of skinIds) { let addSkin = gameData.fashion.get(id); for (let attr of addSkin.globalAttr) { let fixUp = attr.number * HERO_CE_RATIO; updateRoleAttr(roleAttrs, attr.id, { inc: { fixUp } }); } } role.attr = roleAttrs; return roleAttrs; } /** * 升星觉醒升品等 * @param {HeroType} hero 武将更新前的值 * @param {HeroUpdate} update 更新的值 * @param {number} type 养成类型 * @param {number[]} addSeidList 用于更新被动 * @param {number[]} removeSeidList 用于更新被动 */ export function calHeroStarIncAttr(originHero: HeroType, update: HeroUpdate, type: number, addSeidList: Array, removeSeidList: Array) { let { star: originStar, starStage: originStarStage, quality: originQuality, colorStar: originColorStar, colorStarStage: originColorStarStage, attr: heroAttrs, skinId: originSkinId, lv: oldLv } = originHero; let { star = originStar, starStage = originStarStage, quality = originQuality, colorStar = originColorStar, colorStarStage = originColorStarStage, skinId = originSkinId, lv = oldLv } = update; const dicHero = gameData.hero.get(skinId); const isWake = colorStar > 0; // 是否觉醒,只要激活了觉醒,彩星就会 > 1 const isFirstWake = colorStar > 0 && originColorStar <= 0; // 是否是初次觉醒 const isUpStar = originStar != star || originColorStar != colorStar; // 是否有升星 // console.log('*isUpstar', isUpStar, originStar, star, originColorStar, colorStar) if(starStage == ABI_STAGE.START) star--; if(colorStarStage == ABI_STAGE.START) colorStar--; const dicStar = isWake ? getHeroWakeByQuality(dicHero.jobClass, dicHero.quality, colorStar) : getHeroStarByQuality(dicHero.jobClass, quality, star); // 星级表 let stages = new Array(); // 需要升级的阶 if (type == HERO_SYSTEM_TYPE.LVUP) { stages = getAllAttrStage(); } else if (type == HERO_SYSTEM_TYPE.STAR) { let end = isUpStar? ABI_STAGE.END: starStage; if(end < originStarStage) { stages = getAllAttrStage(); } else { for(let i = originStarStage; i < end; i++) { stages.push(i + 1); } } } else if (type == HERO_SYSTEM_TYPE.QUALITY) { stages = getAllAttrStage(); } else if (type = HERO_SYSTEM_TYPE.COLORSTAR) { if (isFirstWake) { // 首次觉醒 stages = getAllAttrStage(); } else { let end = isUpStar? ABI_STAGE.END: colorStarStage; if(end < originColorStarStage) { stages = getAllAttrStage(); } else { for(let i = originColorStarStage; i < end; i++) { stages.push(i + 1); } } } } else if (type == HERO_SYSTEM_TYPE.SKIN) { stages = getAllAttrStage(); } for (let stage of stages) { let targetAttrId = ABI_STAGE_TO_TYPE.get(stage); // 转换为18维的属性id let heroAttr = dicHero.baseAbilityArr.get(targetAttrId); // 武将表hp等 let heroUpAttr = dicHero.baseAbilityUpArr.get(targetAttrId); // 武将表hp_up等 let starUp = 0; // 星级成长 if (!!dicStar && !!dicStar.ceAttr) { starUp = dicStar.ceAttr.get(stage); } let newBase = (heroAttr + lv * (heroUpAttr + starUp)) * HERO_CE_RATIO; updateHeroAttr(heroAttrs, targetAttrId, { set: { base: newBase } }); } let curSeidList = getSeidListOfFashion(skinId, star, colorStar); let preSeidList = getSeidListOfFashion(originSkinId, originStar, originColorStar); curSeidList.forEach((seid, type) => { if (!preSeidList.has(type)) { addSeidList.push(seid, 0); } }); preSeidList.forEach((seid, type) => { if (!curSeidList.has(type)) { removeSeidList.push(seid, 0); } }); originHero.attr = heroAttrs; return heroAttrs;//属性增量可以是多个 } type updateCeAttr = Partial; function updateHeroAttr(heroAttrs: CeAttrData[], id: number, update: { inc?: updateCeAttr, set?: updateCeAttr }) { let index = heroAttrs.findIndex(cur => cur.id == id); let curAttr = heroAttrs[index]; if(!curAttr) { curAttr = new CeAttrData(id); heroAttrs.push(curAttr); index = heroAttrs.length - 1; } if(update.inc) { let { base, equipUp, fixUp, ratioUp } = update.inc; if(base != undefined) curAttr.base += base; if(equipUp != undefined) curAttr.equipUp += equipUp; if(fixUp != undefined) curAttr.fixUp += fixUp; if(ratioUp != undefined) curAttr.ratioUp += ratioUp; } if(update.set) { let { base, equipUp, fixUp, ratioUp } = update.set; if(base != undefined) curAttr.base = base; if(equipUp != undefined) curAttr.equipUp = equipUp; if(fixUp != undefined) curAttr.fixUp = fixUp; if(ratioUp != undefined) curAttr.ratioUp = ratioUp; } if(curAttr.base <= 0 && curAttr.equipUp <=0 && curAttr.fixUp <=0 && curAttr.ratioUp <= 0) { heroAttrs.splice(index, 1); } } type updateCeAttrRole = Partial; function updateRoleAttr(roleAttrs: CeAttrDataRole[], id: number, update: { inc?: updateCeAttrRole, set?: updateCeAttrRole }) { let curAttr = roleAttrs.find(cur => cur.id == id); if(!curAttr) { curAttr = new CeAttrDataRole(id); roleAttrs.push(curAttr); } if(update.inc) { let { fixUp, ratioUp } = update.inc; if(fixUp) curAttr.fixUp = cal.add(curAttr.fixUp, fixUp); if(ratioUp) curAttr.ratioUp = cal.add(curAttr.ratioUp, ratioUp); } if(update.set) { let { fixUp, ratioUp } = update.set; if(fixUp) curAttr.fixUp = fixUp; if(ratioUp) curAttr.ratioUp = ratioUp; } } /** * 获取皮肤上的seid * @param skinId * @param originStar * @param originColorStar */ function getSeidListOfFashion(skinId: number, originStar: number, originColorStar: number) { let seidList = new Map(); // type => seid let dicHero = gameData.hero.get(skinId); let { starSeidArr, colorStarSeidArr } = gameData.heroSkill.get(dicHero.skill); for (let { star, value, type } of starSeidArr) { if (originStar >= star) { seidList.set(type, value); } } for (let { star, value, type } of colorStarSeidArr) { if (originColorStar >= star) { seidList.set(type, value); } } return seidList } /** * 兵种训练 * @param {HeroType} originHero 原始武将 * @param {HeroUpdate} update 更新的数据 */ export function calHeroTrainIncAttr(originHero: HeroType, update: HeroUpdate) { let { attr: heroAttrs, job: oldJob, jobStage: oldJobStage } = originHero; let { job = oldJob, jobStage = oldJobStage } = update; let dicJob = gameData.job.get(job); let lastJob = getJobByGradeAndClass(dicJob.job_class, dicJob.grade - 1); let dicLastJob = lastJob? gameData.job.get(lastJob.jobid): null; for(let i = 1; i <= dicJob.maxStage; i++) { if(oldJobStage < i && jobStage >= i) { let lastAttr = dicLastJob? dicLastJob.ceAttr.get(i).attr: 0; let targetAttrId = dicJob.ceAttr.get(i).id; let targetAttrValue = dicJob.ceAttr.get(i).attr; let inc = (targetAttrValue - lastAttr) * HERO_CE_RATIO; // console.log('*******', targetAttrId, targetAttrValue, lastAttr, inc ) updateHeroAttr(heroAttrs, targetAttrId, { inc: { fixUp: inc } }); } } return heroAttrs; } /** * 兵种进阶 * @param {HeroType} originHero 原始武将 * @param {HeroUpdate} update 更新内容 * @param {number[]} addSeidList 用于更新被动 * @param {number[]} removeSeidList 用于更新被动 */ export function calHeroJobStageUpIncAttr(originHero: HeroType, update: HeroUpdate, addSeidList: Array, removeSeidList: Array) { let { job: oldJob, attr: heroAttrs } = originHero; let { job = oldJob } = update; let lastJob = gameData.job.get(oldJob); let currentJob = gameData.job.get(job); let lastSeids = lastJob?.seid||new Array(); let curSeids = currentJob?.seid||new Array(); for (let seid of curSeids) { let index = findIndex(lastSeids, seid); if (index < 0) { addSeidList.push(seid, 0); } } for (let seid of lastSeids) { let index = findIndex(curSeids, seid); if (index < 0) { removeSeidList.push(seid, 0); } } return heroAttrs; } /** * 初始计算兵种属性 * @param {HeroType} originHero 原始武将 * @param {HeroUpdate} hero 更新后的武将 * @param {number[]} addSeidList 用于更新被动 * @param {number[]} removeSeidList 用于更新被动 */ export function calHeroJobAttr(originHero: HeroType, hero: HeroUpdate, addSeidList: Array, removeSeidList: Array) { let { attr: heroAttrs } = originHero; let currentJob = gameData.job.get(hero.job); let jobGradeAndClass = getJobByGradeAndClass(currentJob.job_class, currentJob.grade - 1); let lastJob: DicJob; if (!!jobGradeAndClass) { lastJob = gameData.job.get(jobGradeAndClass.jobid); } for (let stage = ABI_JOB_STAGE.START; stage <= ABI_JOB_STAGE.END; stage++) { if(hero.jobStage >= stage) { let targetAttrId = currentJob.ceAttr.get(stage).id; let fixUp = currentJob.ceAttr.get(stage).attr * HERO_CE_RATIO; updateHeroAttr(heroAttrs, targetAttrId, { inc: { fixUp }}) } else { if(lastJob) { let targetAttrId = lastJob.ceAttr.get(stage).id; let fixUp = lastJob.ceAttr.get(stage).attr * HERO_CE_RATIO; updateHeroAttr(heroAttrs, targetAttrId, { inc: { fixUp } }); } } }; originHero.attr = heroAttrs; heroAttrs = calHeroJobStageUpIncAttr(originHero, hero, addSeidList, removeSeidList); return heroAttrs; } /** * 穿戴时装的单武将加成 * @param {HeroType} originHero 原始武将 * @param {number} wearSkinId 穿戴的皮肤 * @param {number} pullSkinId 脱下的皮肤 * @param {number[]} addSeidList 用于更新被动 * @param {number[]} removeSeidList 用于更新被动 * @param {boolean} isInit 是否是计算初始战力 */ export function calHeroWearSkinIncAttr(originHero: HeroType, update: HeroUpdate, addSeidList: number[], removeSeidList: number[]) { let { attr: heroAttrs, skinId: originSkinId } = originHero; let { skinId = originSkinId } = update; calHeroStarIncAttr(originHero, update, HERO_SYSTEM_TYPE.SKIN, addSeidList, removeSeidList); let addSkin = gameData.fashionBySkinId.get(skinId); let delSkin = gameData.fashionBySkinId.get(originSkinId); if (delSkin) { for (let attr of delSkin.actorAttr) { let fixUp = -1 * attr.number * HERO_CE_RATIO; updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }); } } for (let attr of addSkin.actorAttr) { let fixUp = attr.number * HERO_CE_RATIO; updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }); } originHero.attr = heroAttrs; return heroAttrs; } /** * 羁绊解锁 * @param {HeroType} originHero 原始武将 * @param {HeroUpdate} update 更新数据 * @param {number} shipId 解锁的那个id */ export function calHeroConectIncAttr(originHero: HeroType, update: HeroUpdate, shipId: number) { let { connections: oldConnections = [], favourLv, attr: heroAttrs } = originHero; let { connections = oldConnections } = update; let oldConnect = oldConnections.find(cur => cur.shipId == shipId); let connect = connections.find(cur => cur.shipId == shipId); let oldLevel = oldConnect?.level||0; let level = connect?.level||0; let fiendShipLevel = gameData.friendShipLevelMap.get(favourLv); let currentShip = getFriendShipById(shipId, level); if (currentShip) { for (let attr of currentShip.attributes) { let fixUp = attr.number * (HERO_CE_RATIO + fiendShipLevel.add); updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }); } } if (level > 1) { let lastShip = getFriendShipById(shipId, oldLevel); if (lastShip) { for (let attr of lastShip.attributes) { let fixUp = -1 * attr.number * (HERO_CE_RATIO + fiendShipLevel.add); updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }) } } } originHero.attr = heroAttrs; return heroAttrs; } /** * 好感度升级,影响羁绊加成 * * @param {HeroType} originHero 原始武将数据 * @param {HeroUpdate} update 更新的数据 */ export function calHeroFavourUpIncAttr(originHero: HeroType, update: HeroUpdate) { let { favourLv: oldFavourLv, attr: heroAttrs } = originHero; let { favourLv = oldFavourLv } = update; let currentFiendShipLevel = gameData.friendShipLevelMap.get(favourLv); let difAdd = currentFiendShipLevel.add; if (oldFavourLv && oldFavourLv > 0) { // 减上一级好感 let lastFiendShipLevel = gameData.friendShipLevelMap.get(oldFavourLv); difAdd -= lastFiendShipLevel.add; } for (let {shipId, level} of originHero.connections) { let dicHeroFriendShip = getFriendShipById(shipId, level); for (let attr of dicHeroFriendShip.attributes) { let fixUp = (attr.number + difAdd ) * HERO_CE_RATIO; updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp } }); } } originHero.attr = heroAttrs; return heroAttrs; } export function calComposeEquipIncAttr(hero: HeroType, update: HeroUpdate, eplaceId: number) { let { attr: heroAttrs } = hero; let newEquip = update.ePlace.find(cur => cur.id == eplaceId); if(newEquip) { let dicEquip = gameData.equipById.get(newEquip.equipId); for(let attr of dicEquip.attribute) { updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp: attr.num * HERO_CE_RATIO } }); } } return heroAttrs; } export function calEquipStrengthIncAttr(hero: HeroType, update: HeroUpdate, eplaceIds: number[]) { let { attr: heroAttrs, ePlace: oldEplace } = hero; let { ePlace: newEplace } = update; for(let eplaceId of eplaceIds) { let oldEquip = oldEplace.find(cur => cur.id == eplaceId); let newEquip = newEplace.find(cur => cur.id == eplaceId); if(newEquip && oldEquip) { let dicEquip = gameData.equipById.get(oldEquip.equipId); for(let attr of dicEquip.attributeUp) { updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp: attr.num * (newEquip.lv - oldEquip.lv) * HERO_CE_RATIO } }); } } } return heroAttrs } export function calEquipQualityIncAttr(hero: HeroType, update: HeroUpdate, eplaceIds: number[]) { let { attr: heroAttrs, ePlace: oldEplace } = hero; let { ePlace: newEplace } = update; for(let eplaceId of eplaceIds) { let oldEquip = oldEplace.find(cur => cur.id == eplaceId); let newEquip = newEplace.find(cur => cur.id == eplaceId); if(newEquip && oldEquip) { let dicOldEquipQuality = getEquipQualityIdByEquipIdAndPoint(oldEquip.equipId, oldEquip.quality, oldEquip.qualityStage); let dicNewEquipQuality = getEquipQualityIdByEquipIdAndPoint(newEquip.equipId, newEquip.quality, newEquip.qualityStage); for(let attr of dicOldEquipQuality.attribute) { updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp: -1 * attr.num * HERO_CE_RATIO } }); } for(let attr of dicNewEquipQuality.attribute) { updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp: attr.num * HERO_CE_RATIO } }); } } } return heroAttrs } export function calEquipStarIncAttr(hero: HeroType, update: HeroUpdate, eplaceIds: number[], addSeidList: number[], removeSeidList: number[]) { // 升星本身的属性加成 let { hid, attr: heroAttrs, ePlace: oldEplace } = hero; let { ePlace: newEplace } = update; for(let eplaceId of eplaceIds) { let oldEquip = oldEplace.find(cur => cur.id == eplaceId); let newEquip = newEplace.find(cur => cur.id == eplaceId); if(newEquip && oldEquip) { let dicOldEquipStar = getEquipStarIdByEquipId(oldEquip.equipId, oldEquip.star); let dicNewEquipStar = getEquipStarIdByEquipId(newEquip.equipId, newEquip.star); // 主属性 for(let attr of getEquipStarMainAttrByStage(oldEquip.equipId, oldEquip.star, oldEquip.starStage)) { updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp: -1 * attr.num * HERO_CE_RATIO } }); } for(let attr of getEquipStarMainAttrByStage(newEquip.equipId, newEquip.star, newEquip.starStage)) { updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp: attr.num * HERO_CE_RATIO } }); } for(let attr of dicOldEquipStar.subAttr) { updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp: -1 * attr.num * HERO_CE_RATIO } }); } for(let attr of dicNewEquipStar.subAttr) { updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp: attr.num * HERO_CE_RATIO } }); } } } // 套装属性 calEquipSuitIncAttr(hid, oldEplace, newEplace, addSeidList, removeSeidList); return heroAttrs; } function calEquipSuitIncAttr(hid: number, oldEplace: EPlace[], newEplace: EPlace[], addSeidList: number[], removeSeidList: number[]) { let dicEquipSuit = getEquipSuitByHero(hid); let oldSuitStars: number[] = [], newSuitStars: number[] = []; for(let equipId of dicEquipSuit.equips) { let oldEquip = oldEplace.find(cur => cur.equipId == equipId); oldSuitStars.push(oldEquip? oldEquip.star: 0); let newEquip = newEplace.find(cur => cur.equipId == equipId); newSuitStars.push(newEquip? newEquip.star: 0); } let oldStar = Math.min(...oldSuitStars); let newStar = Math.min(...newSuitStars); for(let { star, seid } of dicEquipSuit.effect) { if(oldStar >= star) removeSeidList.push(seid); if(newStar >= star) addSeidList.push(seid, 0); } } export function calEquipPutOnOrOffJewelIncAttr(hero: HeroType, update: HeroUpdate, eplaceIds: number[], params: { oldJewel: JewelType, newJewel: JewelType }, addSeidList: number[], removeSeidList: number[]) { let { attr: heroAttrs, ePlace: oldEplace } = hero; let { ePlace: newEplace } = update; for(let eplaceId of eplaceIds) { let oldEquip = oldEplace.find(cur => cur.id == eplaceId); setRandSeToSeidList(params.oldJewel, oldEquip, removeSeidList); let newEquip = newEplace.find(cur => cur.id == eplaceId); setRandSeToSeidList(params.newJewel, newEquip, addSeidList); } return heroAttrs; } function setRandSeToSeidList(jewel: JewelType, equip: EPlace, list: number[]) { if(equip && equip.jewel) { for(let { id, seid, rand } of jewel.randSe) { if(isRandSeUnLock(jewel.id, id, equip.stones)) { list.push(seid, rand); } } } } function isRandSeUnLock(jewelId: number, randSeId: number, stones: Stone[]) { let dicJewel = gameData.jewel.get(jewelId); let dicJewelCondition = getJewelConditionByLvAndSeId(dicJewel.lv, randSeId); let stoneCnt = 0, stoneLv = 0; for(let { stone } of stones) { let dicStone = gameData.stone.get(stone); if(dicStone) { stoneCnt++; stoneLv += dicStone.lv; } } return stoneCnt >= dicJewelCondition.stoneCnt && stoneLv >= dicJewelCondition.stoneLv; } export function calEquipPutOnOrOffStoneIncAttr(hero: HeroType, update: HeroUpdate, eplaceIds: number[], params: { jewel: JewelType }, addSeidList: number[], removeSeidList: number[]) { let { attr: heroAttrs, ePlace: oldEplace } = hero; let { ePlace: newEplace } = update; for(let eplaceId of eplaceIds) { let oldEquip = oldEplace.find(cur => cur.id == eplaceId); updateHeroAttrOfStone(heroAttrs, oldEquip, -1); setRandSeToSeidList(params.jewel, oldEquip, removeSeidList); let newEquip = newEplace.find(cur => cur.id == eplaceId); updateHeroAttrOfStone(heroAttrs, newEquip, 1); setRandSeToSeidList(params.jewel, newEquip, addSeidList); // 地玉石阶数变化可能导致属性词条解锁变化 } return heroAttrs; } function updateHeroAttrOfStone(heroAttrs: CeAttrData[], equip: EPlace, ratio: number) { for(let { stone } of equip.stones) { let dicStone = gameData.stone.get(stone); if(dicStone) { for(let attr of dicStone.attribute) { updateHeroAttr(heroAttrs, attr.id, { inc: { fixUp: ratio * attr.num * HERO_CE_RATIO } }); } } } } export function calJewelResetRandSeIncAttr(hero: HeroType, eplaceIds: number[], params: { oldJewel: JewelType, newJewel: JewelType }, addSeidList: number[], removeSeidList: number[]) { let { attr: heroAttrs, ePlace } = hero; for(let eplaceId of eplaceIds) { let equip = ePlace.find(cur => cur.id == eplaceId); setRandSeToSeidList(params.oldJewel, equip, removeSeidList); setRandSeToSeidList(params.newJewel, equip, addSeidList); } return heroAttrs; } /** * 穿脱, removeSeidList原来身上穿着的所有装备的seid,包括套装的 * @param {HeroType} hero 武将 * @param {number[]} seids args 原来穿着的装备的seid * @param {number[]} addSeidList 用于更新被动 * @param {number[]} removeSeidList 用于更新被动 */ export function calEquipPutOnOffIncAttr(hero: HeroType, seids: Array, addSeidList: Array, removeSeidList: Array) { // 计算身上所有装备的战力值(特技相关以外) let heroAttrs = calHeroEquipIncAttr(hero); // 计算被动技能 let resultSeid = calEquipSeids(hero); for(let seid of resultSeid) { addSeidList.push(seid, 0); } for (let seid of seids) { removeSeidList.push(seid, 0); } return heroAttrs } /** * 计算一个武将身上的所有被动seid * @param {HeroType} hero 武将,equip需要populate */ export function calEquipSeids(_hero: HeroType) { let seids: number[] = []; // // 计算被动技能 // let { ePlace } = hero; // let suits = new Map>(); // suitType => starLevel => DicSuit // for (let { equip } of ePlace) { // if (equip) { // let e = equip; // if (!!e.randSe) { // for (let { seid, rand } of e.randSe) { // seids.push(seid, rand); // } // } // if (e.suitId > 0) { // let { suitType, starLevel } = gameData.suit.get(e.suitId); // if (!suits.has(suitType)) { // suits.set(suitType, new Map()); // } // for(let lv = 1; lv <= starLevel; lv++) { // let dicSuit = getDicSuitByTypeAndLv(suitType, lv); // 计算同type的低阶套装 // if(dicSuit) { // if(!suits.get(suitType).has(lv)) { // suits.get(suitType).set(lv, { dic: dicSuit, count: 0 }); // } // suits.get(suitType).get(lv).count ++; // } // } // } // } // } // for(let [ _suitType, map ] of suits) { // let effectSeid = new Map(); // count => { starLevel, seid } // for(let [ starLevel, { dic: { effect }, count } ] of map) { // for(let { count: effectCount, seid} of effect) { // if(count >= effectCount ) { // 生效 // if(!effectSeid.has(effectCount) || effectSeid.get(effectCount).starLevel < starLevel) { // 没有同数量效果 // effectSeid.set(effectCount, { starLevel, seid }); // } // } // } // } // for(let [_count, { seid }] of effectSeid) { // seids.push(seid, 0); // } // } return seids; } /** * 装备,装备栏升级,装备精炼等涉及到值的 * @param {HeroType} hero 装备更新过的武将 */ export function calHeroEquipIncAttr(hero: HeroType) { let { attr: heroAttrs } = hero; // let setMap = new Map(); // for (let { equip, lv, refineLv } of ePlace) { // if (equip) { // let e = equip; // let dicGoods = gameData.goods.get(e.id); // let { goodsAbility, goodsAbilityUp } = dicGoods; // let dicRefine = gameData.refine.get(refineLv); // let jewel = new Map(); // for (let { jewel: jewelId } of e.holes) { // if (jewelId > 0) { // let g = gameData.goods.get(jewelId); // if (g) { // let jGoods = g.goodsAbility; // jGoods.forEach((value, key) => { // if (!jewel.has(key)) { // jewel.set(key, value); // } else { // jewel.set(key, jewel.get(key) + value); // } // }) // } // } // } // let randMainMap = new Map(); // for(let {id, rand} of (e.randMain||[])) { // randMainMap.set(id, rand); // } // for (let i = ABI_TYPE.ABI_HP; i < ABI_TYPE.ABI_MAX; i++) { // // console.log('***', i); // let value1 = goodsAbility.get(i) || 0 * (HERO_CE_RATIO + e.randRange); // // console.log('基础值', value1); // let valueup = goodsAbilityUp.get(i) || 0; // // console.log('成长', lv, valueup); // let valueRefine = dicRefine ? dicRefine.upPercent : 0; // // console.log('精炼', dicRefine?dicRefine.upPercent:0 ); // let valueJewel = jewel.get(i) || 0; // // console.log('宝石', valueJewel); // let valueGrade = randMainMap.get(i)||0; // // console.log('品相', valueGrade) // let attr = (value1 + lv * valueup) * valueGrade * (HERO_CE_RATIO + valueRefine) + valueJewel * HERO_CE_RATIO * HERO_CE_RATIO; // if(attr >= 0) { // // console.log('装备战力:', i, attr); // if(setMap.has(i)) { // setMap.set(i, setMap.get(i) + Math.floor(attr / HERO_CE_RATIO)); // } else { // setMap.set(i, Math.floor(attr / HERO_CE_RATIO)); // } // } // } // } // } // for (let i = ABI_TYPE.ABI_HP; i < ABI_TYPE.ABI_MAX; i++) { // let attr = setMap.get(i)||0; // updateHeroAttr(heroAttrs, i, { set: { equipUp: attr } }) // } // hero.attr = heroAttrs; return heroAttrs; } /** * 洗炼 * @param {HeroType} hero 更新过的武将 * @param {number} ePaceId 更新的栏位id * @param {number[]} seids 移除的seid * @param {number[]} addSeidList 用于更新被动 * @param {number[]} removeSeidList 用于更新被动 */ export function calRestrengthenIncAttr(hero: HeroType, _ePaceId: number, _seids: Array, _addSeidList: Array, _removeSeidList: Array) { let { attr: heroAttrs } = hero; // let { ePlace } = hero; // let curPlace = ePlace.find(cur => cur.id == ePaceId); // if (curPlace && curPlace.equip) { // let e = curPlace.equip; // for (let { seid, rand } of e.randSe) { // addSeidList.push(seid, rand); // } // } // for (let seid of seids) { // removeSeidList.push(seid) // } return heroAttrs } // 添加技能增加的被动属性 function addSeidEffect(heroAttrs: CeAttrData[], addSeidList: Array, removeSeidList: Array) { // console.log('addSeidList', addSeidList.join()) // console.log('removeSeidList', removeSeidList.join()) let otiginalSeidList = [ { list: addSeidList, multi: 1 }, { list: removeSeidList, multi: -1 } ]; for (let { list, multi } of otiginalSeidList) { let effectList = new Array(); // any: dic_zyz_se表内容 for (let ii = 0; ii < list.length; ii += 2) { let seid = list[ii]; let rand = list[ii + 1] || 0; let dicSeid: DicSe | DicRandomEffectPool = gameData.se.get(seid); if (!dicSeid) dicSeid = gameData.randomEffectPool.get(seid); if (dicSeid && dicSeid.id > 0) { addSeid(effectList, dicSeid.id, rand, dicSeid.gainValueArr) } } // console.log('effectList', JSON.stringify(effectList)); for (let { type, gainValueArr: [ability, value] } of effectList) { if (type == SEID_TYPE.TYPE101) { // 加值 updateHeroAttr(heroAttrs, ability, { inc: {fixUp: value * multi * HERO_CE_RATIO} }); } else if (type == SEID_TYPE.TYPE103) { // 主属性加百分比 if(ABI_TYPE_MAIN.includes(ability)) { updateHeroAttr(heroAttrs, ability, { inc: {ratioUp: value / 1000 * multi} }); } } else if (type == SEID_TYPE.TYPE104) { // 次级属性加百分比 if(!ABI_TYPE_MAIN.includes(ability)) { updateHeroAttr(heroAttrs, ability, { inc: {fixUp: value * 100 * multi * HERO_CE_RATIO } }); } } } } } // 获取dic_zyz_se内容 function addSeid(effectList: Array, seidId: number, rand: number, seidValue = new Array()) { console.log('##### addSeid', effectList, seidId, rand, seidValue) let curSeid: DicSe | DicRandomEffectPool = gameData.se.get(seidId); if (!curSeid) curSeid = gameData.randomEffectPool.get(seidId); if (!curSeid) { console.log("seidId not found:" + seidId); return; } if (!seidValue) seidValue = curSeid.gainValueArr; if (curSeid.type === SEID_TYPE.TYPE999) { for (let i = 0; i < seidValue.length; i++) { addSeid(effectList, seidValue[i], rand); } return; } let seid: DicSe | DicRandomEffectPool = deepCopy(curSeid); console.log('#####', seid) if (curSeid.index > 0) { seid.gainValueArr[curSeid.index - 1] = rand; } effectList.push(seid); } /** * 带上宝石 * @param {HeroType} hero 武将数据 * @param {number} id 带上的宝石 * @param {number} oldId 脱下的宝石 */ function calHeroCeWhenJewelOnOrOff(hero: HeroType, id: number, oldId: number) { let { attr: heroAttrs } = hero; let { goodsAbility } = gameData.goods.get(id)||{ goodsAbility: new Map() }; let { goodsAbility: oldGoodsAbility } = gameData.goods.get(oldId)||{ goodsAbility: new Map() }; let allIds: number[] = []; for(let [ id ] of goodsAbility) { allIds.push(id); } for(let [ id ] of oldGoodsAbility) { if(allIds.indexOf(id) == -1) allIds.push(id); } for(let id of allIds) { let value = goodsAbility.get(id)||0; let oldValue = oldGoodsAbility.get(id)||0; updateHeroAttr(heroAttrs, id, { inc: { equipUp: (value - oldValue) * HERO_CE_RATIO } }) } hero.attr = heroAttrs; return heroAttrs; } /** * 全局加成,百家学宫 * @param role 角色 * @param heros 所有武将 * @param schoolId 学宫学派 * @param hid 换上的武将 * @param preHid 撤下的武将 */ function calSchoolAddAttr(role: RoleType, heros: HeroType[], schoolId: number, hid: number, preHid: number) { let { attr: roleAttrs } = role; let school = gameData.school.get(schoolId); if (!school) return null; let preHero = heros.find(cur => cur.hid == preHid); let curHero = heros.find(cur => cur.hid == hid); let defaultPercent = { mainAttrAPerent: 0, assiAttrAddValue: 0 }; let preRate = preHero ? getSchoolRateByStar(preHero.star, preHero.colorStar, preHero.quality) : defaultPercent; let curRate = curHero ? getSchoolRateByStar(curHero.star, curHero.colorStar, curHero.quality) : defaultPercent; for (let attrId of school.upAttribute) { if(ABI_TYPE_MAIN.includes(attrId)) { // 主属性 let ratioUp = curRate.mainAttrAPerent - preRate.mainAttrAPerent; updateRoleAttr(roleAttrs, attrId, { inc: { ratioUp } }); } else { let fixUp = (curRate.assiAttrAddValue - preRate.assiAttrAddValue) * HERO_CE_RATIO; updateRoleAttr(roleAttrs, attrId, { inc: { fixUp } }); } } return roleAttrs; } /** * 升星,觉醒,升品时,百家学宫配置武将会相应修改全局战力 * @param {HeroType[]} heros 全部武将 * @param {number} type 类型 HERO_SYSTEM_TYPE * @param {number} hid 更新的那个武将 * @param {number} isStarUp 是否升星 */ async function calSchoolStarIncAttr(role: RoleType, heros: HeroType[], type: number, hid: number, isStarUp: number) { let { roleId, attr: roleAttrs } = role; if ((type == HERO_SYSTEM_TYPE.STAR || type == HERO_SYSTEM_TYPE.COLORSTAR) && !isStarUp) { return null; } let hero = heros.find(cur => cur.hid == hid); if(!hero) return null; let curHeroInSchool = await SchoolModel.findByHid(roleId, hid); if (!curHeroInSchool) return null; let preStar = hero.star, preColorStar = hero.colorStar, preQuality = hero.quality; if (type == HERO_SYSTEM_TYPE.STAR && isStarUp) { preStar--; } else if (type == HERO_SYSTEM_TYPE.QUALITY) { preQuality--; } else if (type == HERO_SYSTEM_TYPE.COLORSTAR) { preColorStar--; if(preColorStar <= 0) preQuality--; } else { return null; } let school = gameData.school.get(curHeroInSchool.schoolId); let preRate = getSchoolRateByStar(preStar, preColorStar, preQuality); let curRate = getSchoolRateByStar(hero.star, hero.colorStar, hero.quality); for (let attrId of school.upAttribute) { if(ABI_TYPE_MAIN.includes(attrId)) { // 主属性 let ratioUp = curRate.mainAttrAPerent - preRate.mainAttrAPerent; updateRoleAttr(roleAttrs, attrId, { inc: { ratioUp } }); } else { let fixUp = (curRate.assiAttrAddValue - preRate.assiAttrAddValue) * HERO_CE_RATIO; updateRoleAttr(roleAttrs, attrId, { inc: { fixUp } }); } } return roleAttrs; } /** * 全局加成, 名将谱 * @param heros 所有武将 * @param hid 激活的武将 * @param ceAttr */ function calScrollAddAttr(role: RoleType,heros: HeroType[], hid: number) { let { attr: roleAttrs } = role; // console.log('********** calScrollAddAttr', hid) let curHero = heros.find(cur => cur.hid == hid); let dicHero = gameData.hero.get(hid); if (!curHero || !dicHero) return roleAttrs; let { quality } = dicHero; let { star, quality: curQuality, colorStar } = curHero; // console.log('********** calScrollAddAttr curHero', star, curQuality, colorStar); let heroScroll = getScollByStar(quality, star, curQuality, colorStar); if (!heroScroll) return roleAttrs; // console.log('********** heroScroll', heroScroll); let isInit = star == dicHero.initialStars && curQuality == dicHero.quality && colorStar == 0; let preScroll = isInit? null: gameData.preHeroScroll.get(heroScroll.id); // console.log('********** preScroll', preScroll); heroScroll.ceAttr.forEach((add, attrId) => { let preAdd = preScroll ? preScroll.ceAttr.get(attrId) : 0; let fixUp = (add - preAdd) * HERO_CE_RATIO; // console.log('********** preAdd', attrId, preAdd, fixUp); updateRoleAttr(roleAttrs, attrId, { inc: { fixUp } }); }); return roleAttrs; } /** * 名将谱激活增加单个武将好感 * @param originHero 原始武将 * @param update 更新数据 */ function calHeroCeScrollIncAttr(originHero: HeroType, update: HeroUpdate) { let { attr: heroAttrs, favourLv: oldFavourLv } = originHero; let { favourLv = oldFavourLv } = update; if (favourLv != oldFavourLv) { heroAttrs = calHeroFavourUpIncAttr(originHero, update); } return heroAttrs; } /** * 升爵位 * @param role 角色数据 * @param titleId 升到哪个爵位 */ function calTitle(role: RoleType, update: RoleUpdate) { let { title: oldTitle, attr: roleAttrs } = role; let { title: newTitle = oldTitle } = update; let dicOldTitle = gameData.title.get(oldTitle)||{ mainAttrValue: new Map(), assiAttrValue: new Map() }; let dicNewTitle = gameData.title.get(newTitle); for (let i = ABI_TYPE.ABI_HP; i < ABI_TYPE.ABI_MAX; i++) { if (dicNewTitle.mainAttrValue.has(i) || dicOldTitle.mainAttrValue.has(i)) { let fixUp = ((dicNewTitle.mainAttrValue.get(i) || 0) - (dicOldTitle.mainAttrValue.get(i) || 0)) * HERO_CE_RATIO; updateRoleAttr(roleAttrs, i, { inc: { fixUp } }); } if (dicNewTitle.assiAttrValue.has(i) || dicOldTitle.mainAttrValue.has(i)) { let fixUp = ((dicNewTitle.assiAttrValue.get(i) || 0) - (dicOldTitle.assiAttrValue.get(i) || 0)) * HERO_CE_RATIO; updateRoleAttr(roleAttrs, i, { inc: { fixUp } }); } } return roleAttrs; } /** * 神像强化,更新主属性加成 * @param role 角色数据 * @param update 更新数据 * @param id 更新哪座神像 */ function calTeraphMainAttr(role: RoleType, update: RoleUpdate, id: number) { let { attr: roleAttrs, teraphs: oldTeraphs = [] } = role; let { teraphs = oldTeraphs } = update; let oldTeraph = oldTeraphs.find(cur => cur.id == id); let teraph = teraphs.find(cur => cur.id == id); if(teraph && teraph.attr) { for(let [attrId, val] of teraph.attr) { let oldVal = 0; if(oldTeraph && oldTeraph.attr && oldTeraph.attr.has(attrId)) { oldVal = oldTeraph.attr.get(attrId); } let fixUp = (val - oldVal) * HERO_CE_RATIO; updateRoleAttr(roleAttrs, attrId, { inc: {fixUp} }) } } return roleAttrs; } /** * 神像进阶,更新次级属性加成 * @param role 角色数据 * @param update 更新数据 * @param id 更新哪座神像 */ function calTeraphAssistAttr(role: RoleType, update: RoleUpdate, id: number) { let { attr: roleAttrs, teraphs: oldTeraphs = [] } = role; let { teraphs = oldTeraphs } = update; let oldTeraph = oldTeraphs.find(cur => cur.id == id); let teraph = teraphs.find(cur => cur.id == id); let dicOldTeraph = getTeraph(id, oldTeraph?.grade); let dicTeraph = getTeraph(id, teraph?.grade); if(!dicTeraph) return null; dicTeraph.assiAttrValue.forEach((val, attrId) => { let oldVal = 0; if(dicOldTeraph && dicOldTeraph.assiAttrValue && dicOldTeraph.assiAttrValue.has(attrId)) { oldVal = dicOldTeraph.assiAttrValue.get(attrId); } let fixUp = (val - oldVal) * HERO_CE_RATIO; updateRoleAttr(roleAttrs, attrId, { inc: { fixUp } }); }); return roleAttrs; }