Files
ZYZ/shared/pubUtils/playerCe.ts
2021-08-14 17:57:46 +08:00

1128 lines
42 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 { HERO_SYSTEM_TYPE, ABI_TYPE, HERO_CE_RATIO, HERO_SUB_ATTR_RATIO, LINEUP_NUM } from '../consts';
import { cal, deepCopy, getAllAttrStage, reduceCe } from './util';
import { HeroModel, HeroType, HeroUpdate } from '../db/Hero';
import { RoleModel, RoleType, RoleUpdate } from '../db/Role';
import { CeAttrData, CeAttrDataRole, AttributeCal } from '../domain/roleField/attribute';
import { ABI_STAGE, SEID_TYPE } from '../consts';
import { gameData, getJobByGradeAndClass, getHeroWakeByQuality, getHeroStarByQuality, getFriendShipById, getSchoolRateByStar, getScollByStar, getTeraph, getDicSuitByTypeAndLv } from './data';
import { DicSe } from './dictionary/DicSe';
import { EquipType } from '../db/Equip';
import { DicRandomEffectPool } from './dictionary/DicRandomEffectPool';
import { SchoolModel } from '../db/School';
import { ABI_TYPE_TO_STAGE, ABI_TYPE_MAIN, ABI_JOB_STAGE } from '../consts/constModules/abilityConst'
import { PvpDefenseModel } from '../db/PvpDefense';
import { findIndex } from 'underscore';
import { GuildModel } from '../db/Guild';
import { DicJob } from './dictionary/DicJob';
import { DicSuit } from './dictionary/DicSuit';
// 修改并下发战力
export async function calPlayerCeAndSave(type: number, roleId: string, originHero: HeroType, update: HeroUpdate, args?: Array<number>) {
let role = await RoleModel.findByRoleId(roleId);
let { attr: roleAttrs = [], serverId } = role;
let heroAttrs = calPlayerCe(originHero, update, type, args); // 根据操作计算attr的增加
let newAttr = new AttributeCal();
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, 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),
});
return { pushHeros, role, topLineupCe, hero, guild, serverId }
}
//全局属性加成
export async function reCalAllHeroCe(type: number, roleId: string, update: RoleUpdate, args?: Array<number>) {
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 roleCe = 0; // 总战力加成
let allIncCe = 0;
for (let hero of heros) {
let { attr: heroAttrs } = hero;
let newAttr = new AttributeCal();
newAttr.setByDbData(roleAttrs, heroAttrs);
let heroCe = newAttr.calCe(); // 计算最终战力
let incHeroCe = heroCe - hero.ce;
allIncCe += incHeroCe;
roleCe += heroCe;
pushHeros.push({ hid: hero.hid, ce: reduceCe(hero.ce), incHeroCe: reduceCe(incHeroCe) });
await HeroModel.updateHeroInfo(roleId, hero.hid, { ce: heroCe });
await PvpDefenseModel.updateCe(roleId, hero.hid, incHeroCe); // 更新pvp防守阵战力
}
let { topLineup, topLineupCe } = await calculatetopLineup(role); // 计算更新最强五人战力
update.attr = roleAttrs;
update.ce = roleCe;
update.topLineup = topLineup;
update.topLineupCe = topLineupCe;
role = await RoleModel.updateRoleInfo(roleId, update);
let guild = await GuildModel.updateCe(roleId, allIncCe); // 公会更新战力
return { role, pushHeros, ce: role.ce, topLineupCe: role.topLineupCe, guild, serverId: role.serverId, heros }
}
// 计算武将全局战力
async function reCalRoleAttr(type: number, heros: Array<HeroType>, role: RoleType, update: RoleUpdate, args: Array<number>) {
let { attr: roleAttrs } = role;
switch (type) {
case HERO_SYSTEM_TYPE.INIT:
roleAttrs = calRoleInit(role);
break;
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 function calPlayerCe(hero: HeroType, update: HeroUpdate, type: number, args: Array<number> = []) {
let heroAttrs: CeAttrData[] = []; // {"hp": {"base": number, "fixUp": number, "ratioUp": number}}
let addSeidList = new Array<number>();
let removeSeidList = new Array<number>();
switch (type) {
case HERO_SYSTEM_TYPE.INIT:
heroAttrs = calHeroInitIncAttr(hero, addSeidList, removeSeidList); // args: 升的星盘
break;
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, args[0], args[1], 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.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 {HeroType} hero 武将数据
* @param {number[]} addSeidList 用于更新被动
* @param {number[]} removeSeidList 用于更新被动
*/
export function calHeroInitIncAttr(hero: HeroType, addSeidList: Array<number>, removeSeidList: Array<number>) {
// try{
delete hero._id;
let heroAttrs = calHeroStarIncAttr(hero, hero, HERO_SYSTEM_TYPE.INIT, addSeidList, removeSeidList);
heroAttrs = calHeroWearSkinIncAttr(hero, gameData.hero.get(hero.hid)?.initialSkin||0, 0, addSeidList, removeSeidList, true);
heroAttrs = calHeroJobAttr(hero, hero, addSeidList, removeSeidList);
return heroAttrs;
// }catch(e) {
// console.error(e);
// return [];
// }
}
/**
* 初始全局加成
* @param args
* @param ceAttr
*/
function calRoleInit(role: RoleType) {
let { attr: roleAttrs, teraphs } = role;
delete role._id;
roleAttrs = calTitle({...role, title: 0}, role); // 计算初始爵位带来的全局
for(let {id} of teraphs) {
roleAttrs = calTeraphMainAttr({ ...role, teraphs: [] }, role, id);
}
role.attr = roleAttrs;
return roleAttrs;
}
/**
* 添加皮肤全局加成
* @param args
* @param ceAttr
*/
function calHeroAddSkin(role: RoleType, skinIds: Array<number>) {
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<number>, removeSeidList: Array<number>) {
let isInit = type == HERO_SYSTEM_TYPE.INIT;
let { hid, star: originStar, starStage: originStarStage, quality: originQuality, colorStar: originColorStar, colorStarStage: originColorStarStage, attr: heroAttrs, skins, lv: oldLv } = originHero;
let { star = originStar, starStage = originStarStage, quality = originQuality, colorStar = originColorStar, colorStarStage = originColorStarStage, lv = oldLv } = update;
const dicHero = gameData.hero.get(hid);
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 dicJob = gameData.job.get(dicHero.jobid);
const dicStar = isWake ? getHeroWakeByQuality(dicJob.job_class, dicHero.quality, colorStar) : getHeroStarByQuality(dicJob.job_class, quality, star); // 星级表
let stages = new Array<number>(); // 需要升级的阶
if (type == HERO_SYSTEM_TYPE.INIT) {
stages = getAllAttrStage();
} else 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);
}
}
}
}
for (let stage of stages) {
let targetAttrId = ABI_TYPE_TO_STAGE.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 - 1) * (heroUpAttr + starUp)) * HERO_CE_RATIO;
updateHeroAttr(heroAttrs, targetAttrId, { set: { base: newBase } });
}
// 武将被动技能,初始时候还没有皮肤,就先不算被动
if(skins.length > 0) {
let curSkin = skins.find(cur => cur.enable);
let curSeidList = getSeidListOfFashion(curSkin.id, star, colorStar);
let preSeidList = getSeidListOfFashion(curSkin.id, isInit ? 0 : originStar, isInit ? 0 : 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<CeAttrData>;
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<CeAttrDataRole>;
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 fashionid
* @param originStar
* @param originColorStar
*/
function getSeidListOfFashion(fashionid: number, originStar: number, originColorStar: number) {
let seidList = new Map<number, number>(); // type => seid
if (!gameData.fashion.has(fashionid)) return seidList;
let { skillId } = gameData.fashion.get(fashionid);
let { starSeidArr, colorStarSeidArr } = gameData.heroSkill.get(skillId);
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<number>, removeSeidList: Array<number>) {
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<number>();
let curSeids = currentJob?.seid||new Array<number>();
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<number>, removeSeidList: Array<number>) {
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, wearSkinId: number, pullSkinId: number, addSeidList: number[], removeSeidList: number[], isInit: boolean = false) {
let { attr: heroAttrs } = originHero;
let addSkin = gameData.fashion.get(wearSkinId);
let delSkin = gameData.fashion.get(pullSkinId);
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 } });
}
if (!isInit) { // 初始的时候这一段技能在calHeroStarIncAttr里计算了不用重复算
let { star, colorStar } = originHero;
let curSeidList = getSeidListOfFashion(wearSkinId, star, colorStar);
let preSeidList = getSeidListOfFashion(pullSkinId, star, colorStar);
curSeidList.forEach((seid, type) => {
if (!preSeidList.has(type)) {
removeSeidList.push(seid, 0);
}
});
preSeidList.forEach((seid, type) => {
if (!curSeidList.has(type)) {
addSeidList.push(seid, 0);
}
});
}
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;
}
/**
* 穿脱, removeSeidList原来身上穿着的所有装备的seid包括套装的
* @param {HeroType} hero 武将
* @param {number[]} seids args 原来穿着的装备的seid
* @param {number[]} addSeidList 用于更新被动
* @param {number[]} removeSeidList 用于更新被动
*/
export function calEquipPutOnOffIncAttr(hero: HeroType, seids: Array<number>, addSeidList: Array<number>, removeSeidList: Array<number>) {
// 计算身上所有装备的战力值(特技相关以外)
let heroAttrs = calHeroEquipIncAttr(hero);
// 计算被动技能
let resultSeid = calEquipSeids(hero);
for(let seid of resultSeid) {
addSeidList.push(seid);
}
for (let seid of seids) {
removeSeidList.push(seid)
}
return heroAttrs
}
/**
* 计算一个武将身上的所有被动seid
* @param {HeroType} hero 武将equip需要populate
*/
export function calEquipSeids(hero: HeroType) {
let seids: number[] = [];
// 计算被动技能
let { ePlace } = hero;
let suits = new Map<number, Map<number, { dic: DicSuit, count: number }>>(); // suitType => starLevel => DicSuit
for (let { equip } of ePlace) {
if (equip) {
let e = <EquipType>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<number, { dic: DicSuit, count: number }>());
}
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<number, { starLevel: number, seid: number }>(); // 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 { ePlace, attr: heroAttrs } = hero;
let setMap = new Map<number, number>();
for (let { equip, lv, refineLv } of ePlace) {
if (equip) {
let e = <EquipType>equip;
let dicGoods = gameData.goods.get(e.id);
let { goodsAbility, goodsAbilityUp } = dicGoods;
let dicRefine = gameData.refine.get(refineLv);
let jewel = new Map<number, number>();
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<number, number>();
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<number>, addSeidList: Array<number>, removeSeidList: Array<number>) {
let { attr: heroAttrs } = hero;
let { ePlace } = hero;
let curPlace = ePlace.find(cur => cur.id == ePaceId);
if (curPlace && curPlace.equip) {
let e = <EquipType>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<number>, removeSeidList: Array<number>) {
// 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<DicSe>(); // 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.TYPE102) { // 加百分比
if(ABI_TYPE_MAIN.includes(ability)) {
updateHeroAttr(heroAttrs, ability, { inc: {ratioUp: value * multi} });
} else { // 次级属性102特殊处理
updateHeroAttr(heroAttrs, ability, { inc: {fixUp: value * multi * HERO_SUB_ATTR_RATIO } });
}
}
}
}
}
// 获取dic_zyz_se内容
function addSeid(effectList: Array<any>, seidId: number, rand: number, seidValue = new Array<number>()) {
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);
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<number, number>() };
let { goodsAbility: oldGoodsAbility } = gameData.goods.get(oldId)||{ goodsAbility: new Map<number, number>() };
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--;
} 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;
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;
let heroScroll = getScollByStar(quality, star, curQuality, colorStar);
if (!heroScroll) return roleAttrs;
let preScroll = gameData.preHeroScroll.get(heroScroll.id);
heroScroll.ceAttr.forEach((add, id) => {
let attrId = ABI_TYPE_TO_STAGE.get(id);
let preAdd = preScroll ? preScroll.ceAttr.get(id) : 0;
let fixUp = (add - preAdd) * HERO_CE_RATIO;
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);
console.log('***** oldTitle, newTitle', oldTitle, newTitle);
for (let i = ABI_TYPE.ABI_HP; i < ABI_TYPE.ABI_MAX; i++) {
if (dicNewTitle.mainAttrValue.has(i) || dicOldTitle.mainAttrValue.has(i)) {
console.log()
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 ratioUp = val - oldVal;
updateRoleAttr(roleAttrs, attrId, { inc: { ratioUp } });
});
return roleAttrs;
}