import { EQUIP_EPLACEID, EQUIP_STONE, FRIENDSHIP_INDEX, HERO_SYSTEM_TYPE, LINEUP_NUM, RESONANCE, RESONANCE_SORT_TYPE } from "../../consts"; import { ArtifactModel } from "../../db/Artifact"; import { EPlace, HeroModel, HeroType } from "../../db/Hero"; import { JewelModel, JewelType } from "../../db/Jewel"; import { ResonanceModel, ResonanceType } from "../../db/Resonance"; import { RoleModel } from "../../db/Role"; import { HeroParam } from "../../domain/roleField/hero"; import { gameData, getEquipByJobClassAndEPlace } from "../../pubUtils/data"; import { ReturnResonanceParam } from "../../pubUtils/interface"; import { calculateCeWithHeroes } from "../playerCeService"; import { getNewJob, initSkinTalent } from "../roleService"; import { pick } from 'underscore'; import * as util from 'util'; export async function refreshResonanceData(roleId: string, serverId: number, sid: string) { let resonanceDatas: ReturnResonanceParam[] = []; let resonanceLv = {}, resonanceJob = {}, resonanceCon = [], resonanceEquip = [], resonanceEpQuality = [], resonanceEpStar = [], resonanceJewel = [], resonanceStone = []; let role = await RoleModel.findByRoleId(roleId); let topHids = role.topLineup.map(cur => cur.hid); if (topHids.length < LINEUP_NUM) return { resonanceDatas }; let { dbResonanceMap, newPositionArr, posHids } = await getResonanceDataMap(roleId); resonanceDatas = newPositionArr; let dbHeroes: HeroType[] = await HeroModel.findByHidsAndRole(roleId, [...topHids, ...posHids]); let topLineHeroes: HeroType[] = []; for (const top of role.topLineup) { topLineHeroes.push(dbHeroes.find(cur => cur.hid == top.hid)); } let dbJewelMap = await getJewelDataMap(dbHeroes); // 武将等级 let topLineHero: HeroType = sortData(topLineHeroes, RESONANCE_SORT_TYPE.LV); resonanceLv = { hid: topLineHero.hid, lv: topLineHero.lv }; for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); hero.lv = topLineHero.lv; hero.exp = topLineHero.exp; } // 职业(职阶、天赋) topLineHero = sortData(topLineHeroes, RESONANCE_SORT_TYPE.JOBSTAGE); resonanceJob = { hid: topLineHero.hid, job: topLineHero.job, jobStage: topLineHero.jobStage }; for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); let preJobStage = hero.jobStage; hero.jobStage = topLineHero.jobStage; hero.job = getNewJob(hero, topLineHero.job); if (preJobStage != hero.jobStage) { //天赋树置空 hero.skins = initSkinTalent(hero.skins || []); } } // 羁绊1, 2, 3 for (let index = 1; index <= FRIENDSHIP_INDEX.THREE; index++) { topLineHero = sortData(topLineHeroes, RESONANCE_SORT_TYPE.CONNECT, index); const topDicShipId = gameData.friendShipByIndex.get(`${topLineHero.hid}_${index}`); const topShipData = (topLineHero.connections || []).find(cur => cur.shipId == topDicShipId); resonanceCon.push({ hid: topLineHero.hid, index, level: topShipData?.level || 0 }); if (!topShipData) continue; for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); const dicShipId = gameData.friendShipByIndex.get(`${hero.hid}_${index}`) let shipData = hero.connections.find(cur => cur.shipId == dicShipId); const dicShipData = gameData.friendShipsByLv.get(`${hid}_${dicShipId}_${topShipData?.level || 0}`); let sign = true; for (let hi of dicShipData?.hids || []) { if (!dbHeroes.find(cur => cur.hid == hi)) { sign = false; break; } } if (!sign) continue; if (!shipData) hero.connections.push({ shipId: dicShipId, level: topShipData?.level || 0, exp: topShipData?.exp || 0 }); else { shipData.shipId = dicShipId shipData.exp = topShipData?.exp || 0; shipData.level = topShipData?.level || 0; } } } // 装备 1武器,2衣甲,3帽子,4鞋子 for (let id = 1; id <= EQUIP_EPLACEID.SHOE_ID; id++) { //装备强化 topLineHero = sortData(topLineHeroes, RESONANCE_SORT_TYPE.EQUIP_LV, id); let topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); if (!topLineHeroEplace) resonanceEquip.push({ hid: topLineHero.hid, id, lv: 0 }); else resonanceEquip.push({ hid: topLineHero.hid, id, lv: topLineHeroEplace?.lv || 0 }); for (let [hid] of dbResonanceMap) { if (!topLineHeroEplace || !topLineHeroEplace.lv) continue; let hero = dbHeroes.find(cur => cur.hid == hid); let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...getInitEplace(id, hero.skinId) }); ePlaceData = hero.ePlace.find(cur => cur.id == id); } ePlaceData.lv = topLineHeroEplace.lv; } //装备升品 topLineHero = sortData(topLineHeroes, RESONANCE_SORT_TYPE.EQUIP_QUALITY, id); topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); if (!topLineHeroEplace) resonanceEpQuality.push({ hid: topLineHero.hid, id, quality: 0, qualityStage: 0 }) else resonanceEpQuality.push({ hid: topLineHero.hid, id, quality: topLineHeroEplace?.quality || 0, qualityStage: topLineHeroEplace?.qualityStage || 0 }) for (let [hid] of dbResonanceMap) { if (!topLineHeroEplace || (!topLineHeroEplace.quality && !topLineHeroEplace.qualityStage)) continue; let hero = dbHeroes.find(cur => cur.hid == hid); let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...getInitEplace(id, hero.skinId) }); ePlaceData = hero.ePlace.find(cur => cur.id == id); }; ePlaceData.quality = topLineHeroEplace.quality; ePlaceData.qualityStage = topLineHeroEplace.qualityStage; } //装备精练 topLineHero = sortData(topLineHeroes, RESONANCE_SORT_TYPE.EQUIP_STAR, id); topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); if (!topLineHeroEplace) resonanceEpStar.push({ hid: topLineHero.hid, id, star: 0, starStage: 0 }) else resonanceEpStar.push({ hid: topLineHero.hid, id, star: topLineHeroEplace?.star || 0, starStage: topLineHeroEplace?.starStage || 0 }) for (let [hid] of dbResonanceMap) { if (!topLineHeroEplace || (!topLineHeroEplace.star && !topLineHeroEplace.starStage)) continue; let hero = dbHeroes.find(cur => cur.hid == hid); let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...getInitEplace(id, hero.skinId) }); ePlaceData = hero.ePlace.find(cur => cur.id == id); }; ePlaceData.star = topLineHeroEplace.star; ePlaceData.starStage = topLineHeroEplace.starStage; } //天晶 if (RESONANCE.JEWEL) { topLineHero = sortData(topLineHeroes, RESONANCE_SORT_TYPE.JEWEL, id, dbJewelMap); topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); if (!topLineHeroEplace) resonanceJewel.push({ hid: topLineHero.hid, id, jewel: 0 }); else resonanceJewel.push({ hid: topLineHero.hid, id, jewel: topLineHeroEplace?.jewel || 0 }); //破,御,护,命 for (let [hid] of dbResonanceMap) { if (!topLineHeroEplace || !topLineHeroEplace.jewel) continue; let hero = dbHeroes.find(cur => cur.hid == hid); let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...getInitEplace(id, hero.skinId) }); ePlaceData = hero.ePlace.find(cur => cur.id == id); }; ePlaceData.jewel = topLineHeroEplace.jewel; } } //地玉 if (RESONANCE.STONE) { //破,御,护,命 1,2,3 resonanceStone.push({ id, stones: [] }); for (let index = 1; index <= EQUIP_STONE.THREE; index++) { topLineHero = sortData(topLineHeroes, RESONANCE_SORT_TYPE.STONE, id, null, index); topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); resonanceStone.find(cur => cur.id == id).stones.push({ hid: topLineHero.hid, id: index, stone: 0 }); if (topLineHeroEplace && topLineHeroEplace.stones) { const topLineHeroStone = topLineHeroEplace.stones.find(cur => cur.id == index); if (topLineHeroStone) resonanceStone.find(cur => cur.id == id).stones.find(cur => cur.id == index).stone = topLineHeroStone.stone; } for (let [hid] of dbResonanceMap) { if (!topLineHeroEplace || !topLineHeroEplace.stones) continue; const topLineHeroStone = topLineHeroEplace.stones.find(cur => cur.id == index); if (!topLineHeroStone || !topLineHeroStone.stone) continue; let hero = dbHeroes.find(cur => cur.hid == hid); let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...getInitEplace(id, hero.skinId) }); ePlaceData = hero.ePlace.find(cur => cur.id == id); }; ePlaceData.stones.find(cur => cur.id == index).stone = topLineHeroStone.stone; } } } } let newHeroes: HeroType[] = []; for (let hero of dbHeroes) { if (dbResonanceMap.has(hero.hid)) newHeroes.push(hero); } // 重新计算战力 if (newHeroes.length > 0) { let artifacts = await ArtifactModel.findbyHids(roleId, posHids); let { heroes } = await calculateCeWithHeroes(HERO_SYSTEM_TYPE.RESONANCE_CAL, roleId, serverId, sid, newHeroes, { jewels: [...dbJewelMap.values()], heroes: newHeroes, artifacts }); for (let hero of (heroes || [])) { const { hid } = hero; const heroResult = new HeroParam(hero); resonanceDatas.push({ isResonance: true, position: dbResonanceMap.get(hid).position, ...pick(heroResult, ['hid', 'seqId', 'lv', 'exp', 'job', 'jobStage', 'talent', 'usedTalentPoint', 'totalTalentPoint', 'connections', 'ePlace', 'ce']) }); } } return { resonanceDatas, resonanceLv, resonanceJob, resonanceCon, resonanceEquip, resonanceEpQuality, resonanceEpStar, resonanceJewel, resonanceStone }; } export function sortData(heroes: HeroType[], sortType: number, findType?: number, jewelMap?: Map, extendValue?: number) { switch (sortType) { case RESONANCE_SORT_TYPE.LV: { heroes.sort((a, b) => { if (a.lv !== b.lv) { return b.lv - a.lv; } else { return b.ce - a.ce; } }); break; } case RESONANCE_SORT_TYPE.JOBSTAGE: { heroes.sort((a, b) => { let gradeA = gameData.job.get(a.job)?.grade || 0; let gradeB = gameData.job.get(b.job)?.grade || 0; if (gradeA != gradeB) { return gradeB - gradeA; } else if (a.jobStage !== b.jobStage) { return b.jobStage - a.jobStage; } else { return b.ce - a.ce; } }); break; } case RESONANCE_SORT_TYPE.CONNECT: { heroes = sortByConnect(heroes, findType) break; } case RESONANCE_SORT_TYPE.EQUIP_LV: { heroes = sortByEquipLv(heroes, findType); break; } case RESONANCE_SORT_TYPE.EQUIP_QUALITY: { heroes = sortByEquipQuality(heroes, findType); break; } case RESONANCE_SORT_TYPE.EQUIP_STAR: { heroes = sortByEquipStar(heroes, findType); break; } case RESONANCE_SORT_TYPE.JEWEL: { heroes = sortByEquipJewel(heroes, findType, jewelMap); break; } case RESONANCE_SORT_TYPE.STONE: { heroes = sortByEquipStone(heroes, findType, extendValue); break; } } let topLineHeroes: HeroType[] = heroes; // console.log('-x-x--x-x-x-x-x-x-x-x-x- topLineHeroes', util.inspect(heroes, { depth: null })); return topLineHeroes[LINEUP_NUM - 1]; } export function sortByConnect(heroes: HeroType[], index: number) { heroes.sort((a, b) => { const dicShipIdA = gameData.friendShipByIndex.get(`${a.hid}_${index}`) const valA = a.connections.find(obj => obj.shipId === dicShipIdA)?.level || 0; const dicShipIdB = gameData.friendShipByIndex.get(`${b.hid}_${index}`) const valB = b.connections.find(obj => obj.shipId === dicShipIdB)?.level || 0; if (valA != valB) { return valB - valA; } else { return b.ce - a.ce; } }); return heroes } export function sortByEquipLv(heroes: HeroType[], id: number) { heroes.sort((a, b) => { const valA = a.ePlace.find(obj => obj.id == id)?.lv || 0 const valB = b.ePlace.find(obj => obj.id == id)?.lv || 0; if (valA != valB) { return valB - valA; } else { return b.ce - a.ce; } }); return heroes; } export function sortByEquipQuality(heroes: HeroType[], id: number) { heroes.sort((a, b) => { const valA = a.ePlace.find(obj => obj.id == id)?.quality || 0; const valStageA = a.ePlace.find(obj => obj.id == id)?.qualityStage || 0; const valB = b.ePlace.find(obj => obj.id == id)?.quality || 0; const valStageB = b.ePlace.find(obj => obj.id == id)?.qualityStage || 0; if (valA != valB) { return valB - valA; } else if (valStageA != valStageB) { return valStageB - valStageA; } else { return b.ce - a.ce; } }); return heroes; } export function sortByEquipStar(heroes: HeroType[], id: number) { heroes.sort((a, b) => { const valA = a.ePlace.find(obj => obj.id == id)?.star || 0; const valStageA = a.ePlace.find(obj => obj.id == id)?.starStage || 0; const valB = b.ePlace.find(obj => obj.id == id)?.star || 0; const valStageB = b.ePlace.find(obj => obj.id == id)?.starStage || 0; if (valA != valB) { return valB - valA; } else if (valStageA != valStageB) { return valStageB - valStageA; } else { return b.ce - a.ce; } }); return heroes; } export function sortByEquipJewel(heroes: HeroType[], eplaceId: number, jewelMap: Map) { heroes.sort((a, b) => { const jewelA = a.ePlace.find(obj => obj.id == eplaceId)?.jewel || 0 let jewelAData = jewelMap.get(jewelA); const dicJewelALv = gameData.jewel.get(jewelAData?.id || 0)?.lv || 0; let valA = 0; if (jewelAData) { if (jewelAData.randSe && jewelAData.randSe.length > 0) { for (let { seid, rand } of jewelAData.randSe) { let dicRandomEffectPool = gameData.randomEffectPool.get(seid); if (!dicRandomEffectPool) continue; if (!dicRandomEffectPool.Max) dicRandomEffectPool = gameData.randomEffectPool.get(1); if (!dicRandomEffectPool || ((dicRandomEffectPool?.Max || 0) == 0)) continue; valA += rand / (dicRandomEffectPool.Max); } } if (jewelAData.rareSe && jewelAData.rareSe.length > 0) { for (let { seid, rand } of jewelAData.rareSe) { let dicRandomEffectPool = gameData.randomEffectPool.get(seid); if (!dicRandomEffectPool) continue; if (!dicRandomEffectPool.Max) dicRandomEffectPool = gameData.randomEffectPool.get(1); if (!dicRandomEffectPool || ((dicRandomEffectPool?.Max || 0) == 0)) continue; valA += rand / (dicRandomEffectPool.Max); } } } const jewelB = b.ePlace.find(obj => obj.id == eplaceId)?.jewel || 0 let jewelBData = jewelMap.get(jewelB); const dicJewelBLv = gameData.jewel.get(jewelBData?.id || 0)?.lv || 0; let valB = 0; if (jewelBData) { if (jewelBData.randSe && jewelBData.randSe.length > 0) { for (let { seid, rand } of jewelBData.randSe) { let dicRandomEffectPool = gameData.randomEffectPool.get(seid); if (!dicRandomEffectPool) continue; if (!dicRandomEffectPool.Max) dicRandomEffectPool = gameData.randomEffectPool.get(1); if (!dicRandomEffectPool || (dicRandomEffectPool?.Max || 0) == 0) continue; valB += rand / (dicRandomEffectPool.Max); } } if (jewelBData.rareSe && jewelBData.rareSe.length > 0) { for (let { seid, rand } of jewelBData.rareSe) { let dicRandomEffectPool = gameData.randomEffectPool.get(seid); if (!dicRandomEffectPool) continue; if (!dicRandomEffectPool.Max) dicRandomEffectPool = gameData.randomEffectPool.get(1); if (!dicRandomEffectPool || (dicRandomEffectPool?.Max || 0) == 0) continue; valB += rand / (dicRandomEffectPool.Max); } } } if (dicJewelALv != dicJewelBLv) { return dicJewelBLv - dicJewelALv; } else if (valA != valB) { return valB - valA; } else { return b.ce - a.ce; } }); return heroes; } export function sortByEquipStone(heroes: HeroType[], id: number, extendValue: number) { heroes.sort((a, b) => { const stoneA = a.ePlace.find(obj => obj.id == id)?.stones || []; const stoneIdA = stoneA.find(obj => obj.id == extendValue)?.stone || 0; const valA = gameData.stone.get(stoneIdA)?.lv || 0; const stoneB = b.ePlace.find(obj => obj.id == id)?.stones || []; const stoneIdB = stoneB.find(obj => obj.id == extendValue)?.stone || 0; const valB = gameData.stone.get(stoneIdB)?.lv || 0; if (valA != valB) { return valB - valA; } else { return b.ce - a.ce; } }); return heroes; } export async function getResonanceDataMap(roleId: string) { let dbResonance = await ResonanceModel.findByRoleId(roleId); let dbResonanceMap = new Map(); let newPositionArr: ReturnResonanceParam[] = [], posHids: number[] = []; for (let obj of dbResonance) { if (obj.hid) { dbResonanceMap.set(obj.hid, obj); posHids.push(obj.hid); } else newPositionArr.push({ position: obj.position }); } return { dbResonanceMap, newPositionArr, posHids }; } export async function getJewelDataMap(heroes: HeroType[]) { let dbJewelMap = new Map(); let seqIds = []; for (let hero of heroes) { const { ePlace } = hero; if (!ePlace || ePlace.length == 0) continue; for (let { jewel } of ePlace) { if (jewel == 0) continue; seqIds.push(jewel); } } if (seqIds.length > 0) { let dbJewels = await JewelModel.findbySeqIds(seqIds); if (dbJewels.length > 0) { for (let obj of dbJewels) { dbJewelMap.set(obj.seqId, obj); } } } return dbJewelMap; } export function getInitEplace(id: number, skinId: number) { const dicHero = gameData.hero.get(skinId) const dicEquip = getEquipByJobClassAndEPlace(dicHero?.jobClass, id); return new EPlace(id, dicEquip.id); }