928 lines
36 KiB
TypeScript
928 lines
36 KiB
TypeScript
/**
|
||
* 体力系统
|
||
*/
|
||
|
||
import { HERO_SYSTEM_TYPE, ABI_TYPE, JEWEL_ATTR } from '../consts';
|
||
|
||
import { deepCopy, getAllAttrStage, reduceCe } from './util';
|
||
import { HeroModel, HeroType } from '../db/Hero';
|
||
import { RoleModel, RoleType } from '../db/Role';
|
||
import { CeAttrData, CeAttr, CeAttrRole, CeAttrNumber, CeAttrDataRole } from '../domain/roleField/attribute';
|
||
import { getAttrNameByJobStage, getAttrCeRatio, getAtrrNameById, ABI_STAGE, SEID_TYPE } from '../consts';
|
||
import { gameData, getJobByGradeAndClass, getHeroWakeByQuality, getHeroStarByQuality, getFriendShipById, getSchoolRateByStar, getScollByStar, getFieldByStage } from './data';
|
||
import { DicSe } from './dictionary/DicSe';
|
||
import { EquipType } from '../db/Equip';
|
||
import { DicRandomEffectPool } from './dictionary/DicRandomEffectPool';
|
||
import { getGoodById } from './gamedata';
|
||
import { SchoolModel } from '../db/School';
|
||
import { getTeraphAttr, HEROTARIN } from '../consts/constModules/abilityConst'
|
||
import { PvpDefenseModel } from '../db/PvpDefense';
|
||
const HERO_CE_RATIO = 100;
|
||
import { findIndex } from 'underscore';
|
||
import { GuildModel } from '../db/Guild';
|
||
|
||
//战力计算TODO
|
||
export function calPlayerCe(globalCeAttr: CeAttrRole, hero: HeroType, type: number, args: Array<number> = []) {
|
||
let heroCe = 0;
|
||
let reIncAttr: CeAttr = {}; // {"hp": {"base": number, "fixUp": number, "ratioUp": number}}
|
||
|
||
let addSeidList = new Array<number>();
|
||
let removeSeidList = new Array<number>();
|
||
|
||
switch (type) {
|
||
case HERO_SYSTEM_TYPE.INIT:
|
||
reIncAttr = 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:
|
||
reIncAttr = calHeroStarIncAttr(hero, type, args.shift(), args, addSeidList, removeSeidList); // args: 升的星盘
|
||
break;
|
||
case HERO_SYSTEM_TYPE.TRAIN:
|
||
reIncAttr = calHeroTrainIncAttr(hero);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.STAGEUP:
|
||
reIncAttr = calHeroJobStageUpIncAttr(hero, args, addSeidList, removeSeidList);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.SKIN:
|
||
reIncAttr = calHeroWearSkinIncAttr(hero, args, addSeidList, removeSeidList);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.FAVOUR:
|
||
reIncAttr = calHeroFavourUpIncAttr(hero, args);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.CONNECT:
|
||
reIncAttr = calHeroConectIncAttr(hero, args);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.EQUIP:
|
||
reIncAttr = calEquipPutOnOffIncAttr(hero, args, addSeidList, removeSeidList);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.EQUIP_BASE:
|
||
reIncAttr = calHeroEquipIncAttr(hero);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.RESTRENGTHEN:
|
||
reIncAttr = calRestrengthenIncAttr(hero, args.shift(), args, addSeidList, removeSeidList);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.JEWEL_ON:
|
||
reIncAttr = calHeroCeWhenJewelOn(hero, args);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.JEWEL_OFF:
|
||
reIncAttr = calHeroCeWhenJewelOff(hero, args);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.SCROLL:
|
||
reIncAttr = calHeroCeScrollIncAttr(hero, args[0], args[1]);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
addSeidEffect(reIncAttr, hero.ceAttr, addSeidList, removeSeidList); // 处理加值
|
||
if (!hero.ceAttr) hero.ceAttr = new CeAttr();
|
||
for (let attrName in hero.ceAttr) {
|
||
if (attrName == '_id') continue;
|
||
let globalAttrData: CeAttrDataRole = globalCeAttr[attrName] || new CeAttrDataRole();
|
||
if (!hero.ceAttr[attrName]) hero.ceAttr[attrName] = new CeAttrData();
|
||
if (!!reIncAttr[attrName]) {
|
||
for (let attrKey in reIncAttr[attrName]) {
|
||
hero.ceAttr[attrName][attrKey] = parseInt(reIncAttr[attrName][attrKey] || 0);
|
||
}
|
||
}
|
||
let attrNumber = (hero.ceAttr[attrName].fixUp + (hero.ceAttr[attrName].equipUp || 0) + globalAttrData.fixUp) * HERO_CE_RATIO + hero.ceAttr[attrName].base * (HERO_CE_RATIO + hero.ceAttr[attrName].ratioUp + globalAttrData.ratioUp);
|
||
// console.log(hero.hid, attrNumber, attrName, getAttrCeRatio(attrName))
|
||
heroCe += attrNumber * getAttrCeRatio(attrName);
|
||
}
|
||
let incCe = heroCe - hero.ce;
|
||
hero.ce = heroCe > 0 ? heroCe : 1;
|
||
if (hero.historyCe < hero.ce) hero.historyCe = hero.ce;
|
||
return incCe;
|
||
}
|
||
|
||
//修改并下发战力
|
||
export async function calPlayerCeAndSave(roleId: string, heros: Array<HeroType>, type?: number, args?: Array<number>) {
|
||
if (!heros.length) heros = await HeroModel.findByRole(roleId);
|
||
let incPlayerCe = 0;
|
||
let pushHeros = new Array<{ hid: number, ce: number, incHeroCe: number }>();
|
||
let role = await RoleModel.findByRoleId(roleId);
|
||
if (!role.globalCeAttr) role.globalCeAttr = new CeAttr();
|
||
await reCalRoleAttr(heros, role.globalCeAttr, type, args);
|
||
for (let hero of heros) {
|
||
let incHeroCe = calPlayerCe(role.globalCeAttr, hero, type, args);
|
||
|
||
incPlayerCe += incHeroCe;
|
||
await calculateTopFive(role, hero.hid, hero.ce, hero._id); // 计算更新最强五人战力
|
||
await HeroModel.updateHeroInfo(roleId, hero.hid, hero);
|
||
await PvpDefenseModel.updateCe(roleId, hero.hid, hero.ce); // 更新pvp防守阵战力
|
||
pushHeros.push({
|
||
hid: hero.hid,
|
||
ce: reduceCe(hero.ce),
|
||
incHeroCe: reduceCe(incHeroCe),
|
||
});
|
||
}
|
||
role.ce += incPlayerCe;
|
||
let { topFive, topFiveCe } = role;
|
||
await RoleModel.updateRoleInfo(roleId, { globalCeAttr: role.globalCeAttr, ce: role.ce, topFive, topFiveCe });
|
||
await GuildModel.updateCe(roleId, incPlayerCe);
|
||
return { pushHeros, role, topFiveCe }
|
||
}
|
||
|
||
export async function calculateTopFive(role: RoleType, hid: number, ce: number, heroId: string) {
|
||
let topFive = role?.topFive || new Array();
|
||
|
||
topFive.sort((a, b) => { return b.ce - a.ce }); // 0-5,最大-最小
|
||
let index = topFive.findIndex(cur => cur.hid == hid);
|
||
if(index != -1 && !heroId) {
|
||
let heroes = await HeroModel.getTopHero(role.roleId, 5);
|
||
topFive = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } });
|
||
} else {
|
||
if (index == -1) { // 不在最强列表
|
||
if (topFive.length < 5) { // 不满5人
|
||
topFive.push({ hid, ce, hero: heroId });
|
||
} else if (topFive.length == 5) {
|
||
if (ce > topFive[topFive.length - 1].ce) { // 跻身最强5人
|
||
topFive.pop();
|
||
topFive.push({ hid, ce, hero: heroId });
|
||
}
|
||
} else {
|
||
topFive.splice(5, topFive.length - 5);
|
||
}
|
||
} else { // 原来就是最强5人
|
||
if (ce < topFive[topFive.length - 1].ce) { // 滑出最强
|
||
let heroes = await HeroModel.getTopHero(role.roleId, 5);
|
||
topFive = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } });
|
||
} else {
|
||
topFive[index].ce = ce;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
let topFiveCe = topFive.reduce((pre, cur) => {
|
||
return pre + cur.ce
|
||
}, 0);
|
||
|
||
role.topFive = topFive;
|
||
role.topFiveCe = topFiveCe;
|
||
return role;
|
||
}
|
||
|
||
// 初始战力
|
||
export function calHeroInitIncAttr(hero: HeroType, addSeidList: Array<number>, removeSeidList: Array<number>) {
|
||
let res = calHeroStarIncAttr(hero, HERO_SYSTEM_TYPE.INIT, hero.hid, [], addSeidList, removeSeidList);
|
||
let curSkin = hero.skins.find(cur => cur.enable);
|
||
calHeroWearSkinIncAttr(hero, [curSkin ? curSkin.id : 0, 0], addSeidList, removeSeidList, true, res);
|
||
calHeroJobAttr(hero, res, addSeidList, removeSeidList);
|
||
return res;
|
||
}
|
||
|
||
export function calRoleInitIncAttr(heros: HeroType[], globalCeAttr: CeAttrRole) {
|
||
let args = new Array<number>();
|
||
for (let hero of heros) {
|
||
for (let skin of hero.skins) {
|
||
args.push(skin.id);
|
||
}
|
||
}
|
||
let res = calHeroAddSkin(args, globalCeAttr);
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param hero HeroType 武将更新后的值
|
||
* @param type number 类型
|
||
* @param hid number 当前武将id
|
||
* @param args number[] 当升星时,一个参数,0-是否升了一星;当觉醒时,两个参数,0-是否升了一星,1-是否初次觉醒
|
||
* @param addSeidList number[] 用于更新被动
|
||
* @param removeSeidList number[] 用于更新被动
|
||
*/
|
||
export function calHeroStarIncAttr(hero: HeroType, type: number, hid: number, args: number[], addSeidList: Array<number>, removeSeidList: Array<number>) {
|
||
let isInit = type == HERO_SYSTEM_TYPE.INIT;
|
||
let { star, starStage, quality, colorStar, colorStarStage, ceAttr, skins } = hero;
|
||
let originStar = star, originColorStar = colorStar;
|
||
|
||
let res: CeAttr = {};
|
||
if (hero.hid != hid) return res;
|
||
|
||
const dicHero = gameData.hero.get(hero.hid);
|
||
|
||
const isWake = colorStar > 0; // 是否觉醒,只要激活了觉醒,彩星就会 > 1
|
||
if (isWake) {
|
||
if (colorStarStage == ABI_STAGE.START) originColorStar = colorStar - 1;
|
||
} else {
|
||
if (starStage == ABI_STAGE.START) originStar = star - 1;
|
||
}
|
||
const dicStar = isWake ? getHeroWakeByQuality(dicHero.quality, originColorStar) : getHeroStarByQuality(quality, originStar); // 星级表
|
||
|
||
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) {
|
||
stages = [args[0] ? ABI_STAGE.END : starStage];
|
||
} else if (type == HERO_SYSTEM_TYPE.QUALITY) {
|
||
stages = getAllAttrStage();
|
||
} else if (type = HERO_SYSTEM_TYPE.COLORSTAR) {
|
||
if (args[1]) { // 首次觉醒
|
||
stages = getAllAttrStage();
|
||
} else {
|
||
stages.push(args[0] ? ABI_STAGE.END : hero.colorStarStage)
|
||
}
|
||
}
|
||
for (let stage of stages) {
|
||
|
||
let targetAttrId = getFieldByStage(stage, hero.job); // 转换为17维的属性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 + (hero.lv - 1) * (heroUpAttr + starUp)) * HERO_CE_RATIO;
|
||
let field = getAtrrNameById(targetAttrId);
|
||
let ceAttrData: CeAttrData = ceAttr[field] || new CeAttrData(); // 存表中的属性下的base,fixup,ratioup
|
||
let { ratioUp = 0, fixUp = 0 } = ceAttrData;
|
||
res[field] = { base: newBase, ratioUp, fixUp }; // base变动,增量为△base * ratio + 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);
|
||
for (let [type, seid] of curSeidList) {
|
||
if (!preSeidList.has(type)) {
|
||
addSeidList.push(seid, 0);
|
||
}
|
||
}
|
||
for (let [type, seid] of preSeidList) {
|
||
if (!curSeidList.has(type)) {
|
||
removeSeidList.push(seid, 0);
|
||
}
|
||
}
|
||
|
||
return res;//属性增量可以是多个
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
//训练
|
||
export function calHeroTrainIncAttr(hero: HeroType) {
|
||
let res: CeAttr = {};
|
||
let attrName: string = getAttrNameByJobStage(hero.jobStage);
|
||
res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp };
|
||
let currentJob = gameData.job.get(hero.job);
|
||
if (currentJob.grade > 1) {
|
||
let jobGradeAndClass = getJobByGradeAndClass(currentJob.job_class, currentJob.grade - 1);
|
||
let lastJob = gameData.job.get(jobGradeAndClass.jobid);
|
||
res[attrName].fixUp += (currentJob[attrName] - lastJob[attrName]) * HERO_CE_RATIO;
|
||
} else {
|
||
res[attrName].fixUp += currentJob[attrName] * HERO_CE_RATIO;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
//进阶
|
||
export function calHeroJobStageUpIncAttr(hero: HeroType, args: Array<number>, addSeidList: Array<number>, removeSeidList: Array<number>) {
|
||
let res: CeAttr = {};
|
||
let lastJob = gameData.job.get(args[0]) || { seid: [] };
|
||
let currentJob = gameData.job.get(hero.job);
|
||
for (let seid of currentJob.seid) {
|
||
let index = findIndex(lastJob.seid, seid);
|
||
if (index < 0) {
|
||
addSeidList.push(seid, 0);
|
||
}
|
||
}
|
||
for (let seid of lastJob.seid) {
|
||
let index = findIndex(currentJob.seid, seid);
|
||
if (index < 0) {
|
||
removeSeidList.push(seid, 0);
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
|
||
export function calHeroJobAttr(hero: HeroType, res: CeAttr, addSeidList: Array<number>, removeSeidList: Array<number>) {
|
||
let currentJob = gameData.job.get(hero.job);
|
||
let jobGradeAndClass = getJobByGradeAndClass(currentJob.job_class, currentJob.grade - 1);
|
||
let lastJob;
|
||
if (!!jobGradeAndClass) {
|
||
lastJob = gameData.job.get(jobGradeAndClass.jobid);
|
||
}
|
||
for (let key in HEROTARIN) {
|
||
let attrName: string = HEROTARIN[key];
|
||
res[attrName] = res[attrName] || { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp };
|
||
if (hero.jobStage >= parseInt(key)) {
|
||
res[attrName].fixUp += currentJob[attrName] * HERO_CE_RATIO;
|
||
} else {
|
||
if (lastJob)
|
||
res[attrName].fixUp += lastJob[attrName] * HERO_CE_RATIO;
|
||
}
|
||
}
|
||
calHeroJobStageUpIncAttr(hero, [0], addSeidList, removeSeidList);
|
||
return res;
|
||
}
|
||
|
||
//穿戴时装
|
||
export function calHeroWearSkinIncAttr(hero: HeroType, args: Array<number>, addSeidList: Array<number>, removeSeidList: Array<number>, isInit = false, heroAttr?: CeAttr) {
|
||
let res: CeAttr = heroAttr || {};
|
||
let addSkin = gameData.fashion.get(args[0]);
|
||
let delSkin = gameData.fashion.get(args[1]);
|
||
let attrName: string;
|
||
if (delSkin) {
|
||
for (let attr of delSkin.actorAttr) {
|
||
attrName = getAtrrNameById(attr.id);
|
||
res[attrName] = res[attrName] || { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp -= attr.number * HERO_CE_RATIO;
|
||
}
|
||
}
|
||
for (let attr of addSkin.actorAttr) {
|
||
attrName = getAtrrNameById(attr.id);
|
||
res[attrName] = res[attrName] || { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp += attr.number * HERO_CE_RATIO;
|
||
}
|
||
|
||
if (!isInit) { // 初始的时候,这一段技能在calHeroStarIncAttr里计算了,不用重复算
|
||
let { star, colorStar } = hero;
|
||
|
||
let curSeidList = getSeidListOfFashion(args[0], star, colorStar);
|
||
let preSeidList = getSeidListOfFashion(args[1], star, colorStar);
|
||
for (let [type, seid] of curSeidList) {
|
||
if (!preSeidList.has(type)) {
|
||
removeSeidList.push(seid, 0);
|
||
}
|
||
}
|
||
for (let [type, seid] of preSeidList) {
|
||
if (!curSeidList.has(type)) {
|
||
addSeidList.push(seid, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
//羁绊解锁
|
||
export function calHeroConectIncAttr(hero: HeroType, args: Array<number>) {
|
||
let res: CeAttr = {};
|
||
let fiendShipLevel = gameData.friendShipLevelMap.get(hero.favourLv);
|
||
let shipId = args[0];//当前升级的羁绊序号
|
||
let level = args[1];//当前升级的羁绊等级
|
||
let attrName: string;
|
||
let currentShip = getFriendShipById(shipId, level);
|
||
for (let attr of currentShip.attributes) {
|
||
attrName = getAtrrNameById(attr.id);
|
||
res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp += attr.number * (HERO_CE_RATIO + fiendShipLevel.add);
|
||
}
|
||
if (level > 1) {
|
||
let lastShip = getFriendShipById(shipId, level - 1);
|
||
for (let attr of lastShip.attributes) {
|
||
attrName = getAtrrNameById(attr.id);
|
||
res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp -= attr.number * (HERO_CE_RATIO + fiendShipLevel.add);
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
//好感升级
|
||
export function calHeroFavourUpIncAttr(hero: HeroType, args: Array<number>) {
|
||
let res: CeAttr = {};
|
||
let currentFiendShipLevel = gameData.friendShipLevelMap.get(hero.favourLv);
|
||
let difAdd = currentFiendShipLevel.add;
|
||
if (!!args[0]) {
|
||
let lastFiendShipLevel = gameData.friendShipLevelMap.get(args[0]);
|
||
difAdd -= lastFiendShipLevel.add;
|
||
}
|
||
let attrName: string;
|
||
for (let connect of hero.connections) {
|
||
let heroShip = getFriendShipById(connect.shipId, connect.level);
|
||
for (let attr of heroShip.attributes) {
|
||
attrName = getAtrrNameById(attr.id);
|
||
res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp += attr.number * (HERO_CE_RATIO + difAdd);
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
// 穿脱, removeSeidList原来身上穿着的所有装备的seid,包括套装的
|
||
export function calEquipPutOnOffIncAttr(hero: HeroType, args: Array<number>, addSeidList: Array<number>, removeSeidList: Array<number>) {
|
||
// 计算身上所有装备的战力值(特技相关以外)
|
||
let res = calHeroEquipIncAttr(hero);
|
||
|
||
// 计算被动技能
|
||
let { ePlace } = hero;
|
||
let suits = new Map<number, number>();
|
||
|
||
for (let { equip } of ePlace) {
|
||
if (equip) {
|
||
let e = <EquipType>equip;
|
||
for (let { seid, rand } of e.randSe) {
|
||
addSeidList.push(seid, rand);
|
||
}
|
||
if (e.suitId > 0) {
|
||
if (suits.has(e.suitId)) {
|
||
suits.set(e.suitId, suits.get(e.suitId) + 1);
|
||
} else {
|
||
suits.set(e.suitId, 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
suits.forEach((suitId, count) => {
|
||
let { effect } = gameData.suit.get(suitId);
|
||
for (let e of effect) {
|
||
if (count >= e.count) {
|
||
addSeidList.push(e.seid, 0);
|
||
}
|
||
}
|
||
});
|
||
|
||
for (let arg of args) {
|
||
removeSeidList.push(arg)
|
||
}
|
||
|
||
return res
|
||
}
|
||
|
||
export function calEquipSeids(hero: HeroType) {
|
||
let seids = [];
|
||
// 计算被动技能
|
||
let { ePlace } = hero;
|
||
let suits = new Map<number, number>();
|
||
|
||
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) {
|
||
if (suits.has(e.suitId)) {
|
||
suits.set(e.suitId, suits.get(e.suitId) + 1);
|
||
} else {
|
||
suits.set(e.suitId, 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
suits.forEach((suitId, count) => {
|
||
let { effect } = gameData.suit.get(suitId);
|
||
for (let e of effect) {
|
||
if (count >= e.count) {
|
||
seids.push(e.seid, 0);
|
||
}
|
||
}
|
||
});
|
||
return seids;
|
||
}
|
||
|
||
// 装备,装备栏升级,装备精炼等涉及到值的
|
||
export function calHeroEquipIncAttr(hero: HeroType) {
|
||
let res: CeAttr = {};
|
||
let { ePlace } = hero;
|
||
|
||
let attrResult = new CeAttrNumber();
|
||
|
||
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);
|
||
}
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
for (let i = ABI_TYPE.ABI_HP; i < ABI_TYPE.ABI_MAX; i++) {
|
||
if (i == ABI_TYPE.ABI_SPEED || i == ABI_TYPE.ABI_AP) continue;
|
||
let attrName = getAtrrNameById(i);
|
||
// console.log('***', i, attrName);
|
||
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('refine', dicRefine?dicRefine.upPercent:0 );
|
||
let valueJewel = jewel.get(i) || 0;
|
||
// console.log('jewel', valueJewel);
|
||
let attr = (value1 + lv * valueup) * (HERO_CE_RATIO + valueRefine) + valueJewel * HERO_CE_RATIO;
|
||
|
||
attrResult[attrName] += attr;
|
||
}
|
||
}
|
||
}
|
||
|
||
for (let attrName in attrResult) {
|
||
let originalCe = hero.ceAttr[attrName].equipUp || 0;
|
||
console.log('装备战力:', attrName, attrResult[attrName], originalCe);
|
||
res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp, equipUp: originalCe };
|
||
res[attrName].equipUp += attrResult[attrName] - originalCe;
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
// 洗炼
|
||
export function calRestrengthenIncAttr(hero: HeroType, ePaceId: number, args: Array<number>, addSeidList: Array<number>, removeSeidList: Array<number>) {
|
||
|
||
let res: CeAttr = {};
|
||
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 arg of args) { removeSeidList.push(arg) }
|
||
|
||
return res
|
||
}
|
||
|
||
// 添加技能增加的被动属性
|
||
function addSeidEffect(reIncAttr: CeAttr, heroCeAttr: CeAttr, addSeidList: Array<number>, removeSeidList: Array<number>) {
|
||
|
||
console.log('addSeidList', addSeidList)
|
||
console.log('removeSeidList', removeSeidList)
|
||
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)
|
||
}
|
||
}
|
||
|
||
for (let { type, gainValueArr: [ability, value] } of effectList) {
|
||
let attrName = getAtrrNameById(ability);
|
||
if (!attrName) continue;
|
||
if (type == SEID_TYPE.TYPE101) { // 加值
|
||
if (!reIncAttr[attrName]) {
|
||
reIncAttr[attrName] = deepCopy(heroCeAttr[attrName]);
|
||
}
|
||
if (!reIncAttr[attrName]) {
|
||
delete reIncAttr[attrName];
|
||
continue;
|
||
}
|
||
reIncAttr[attrName].fixUp += value * multi * HERO_CE_RATIO;
|
||
delete reIncAttr[attrName]._id;
|
||
} else if (type == SEID_TYPE.TYPE102) { // 加百分比
|
||
if (!reIncAttr[attrName]) {
|
||
reIncAttr[attrName] = deepCopy(heroCeAttr[attrName]);
|
||
}
|
||
if (!reIncAttr[attrName]) {
|
||
delete reIncAttr[attrName];
|
||
continue;
|
||
}
|
||
reIncAttr[attrName].ratioUp += value * multi;
|
||
delete reIncAttr[attrName]._id;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
// 获取dic_zyz_se内容
|
||
function addSeid(effectList: Array<any>, seidId: number, rand: number, seidValue = new Array<number>()) {
|
||
// console.log('addSeidEffect', seidId, seidValue)
|
||
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);
|
||
}
|
||
|
||
function calHeroCeWhenJewelOn(hero: HeroType, args: Array<number>) {
|
||
let res: CeAttr = {};
|
||
let id = args[0];
|
||
let oldId = args[1];
|
||
let goodInfo = getGoodById(id);
|
||
let oldGoodInfo;
|
||
if (!!oldId)
|
||
oldGoodInfo = getGoodById(oldId);
|
||
for (let attrName in JEWEL_ATTR) {
|
||
if (!!goodInfo[attrName]) {
|
||
res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp += goodInfo[attrName];
|
||
if (oldGoodInfo)
|
||
res[attrName].fixUp -= oldGoodInfo[attrName];
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
function calHeroCeWhenJewelOff(hero: HeroType, args: Array<number>) {
|
||
let res: CeAttr = {};
|
||
for (let id of args) {
|
||
let goodInfo = getGoodById(id);
|
||
for (let attrName in JEWEL_ATTR) {
|
||
if (!!goodInfo[attrName]) {
|
||
res[attrName] = { fixUp: hero.ceAttr[attrName].fixUp, base: hero.ceAttr[attrName].base, ratioUp: hero.ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp -= goodInfo[attrName];
|
||
}
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
//全局属性加成
|
||
export async function reCalAllHeroCe(roleId: string, type: number, args: Array<number>) {
|
||
let role = await RoleModel.findByRoleId(roleId);
|
||
if (!role.globalCeAttr) role.globalCeAttr = new CeAttr();
|
||
let pushHeros: Array<{ hid: number, ce: number, incHeroCe: number }> = []
|
||
let heros = await HeroModel.findByRole(roleId);
|
||
await reCalRoleAttr(heros, role.globalCeAttr, type, args);
|
||
role.ce = 0;
|
||
for (let hero of heros) {
|
||
let heroCe = 0;
|
||
for (let attrName in role.globalCeAttr) {
|
||
if (attrName == '_id')
|
||
continue;
|
||
let heroAttrData: CeAttrData = hero.ceAttr[attrName] || new CeAttrData();
|
||
let globalAttrData: CeAttrData = role.globalCeAttr[attrName];
|
||
let attrNumber = (heroAttrData.fixUp + (heroAttrData.equipUp || 0) + globalAttrData.fixUp) * HERO_CE_RATIO + heroAttrData.base * (HERO_CE_RATIO + heroAttrData.ratioUp + globalAttrData.ratioUp);
|
||
heroCe += attrNumber * getAttrCeRatio(attrName);
|
||
}
|
||
let incHeroCe = heroCe - hero.ce;
|
||
hero.ce = heroCe;
|
||
role.ce += hero.ce;
|
||
pushHeros.push({ hid: hero.hid, ce: reduceCe(hero.ce), incHeroCe: reduceCe(incHeroCe) });
|
||
await HeroModel.updateHeroInfo(roleId, hero.hid, { ce: hero.ce });
|
||
}
|
||
role = await RoleModel.updateRoleInfo(roleId, { globalCeAttr: role.globalCeAttr, ce: role.ce });
|
||
return { pushHeros, ce: role.ce, topFiveCe: role.topFiveCe }
|
||
}
|
||
|
||
function calHeroAddSkin(args: Array<number>, ceAttr: CeAttrRole) {
|
||
let res: CeAttrRole = {};
|
||
for (let arg of args) {
|
||
let addSkin = gameData.fashion.get(arg);
|
||
let attrName: string;
|
||
for (let attr of addSkin.globalAttr) {
|
||
attrName = getAtrrNameById(attr.id);
|
||
res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp += attr.number * HERO_CE_RATIO;
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* 全局加成,百家学宫
|
||
* @param heros 所有武将
|
||
* @param schoolId 学宫学派
|
||
* @param hid 换上的武将
|
||
* @param preHid 撤下的武将
|
||
* @param ceAttr
|
||
*/
|
||
function calSchoolAddAttr(heros: HeroType[], schoolId: number, hid: number, preHid: number, ceAttr: CeAttrRole) {
|
||
let res: CeAttrRole = {};
|
||
let school = gameData.school.get(schoolId);
|
||
let preHero = heros.find(cur => cur.hid == preHid);
|
||
let curHero = heros.find(cur => cur.hid == hid);
|
||
if (!school) return res;
|
||
|
||
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;
|
||
|
||
let attrName: string;
|
||
for (let attrId of school.upAttribute) {
|
||
attrName = getAtrrNameById(attrId);
|
||
res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp };
|
||
if (attrId < ABI_TYPE.ABI_SPEED) { // 主属性
|
||
res[attrName].ratioUp += curRate.mainAttrAPerent - preRate.mainAttrAPerent;
|
||
} else { // 次级属性
|
||
res[attrName].fixUp += (curRate.assiAttrAddValue - preRate.assiAttrAddValue) * HERO_CE_RATIO;
|
||
}
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* 升星,觉醒,升品时,百家学宫配置武将会相应修改全局战力
|
||
* @param heros HeroType[] 传入只有一个,如果有全局计算,后面push其他武将
|
||
* @param type number 类型
|
||
* @param args
|
||
* @param ceAttr
|
||
*/
|
||
async function calSchoolStarIncAttr(heros: HeroType[], type: number, args: number[], ceAttr: CeAttrRole) {
|
||
let res: CeAttrRole = {};
|
||
let [hid, isStarUp] = args; // 是否升星,是否初次觉醒
|
||
let needCal = false;
|
||
let roleId: string = '';
|
||
for (let hero of heros) {
|
||
if (hero.hid != hid) {
|
||
continue;
|
||
}
|
||
if ((type == HERO_SYSTEM_TYPE.STAR || type == HERO_SYSTEM_TYPE.COLORSTAR) && !isStarUp) {
|
||
continue;
|
||
}
|
||
roleId = hero.roleId;
|
||
let curHeroInSchool = await SchoolModel.findByHid(roleId, hid);
|
||
if (!curHeroInSchool) continue;
|
||
|
||
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 {
|
||
continue;
|
||
}
|
||
let school = gameData.school.get(curHeroInSchool.schoolId);
|
||
let preRate = getSchoolRateByStar(preStar, preColorStar, preQuality);
|
||
let curRate = getSchoolRateByStar(hero.star, hero.colorStar, hero.quality);
|
||
|
||
let attrName: string;
|
||
for (let attrId of school.upAttribute) {
|
||
attrName = getAtrrNameById(attrId);
|
||
res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp };
|
||
if (attrId < ABI_TYPE.ABI_SPEED) { // 主属性
|
||
res[attrName].ratioUp += curRate.mainAttrAPerent - preRate.mainAttrAPerent;
|
||
} else { // 次级属性
|
||
res[attrName].fixUp += (curRate.assiAttrAddValue - preRate.assiAttrAddValue) * HERO_CE_RATIO;
|
||
}
|
||
}
|
||
needCal = true;
|
||
|
||
}
|
||
|
||
if (needCal) {
|
||
const allHeros = await HeroModel.findByRole(roleId);
|
||
for (let hero of allHeros) {
|
||
if (hero.hid != hid) heros.push(hero);
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* 全局加成, 名将谱
|
||
* @param heros 所有武将
|
||
* @param hid 激活的武将
|
||
* @param ceAttr
|
||
*/
|
||
function calScrollAddAttr(heros: HeroType[], hid: number, ceAttr: CeAttrRole) {
|
||
let res: CeAttrRole = {};
|
||
|
||
let curHero = heros.find(cur => cur.hid == hid);
|
||
let dicHero = gameData.hero.get(hid);
|
||
if (!curHero || !dicHero) return res;
|
||
let { quality } = dicHero;
|
||
let { star, quality: curQuality, colorStar, job } = curHero;
|
||
let heroScroll = getScollByStar(quality, star, curQuality, colorStar);
|
||
if (!heroScroll) return res;
|
||
|
||
let preScroll = gameData.preHeroScroll.get(heroScroll.id);
|
||
heroScroll.ceAttr.forEach((add, id) => {
|
||
let attId = getFieldByStage(id, job);
|
||
let attrName = getAtrrNameById(attId);
|
||
|
||
let preAdd = preScroll ? preScroll.ceAttr.get(id) : 0;
|
||
|
||
res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp += (add - preAdd) * HERO_CE_RATIO;
|
||
});
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* 名将谱激活增加单个武将好感
|
||
* @param hero 当前武将
|
||
* @param hid 激活武将
|
||
* @param preFavourLv 之前的好感度等级,有提升时才计算加成
|
||
*/
|
||
function calHeroCeScrollIncAttr(hero: HeroType, hid: number, preFavourLv: number) {
|
||
let res: CeAttr = {};
|
||
if (hero.hid == hid && hero.favourLv != preFavourLv) {
|
||
res = calHeroFavourUpIncAttr(hero, [preFavourLv]);
|
||
}
|
||
return res;
|
||
}
|
||
|
||
function calTitle(args: Array<number>, ceAttr: CeAttrRole) {
|
||
let res: CeAttrRole = {};
|
||
let titleId = args[0];
|
||
let titleInfo = gameData.title.get(titleId);
|
||
for (let attrName in getTeraphAttr()) {
|
||
res[attrName] = { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp };
|
||
res[attrName].fixUp += titleInfo[attrName] * HERO_CE_RATIO;
|
||
}
|
||
for (let attr of titleInfo.assiAttrValue) {
|
||
let attrName = getAtrrNameById(attr.id);
|
||
if (!attrName) continue;
|
||
res[attrName] = res[attrName] || { fixUp: ceAttr[attrName].fixUp, ratioUp: ceAttr[attrName].ratioUp };
|
||
res[attrName].ratioUp += attr.number * HERO_CE_RATIO;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
export function initRoleAtrr(role: RoleType) {
|
||
if (!role.globalCeAttr) role.globalCeAttr = new CeAttr();
|
||
let titleId = role.title;
|
||
let titleInfo = gameData.title.get(titleId);
|
||
if (!!titleInfo) {
|
||
for (let attrName in getTeraphAttr()) {
|
||
if (!attrName) continue;
|
||
role.globalCeAttr[attrName].fixUp += titleInfo[attrName] * HERO_CE_RATIO;
|
||
}
|
||
for (let attr of titleInfo.assiAttrValue) {
|
||
let attrName = getAtrrNameById(attr.id);
|
||
if (!attrName) continue;
|
||
role.globalCeAttr[attrName].ratioUp += attr.number * HERO_CE_RATIO;
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
async function reCalRoleAttr(heros: Array<HeroType>, ceAttr: CeAttrRole, type: number, args: Array<number>) {
|
||
let reIncAttr: CeAttrRole = {}; // role表属性增量
|
||
switch (type) {
|
||
case HERO_SYSTEM_TYPE.INIT:
|
||
reIncAttr = calRoleInitIncAttr(heros, ceAttr); // 全局变量增
|
||
break;
|
||
case HERO_SYSTEM_TYPE.ADD_SKIN:
|
||
reIncAttr = calHeroAddSkin(args, ceAttr);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.SCHOOL:
|
||
reIncAttr = calSchoolAddAttr(heros, args[0], args[1], args[2], ceAttr);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.SCROLL:
|
||
reIncAttr = calScrollAddAttr(heros, args[0], ceAttr);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.STAR:
|
||
case HERO_SYSTEM_TYPE.COLORSTAR:
|
||
case HERO_SYSTEM_TYPE.QUALITY:
|
||
reIncAttr = await calSchoolStarIncAttr(heros, type, args, ceAttr);
|
||
break;
|
||
case HERO_SYSTEM_TYPE.TITLE:
|
||
reIncAttr = calTitle(args, ceAttr);
|
||
}
|
||
for (let attrName in reIncAttr) {
|
||
if (attrName == '_id') continue;
|
||
let globalAttrData: CeAttrDataRole = reIncAttr[attrName] || new CeAttrDataRole();
|
||
for (let key in globalAttrData) {
|
||
ceAttr[attrName][key] = parseInt(globalAttrData[key] || 0);
|
||
}
|
||
}
|
||
} |