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, HeroUpdate } 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 { initSkinTalent } from "../roleService"; import { pick } from 'underscore'; import * as util from 'util'; // export async function getStartLimt(roleId: string) { // const role = await RoleModel.findByRoleId(roleId); // if (!role || !role.mainWarId || role.mainWarId < RESONANCE.START_MAIN_WARId) return false; // return true; // } export async function refreshResonanceData(roleId: string, serverId: number, sid: string) { let resonances: ReturnResonanceParam[] = []; let dbHeroes: HeroType[] = await HeroModel.findByRole(roleId, [{ field: 'ce', sortBy: -1 }]); if (dbHeroes.length < LINEUP_NUM) return resonances; let { dbResonanceMap, newPositionArr } = await getResonanceDataMap(roleId); for (let positon of newPositionArr) { resonances.push({ positon }); } if (dbResonanceMap.size == 0) return resonances; let dbJewelMap = await getJewelDataMap(dbHeroes); // 武将等级 let topLineHero: HeroType = sortData(dbResonanceMap, dbHeroes, RESONANCE_SORT_TYPE.LV); for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); hero.lv = topLineHero.lv; hero.exp = topLineHero.exp; } // 职业(职阶、天赋) topLineHero = sortData(dbResonanceMap, dbHeroes, RESONANCE_SORT_TYPE.JOBSTAGE); for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); let preJobStage = hero.jobStage; hero.jobStage = topLineHero.jobStage; if (preJobStage != hero.jobStage) { //天赋树置空 hero.skins = initSkinTalent(hero.skins || []); } } // 羁绊1, 2, 3 for (let index = 1; index <= FRIENDSHIP_INDEX.THREE; index++) { topLineHero = sortData(dbResonanceMap, dbHeroes, RESONANCE_SORT_TYPE.CONNECT, index); for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); const topDicShipId = gameData.friendShipByIndex.get(`${topLineHero.hid}_${index}`); const topShipData = topLineHero.connections.find(cur => cur.shipId == topDicShipId); if (!topShipData) continue; const dicShipId = gameData.friendShipByIndex.get(`${hero.hid}_${index}`) let shipData = hero.connections.find(cur => cur.shipId == dicShipId); if (!shipData) hero.connections.push({ shipId: dicShipId, level: topShipData.level, exp: topShipData.exp }); else { shipData.exp = topShipData.exp; shipData.level = topShipData.level; } } } // 装备 1武器,2衣甲,3帽子,4鞋子 for (let id = 1; id <= EQUIP_EPLACEID.SHOE_ID; id++) { //装备强化 topLineHero = sortData(dbResonanceMap, dbHeroes, RESONANCE_SORT_TYPE.EQUIP_LV, id); for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); const topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); if (!topLineHeroEplace || !topLineHeroEplace.lv) continue; let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...await getInitEplace(id, hero.skinId) }); ePlaceData = hero.ePlace.find(cur => cur.id == id); } ePlaceData.lv = topLineHeroEplace.lv; } //装备升品 topLineHero = sortData(dbResonanceMap, dbHeroes, RESONANCE_SORT_TYPE.EQUIP_QUALITY, id); for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); const topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); if (!topLineHeroEplace || !topLineHeroEplace.quality) continue; let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...await getInitEplace(id, hero.skinId) }); ePlaceData = hero.ePlace.find(cur => cur.id == id); }; ePlaceData.quality = topLineHeroEplace.quality; ePlaceData.qualityStage = topLineHeroEplace.qualityStage; } //装备精练 topLineHero = sortData(dbResonanceMap, dbHeroes, RESONANCE_SORT_TYPE.EQUIP_STAR, id); for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); const topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); if (!topLineHeroEplace || !topLineHeroEplace.star) continue; let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...await 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(dbResonanceMap, dbHeroes, RESONANCE_SORT_TYPE.JEWEL, id, dbJewelMap); //破,御,护,命 for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); const topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); if (!topLineHeroEplace || !topLineHeroEplace.jewel) continue; let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...await getInitEplace(id, hero.skinId) }); ePlaceData = hero.ePlace.find(cur => cur.id == id); }; ePlaceData.jewel = topLineHeroEplace.jewel; } } //地玉 if (RESONANCE.STONE) { //破,御,护,命 1,2,3 for (let index = 1; index <= EQUIP_STONE.THREE; index++) { topLineHero = sortData(dbResonanceMap, dbHeroes, RESONANCE_SORT_TYPE.STONE, id, null, index); for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); const topLineHeroEplace = topLineHero.ePlace.find(cur => cur.id == id); if (!topLineHeroEplace || !topLineHeroEplace.stones) continue; const topLineHeroStone = topLineHeroEplace.stones.find(cur => cur.id == index); if (!topLineHeroStone || !topLineHeroStone.stone) continue; let ePlaceData = hero.ePlace.find(cur => cur.id == id); if (!ePlaceData) { hero.ePlace.push({ ...await getInitEplace(id, hero.skinId) }); ePlaceData = hero.ePlace.find(cur => cur.id == id); }; ePlaceData.stones.find(cur => cur.id == index).stone = topLineHeroStone.stone; } } } } let updateHeroes: HeroUpdate[] = [], newHeroes: HeroType[] = [], newHeroIds: number[] = []; for (let [hid] of dbResonanceMap) { let hero = dbHeroes.find(cur => cur.hid == hid); // console.log('-x-x--x-x-x-x-x-x-x-x-x-55 hero', util.inspect(hero, { depth: null })); updateHeroes.push({ ...pick(hero, ['roleId', 'hid', 'lv', 'exp', 'jobStage', 'connections', 'skins', 'jobStage', 'ePlace']) }) newHeroes.push(hero); newHeroIds.push(hid); } await HeroModel.bulkWriteUpdate(updateHeroes) // 重新计算战力 let artifacts = await ArtifactModel.findbyHids(roleId, newHeroIds); let { heroes } = await calculateCeWithHeroes(HERO_SYSTEM_TYPE.REBORN_CAL, roleId, serverId, sid, newHeroes, { jewels: [...dbJewelMap.values()], heroes: newHeroes, artifacts }); for (let hero of (heroes || [])) { const { hid } = hero; const heroResult = new HeroParam(hero); if (!dbResonanceMap.has(hid)) continue; resonances.push({ positon: dbResonanceMap.get(hid).position, ...pick(heroResult, ['hid', 'seqId', 'lv', 'exp', 'jobStage', 'talent', 'usedTalentPoint', 'totalTalentPoint', 'connections', 'ePlace', 'ce']) }); } return resonances; } export function sortData(dbResonanceMap: Map, 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) => { 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[] = []; for (let hero of heroes) { const { hid } = hero; if (!dbResonanceMap.has(hid) && topLineHeroes.length < LINEUP_NUM) { topLineHeroes.push(hero); } } return topLineHeroes[1 - 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: number[] = []; for (let obj of dbResonance) { if (obj.hid) dbResonanceMap.set(obj.hid, obj); else newPositionArr.push(obj.position); } return { dbResonanceMap, newPositionArr }; } 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 async function getInitEplace(id: number, skinId: number) { const dicHero = gameData.hero.get(skinId) const dicEquip = getEquipByJobClassAndEPlace(dicHero?.jobClass, id); return new EPlace(id, dicEquip.id); }