Files
ZYZ/game-server/app/services/role/resonanceService.ts

452 lines
18 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 { 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<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) => {
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<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 (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);
}