Files
ZYZ/game-server/app/services/role/resonanceService.ts
2023-10-13 22:28:46 +08:00

538 lines
23 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 { getNewJob, 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 resonanceDatas: ReturnResonanceParam[] = [];
let resonanceLv = {}, resonanceJob = {}, resonanceCon = [], resonanceEquip = [], resonanceEpQuality = [], resonanceEpStar = [], resonanceJewel = [], resonanceStone = [];
let dbHeroes: HeroType[] = await HeroModel.findByRole(roleId, [{ field: 'ce', sortBy: -1 }]);
let role = await RoleModel.findByRoleId(roleId);
let topLineHeroes: HeroType[] = [];
for (let top of role.topLineup) {
topLineHeroes.push(dbHeroes.find(cur => cur.hid == top.hid));
}
if (topLineHeroes.length < LINEUP_NUM || dbHeroes.length < LINEUP_NUM) return { resonanceDatas };
let { dbResonanceMap, newPositionArr } = await getResonanceDataMap(roleId);
for (let position of newPositionArr) {
resonanceDatas.push({ position });
}
// if (dbResonanceMap.size == 0) return { resonanceDatas };
let dbJewelMap = await getJewelDataMap(dbHeroes);
// 武将等级
let topLineHero: HeroType = sortData(dbResonanceMap, 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(dbResonanceMap, 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(dbResonanceMap, 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);
console.log('x-x-x-x-x- hid', hid)
console.log('x-x-x-x-x- dicShipId', dicShipId)
console.log('x-x-x-x-x- shipData?.shipId', shipData?.shipId)
console.log('x-x-x-x-x- shipData?.level', shipData?.level)
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(dbResonanceMap, 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({ ...await getInitEplace(id, hero.skinId) });
ePlaceData = hero.ePlace.find(cur => cur.id == id);
}
ePlaceData.lv = topLineHeroEplace.lv;
}
//装备升品
topLineHero = sortData(dbResonanceMap, 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({ ...await getInitEplace(id, hero.skinId) });
ePlaceData = hero.ePlace.find(cur => cur.id == id);
};
ePlaceData.quality = topLineHeroEplace.quality;
ePlaceData.qualityStage = topLineHeroEplace.qualityStage;
}
//装备精练
topLineHero = sortData(dbResonanceMap, 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({ ...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, 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({ ...await 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(dbResonanceMap, 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({ ...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);
updateHeroes.push({ ...pick(hero, ['roleId', 'hid', 'lv', 'exp', 'job', 'jobStage', 'connections', 'skins', 'jobStage', 'ePlace']) })
newHeroes.push(hero);
newHeroIds.push(hid);
}
await HeroModel.bulkWriteUpdate(updateHeroes)
// 重新计算战力
if (newHeroes.length > 0) {
let artifacts = await ArtifactModel.findbyHids(roleId, newHeroIds);
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);
if (!dbResonanceMap.has(hid)) continue;
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(dbResonanceMap: Map<number, ResonanceType>, heroes: HeroType[], sortType: number, findType?: number, jewelMap?: Map<number, JewelType>, 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);
// if (findType == 3) {
// console.log('-x-x--x-x-x-x-x-x-x-x-x- topLineHeroes', util.inspect(heroes, { depth: null }));
// }
break;
}
case RESONANCE_SORT_TYPE.STONE:
{
heroes = sortByEquipStone(heroes, findType, extendValue);
break;
}
}
let topLineHeroes: HeroType[] = heroes;
// for (let hero of heroes) {
// const { hid } = hero;
// if (!dbResonanceMap.has(hid) && topLineHeroes.length < LINEUP_NUM) {
// topLineHeroes.push(hero);
// }
// }
// 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<number, JewelType>) {
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 (eplaceId == 3) {
// console.log('-------------------------------------------------------------------');
// console.log('--------------------------------hid', a.hid);
// console.log('--------------------------------dicJewelALv', dicJewelALv);
// console.log('--------------------------------valA', valA);
// console.log('--------------------------------ceA', a.ce);
// console.log('-------------------------------------------------------------------');
// console.log('--------------------------------hid', b.hid);
// console.log('--------------------------------dicJewelBLv', dicJewelBLv);
// console.log('--------------------------------valB', valB);
// console.log('--------------------------------ceB', b.ce);
// }
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<number, ResonanceType>();
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<number, JewelType>();
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);
}