战力计算,远征战力筛选

This commit is contained in:
luying
2020-11-12 18:21:05 +08:00
parent 40c16587b3
commit b0a0bbc71b
34 changed files with 22812 additions and 15964 deletions

440
shared/pubUtils/actor.ts Normal file
View File

@@ -0,0 +1,440 @@
import { getHeroInfoById, getStarRatio, getHeroSkillById, getSeidById, getOlySeidByType, getGoodById } from "./gamedata";
import { ABI_TYPE, SEID_TYPE } from "../consts/abilityConst";
export default class Actor {
private hid: number = 0;
private lv: number = 0;
private oldCe: number = 0;
private star: number = 0;
private fire: number = 0;
private equips: Array<any> = [];
private conections: Array<{id: number;name: string;valid: boolean;}> = [];
/**被动技能 */
private seidList:Array<any> = new Array<any>(3);
private effectList:Map<number,Array<any> > = new Map<number,Array<any> >();
constructor(hero: any) { // 从数据库拿到的hero
this.hid = hero.hid;
this.lv = hero.lv;
this.oldCe = hero.ce;
this.star = hero.star;
this.fire = hero.fire;
this.equips = hero.equips;
console.log(this.hid, this.lv, this.oldCe, this.star, this.fire, this.conections);
this.updateActorEffect();
}
updateActorEffect(){
//添加装备属性和效果
//添加技能
this.updateSkillInfo();
//添加被动效果1.0
for(let i = 0;i < this.seidList.length;i++){
if(this.seidList[i] && this.seidList[i].id > 0){
this.addSeidEffect(this.seidList[i].id,this.seidList[i].gainValueArr);
}
}
//添加被动效果 2.0
// for(let i = 0;i < this.seidList.length;i++){
// if(this.seidList[i]._id > 0){
// this.addSeidEffectNew(this.seidList[i]);
// }
// }
}
/**更新武将的被动技能 */
updateSkillInfo(){
let dicHero = getHeroInfoById(this.hid);
// console.log('updateSkillInfo', dicHero.skill, getHeroSkillById(dicHero.skill))
//被动技能
if(dicHero.skill){
let {seidLvUpArr} = getHeroSkillById(dicHero.skill);
for(let ii = 0;ii < seidLvUpArr.length;ii+=2){
if(this.lv >= seidLvUpArr[ii + 1]){
let dicSeid = getSeidById(seidLvUpArr[ii]);
// console.log('updateSkillInfo*', seidLvUpArr[ii], dicSeid)
if(dicSeid){
this.seidList[Math.floor(ii/2)] = dicSeid;
}
}
}
}
}
addSeidEffect(seidId:number, seidValue?:Array<number>){
// console.log('addSeidEffect', seidId, seidValue)
let curSeid = getSeidById(seidId);
if(!curSeid) {console.log("seidId not found:"+seidId);return;}
if(!seidValue) seidValue = curSeid.gainValueArr;
if(!seidValue) seidValue = [];
if(curSeid.type === 999){
for(let i = 0;i < seidValue.length;i++){
this.addSeidEffect(seidValue[i]);
}
return;
}
let olySeid = getOlySeidByType(curSeid.type);
if(!olySeid) {console.log("olySeidType not found:"+curSeid.type);return;}
if(olySeid.isSeid){ // 是被动
let el = this.effectList.get(curSeid.type);
if(!el || !el.length){
if(!el){
this.effectList.set(curSeid.type, [Object.assign({}, curSeid)]);
} else {
el.push(Object.assign({}, curSeid));
}
}
else{
let buffArr = this.effectList.get(curSeid.type)||[];
if(olySeid.olyType == 101){
let identical:boolean = true;
buffArr.forEach((value)=>{
if(value.type != curSeid.type||value.gainValueArr.length != seidValue?.length){
identical = false;
return;
}
value.gainValueArr.forEach((val,key)=>{
if(!seidValue) seidValue = [];
if(val!= seidValue[key]){
identical = false;
return;
}
})
});
if(!identical){
let el = this.effectList.get(curSeid.type);
if(!el){
this.effectList.set(curSeid.type, [Object.assign({}, curSeid)]);
} else {
el.push(Object.assign({}, curSeid));
}
}
}
else
{
let tBuff,startIndex:number = 0;
if(olySeid.olyType >= 103){
startIndex = 1;
let addSeid:boolean = true;
for(let k = 0;k < buffArr.length;k++){
tBuff = buffArr[k];
if(tBuff && tBuff.gainValueArr && tBuff.gainValueArr[0] == seidValue[0]){
addSeid = false;
break;
}
}
if(addSeid){
tBuff = null;
let el = this.effectList.get(curSeid.type);
if(!el){
this.effectList.set(curSeid.type, [Object.assign({}, curSeid)]);
} else {
el.push(Object.assign({}, curSeid));
}
}
}
else {
tBuff = buffArr[0];
}
if(tBuff){
for(let j = startIndex;j < seidValue.length;j++){
switch(olySeid.olyType){
case 100:
tBuff.gainValueArr[j] += seidValue[j];
break;
case 102:
tBuff.gainValueArr[j] = seidValue[j];
break;
case 103:
if(tBuff.gainValueArr[j] < seidValue[j]){
tBuff.gainValueArr[j] = seidValue[j];
}
break;
case 104:
if(tBuff.gainValueArr[j] > seidValue[j]){
tBuff.gainValueArr[j] = seidValue[j];
}
break;
default:
break;
}
}
}
}
// switch(olySeid._olyType){
// case 1://对比
// break;
// case 2://
// default:
// console.log("not found _olyType:"+olySeid._olyType);
// break;
// }
}
}
}
getGrowUp(abilityType:number):number{
const dicHero = getHeroInfoById(this.hid);
const dicStarRatio = getStarRatio(this.star)||0;
return dicHero.baseAbilityUpArr[abilityType] * dicStarRatio;
}
getBaseAbility(abilityType:number):number{
const dicHero = getHeroInfoById(this.hid);
// console.log('getBaseAbility', dicHero.baseAbilityArr[abilityType]);
// console.log('getBaseAbility', this.lv);
// console.log('getBaseAbility', this.getGrowUp(abilityType));
return dicHero.baseAbilityArr[abilityType] + (this.lv - 1)*this.getGrowUp(abilityType);
}
isHadSeid(type:number):boolean{
let el = this.effectList.get(type);
if(this.effectList.has(type) && el && el.length){
return true;
}
return false;
}
/**
* 获取武将效果
* @type 特技type
* returns Array<Array<Buff> > 0:特技 1buff 2:光环
* */
getSeidEffect(type:number):Array<Array<any> >{
let retArr:Array<Array<any> > = new Array<Array<any> >();
let el = this.effectList.get(type);
if(this.effectList.has(type) && el && el.length){
retArr.push(el);
}
return retArr;
}
/**获取seid 数值效果 */
getSeidAddAbilityNumByAbility(type:number,ability:number){ // type: 101/102等ability1-17代表hp,atk等
let ret:number = 0;
if(this.isHadSeid(type)){ // effectList, buffList
let buff = this.getSeidEffect(type);
for(let i = 0;i < buff.length;i++){
for(let j = 0;j < buff[i].length;j++){
// console.log(ability, buff[i][j].gainValueArr[0], buff[i][j].gainValueArr[1])
if(ability == buff[i][j].gainValueArr[0]){
ret += buff[i][j].gainValueArr[1];
}
}
}
}
// console.log('getSeidAddAbilityNumByAbility', type, ret)
return ret;
}
getRealAbility(abilityType: number) {
let baseAbility:number = 0;
if(abilityType <= ABI_TYPE.ABI_SPEED){
// console.log('getRealAbility', this.getBaseAbility(abilityType));
// console.log('getRealAbility', this.getSeidAddAbilityNumByAbility(SEID_TYPE.TYPE102,abilityType));
// console.log('getRealAbility', this.getSeidAddAbilityNumByAbility(SEID_TYPE.TYPE101,abilityType));
baseAbility = this.getBaseAbility(abilityType)*(100+this.getSeidAddAbilityNumByAbility(SEID_TYPE.TYPE102,abilityType))/100 + this.getSeidAddAbilityNumByAbility(SEID_TYPE.TYPE101,abilityType);
}
else{
baseAbility = this.getSeidAddAbilityNumByAbility(SEID_TYPE.TYPE101,abilityType);
}
return baseAbility
}
calculateCE() {
// 武将
const ceGongshi = '1*hp+2*atk+2*matk+2*def+2*mdef+2*agi+2*luk+1*hit+1*cri+1*flee+1*antCri+1.75*damageIncrease+1.75*damageDecrease+3.5*defIngnore+3.5*bloodSuck'
let hp = this.getRealAbility(ABI_TYPE.ABI_HP); console.log(this.hid, 'hp', hp);
let atk = this.getRealAbility(ABI_TYPE.ABI_ATK); console.log(this.hid, 'atk', atk);
let matk = this.getRealAbility(ABI_TYPE.ABI_MATK); console.log(this.hid, 'matk', matk);
let def = this.getRealAbility(ABI_TYPE.ABI_DEF); console.log(this.hid, 'def', def);
let mdef = this.getRealAbility(ABI_TYPE.ABI_MDEF); console.log(this.hid, 'mdef', mdef);
let agi = this.getRealAbility(ABI_TYPE.ABI_AGI); console.log(this.hid, 'agi', agi);
let speed = this.getRealAbility(ABI_TYPE.ABI_SPEED); console.log(this.hid, 'speed', speed);
let luk = this.getRealAbility(ABI_TYPE.ABI_LUK); console.log(this.hid, 'luk', luk);
let hit = this.getRealAbility(ABI_TYPE.ABI_HIT); console.log(this.hid, 'hit', hit);
let cri = this.getRealAbility(ABI_TYPE.ABI_CRI); console.log(this.hid, 'cri', cri);
let flee = this.getRealAbility(ABI_TYPE.ABI_FLEE); console.log(this.hid, 'flee', flee);
let antCri = this.getRealAbility(ABI_TYPE.ABI_ANT_CRI); console.log(this.hid, 'antCri', antCri);
let damageIncrease = this.getRealAbility(ABI_TYPE.ABI_DAMAGE_INCREASE); console.log(this.hid, 'damageIncrease', damageIncrease);
let damageDecrease = this.getRealAbility(ABI_TYPE.ABI_DAMAGE_DECREASE); console.log(this.hid, 'damageDecrease', damageDecrease);
let defIngnore = this.getRealAbility(ABI_TYPE.ABI_DEF_IGNORE); console.log(this.hid, 'defIngnore', defIngnore);
let bloodSuck = this.getRealAbility(ABI_TYPE.ABI_BLOOD_SUCK); console.log(this.hid, 'bloodSuck', bloodSuck);
let ce = eval(ceGongshi); console.log(this.hid, 'ce', ce);
// 装备
for(let equip of this.equips) {
let good = new HistoryGoods();
good.loadDataByJson(equip);
for(let i = ABI_TYPE.ABI_HP;i < ABI_TYPE.ABI_MAX;i++){
ce += good.getGoodsAddAbility(i);
}
}
console.log('ce2', ce)
return Math.floor(ce);
}
}
class HistoryGoods{
private _goodsId:number = 0;
private _serverGId:number = 0;
private _itid:number = 0;
private _quality:number = 0;
private _lv:number = 0;
/**物攻策攻数值浮动上下限变化率 */
private _randRange:number = 0;
/**装备的武将dataID */
private _equipActorDataId:number = 0;
/**装备属性 */
private _goodsAbility:Array<number> = new Array<number>();
/**装备属性 随机的百分比 */
private _goodsAbilityPre:Array<number> = new Array<number>();
resetAllData(){
this.setGoodsId(0);
this.setItid(0);
this.setEquipActorDataId(0);
for(let i = ABI_TYPE.ABI_HP;i < ABI_TYPE.ABI_MAX;i++){
this._goodsAbility[i] = 0;
this._goodsAbilityPre[i] = 0;
}
}
//加载
loadDataByJson(json){
// "_id": "5f841c27eb94a70b385beea4",
// "seqId": 8,
// "__v": 0,
// "createdAt": "2020-10-12T09:04:39.087Z",
// "eName": "青铜短剑",
// "eid": 1,
// "holes": [],
// "initHoleCnt": 0,
// "lv": 1,
// "randRange": 0,
// "randSe": [],
// "roleId": "1Emy2SnEaw",
// "roleName": "大蝈蝈",
// "type": 1,
// "updatedAt": "2020-10-12T09:04:39.087Z"
if(json.seqId){
this.setServerGId(json.seqId);
this.setGoodsId(json.eid);
this.setEquipActorDataId(json.hid);
//this.setQuality(json.quality);
this.setLevel(json.lv);
this.setRandRange(json.randRange);
let dicGoods = getGoodById(this.getGoodsId());
if(dicGoods){
this.setItid(dicGoods.itid);
}
}
}
//属性的获取方法///////////////
getGoodsId(){
return this._goodsId;
}
setGoodsId(goodsId:number){
this._goodsId = goodsId;
}
getServerGId(){
return this._serverGId;
}
setServerGId(serverGId:number){
this._serverGId = serverGId;
}
getItid(){
return this._itid;
}
setItid(itid:number){
this._itid = itid;
}
getQuality(){
return this._quality;
}
setQuality(quality:number){
this._quality = quality;
}
getLevel(){
return this._lv;
}
setLevel(lv:number){
this._lv = lv;
}
getRandRange(){
return this._randRange;
}
setRandRange(val:number){
this._randRange = val;
}
getEquipActorDataId(){
return this._equipActorDataId;
}
setEquipActorDataId(dataId:number){
this._equipActorDataId = dataId;
}
//属性的获取方法 end ////////////
constructor(){
for(let i = ABI_TYPE.ABI_HP;i < ABI_TYPE.ABI_MAX;i++){
this._goodsAbility[i] = 0;
this._goodsAbilityPre[i] = 0;
}
}
/**是否物品 */
isGoods(){
if(this.getGoodsId() > 0){
return true;
}
else{
return false;
}
}
/**是否装备 */
isEquipment(){
}
/**是否宝物 */
isTreasure(){
}
/**是否道具 */
isItem(){
}
getGoodsAddAbility(ability:number){
return Math.floor(this._goodsAbility[ability] * this._goodsAbilityPre[ability] / 100);
}
}

View File

@@ -1,5 +1,6 @@
import fs = require('fs');
import path = require('path');
import { ABI_TYPE } from '../consts/abilityConst';
let gamedata = {};
const wars = ['dic_zyz_gk_main', 'dic_zyz_gk_mainElite', 'dic_zyz_gk_daily', 'dic_zyz_gk_event', 'dic_zyz_gk_tower', 'dic_zyz_gk_expedition']; // 关卡相关的表
@@ -9,6 +10,10 @@ const towerTaskInfos = new Map<number, any>();
const heroInfos = new Map<number, any>();
const jobInfos = new Map<number, any>();
const levelInfos = new Map<number, {sum: number, cur: number}>();
const starRatioInfo = new Map<number, number>();
const heroSkillInfo = new Map<number, any>()
const seidInfo = new Map<number, any>();
const olySeidInfo = new Map<number, any>();
function parseWarData() {
let result = null;
@@ -48,6 +53,28 @@ function parseHeroData() {
const heroesData = gamedata['jsons'][heroFile] || [];
heroesData.forEach(elem => {
if (elem && elem.heroId) {
elem.baseAbilityArr = new Array<number>();
elem.baseAbilityUpArr = new Array<number>();
elem.baseAbilityArr[ABI_TYPE.ABI_HP] = elem.hp||0;
elem.baseAbilityArr[ABI_TYPE.ABI_ATK] = elem.atk||0;
elem.baseAbilityArr[ABI_TYPE.ABI_MATK] = elem.matk||0;
elem.baseAbilityArr[ABI_TYPE.ABI_DEF] = elem.def||0;
elem.baseAbilityArr[ABI_TYPE.ABI_MDEF] = elem.mdef||0;
elem.baseAbilityArr[ABI_TYPE.ABI_AGI] = elem.agi||0;
elem.baseAbilityArr[ABI_TYPE.ABI_LUK] = elem.luk||0;
elem.baseAbilityArr[ABI_TYPE.ABI_SPEED] = elem.speed||0;
elem.baseAbilityUpArr[ABI_TYPE.ABI_HP] = elem.hp_up||0;
elem.baseAbilityUpArr[ABI_TYPE.ABI_ATK] = elem.atk_up||0;
elem.baseAbilityUpArr[ABI_TYPE.ABI_MATK] = elem.matk_up||0;
elem.baseAbilityUpArr[ABI_TYPE.ABI_DEF] = elem.def_up||0;
elem.baseAbilityUpArr[ABI_TYPE.ABI_MDEF] = elem.mdef_up||0;
elem.baseAbilityUpArr[ABI_TYPE.ABI_AGI] = elem.agi_up||0;
elem.baseAbilityUpArr[ABI_TYPE.ABI_LUK] = elem.luk_up||0;
elem.baseAbilityUpArr[ABI_TYPE.ABI_SPEED] = elem.speed_up||0;
heroInfos.set(elem.heroId, elem);
}
});
@@ -76,6 +103,68 @@ function parseLevelInfo() {
});
}
function parseStarRatio() {
const file = 'dic_star_ratio';
const data = gamedata['jsons'][file] || [];
data.forEach(elem => {
if (elem && elem.star) {
starRatioInfo.set(elem.star, elem.ratio);
}
});
}
function parseHeroSkill() {
const file = 'dic_zyz_heroskill';
const data = gamedata['jsons'][file] || [];
data.forEach(elem => {
if (elem && elem.skillid) {
const seidLvUpArr = new Array<number>();
let skillArr = (elem.seid as string).split('&');
let lvUpArr = (elem.selv_up as string).split('&');
for(let i = 0;i < skillArr.length;i++){
if(skillArr[i]==="") continue;
seidLvUpArr.push(parseInt(skillArr[i]));
if(lvUpArr[i]){
seidLvUpArr.push(parseInt(lvUpArr[i]));
}
else{
seidLvUpArr.push(1000);
}
}
heroSkillInfo.set(elem.skillid, {seidLvUpArr});
}
});
}
function parseSeidList() {
const file = 'dic_zyz_se';
const data = gamedata['jsons'][file] || [];
data.forEach(elem => {
if (elem && elem.id) {
let {gainvalue} = elem;
let gainValueArr = (gainvalue as string).split('&');
elem.gainValueArr = new Array();
for(let g of gainValueArr) {
if(g === "") continue;
elem.gainValueArr.push(parseInt(g));
}
seidInfo.set(elem.id, elem);
}
});
}
function parseOlySeidList() {
const file = 'dic_zyz_se_add';
const data = gamedata['jsons'][file] || [];
data.forEach(elem => {
if (elem && elem.type) {
olySeidInfo.set(elem.type, elem);
}
});
}
function initData (folder: string) {
if(!gamedata.hasOwnProperty(folder)) {
gamedata[folder] = {};
@@ -107,6 +196,10 @@ function parseData() {
parseHeroData();
parseJobData();
parseLevelInfo();
parseStarRatio();
parseHeroSkill();
parseSeidList();
parseOlySeidList();
}
initData('jsons'); // 加载一般json
@@ -173,4 +266,20 @@ export function getLvByExp(exp: number) {
export function getExpByLv(lv: number) {
return levelInfos.get(lv);
}
export function getStarRatio(star: number) {
return starRatioInfo.get(star);
}
export function getHeroSkillById(skillId: number) {
return heroSkillInfo.get(skillId);
}
export function getSeidById(id: number) {
return seidInfo.get(id);
}
export function getOlySeidByType(type: number) {
return olySeidInfo.get(type);
}

View File

@@ -2,6 +2,9 @@ import { STATUS } from './../consts/statusCode';
import { getGamedata } from './gamedata';
import { HeroModel } from '../db/Hero';
import { RoleModel } from '../db/Role';
import { PvpDefenseModel } from '../db/PvpDefense';
import Actor from './actor';
const moment = require('moment');
@@ -26,6 +29,8 @@ const moment = require('moment');
}
export function decodeStrSingle(type, str) { //单层,返回对象而不是数组
let last = str.substr(str.length-1, 1);
if(last == '&') str = str.substr(0, str.length - 1);
if(str == '&'|| !str) {
return {}
} else {
@@ -320,4 +325,46 @@ export function setLocalHours(hour: number, curTime = new Date()) {
let localTime = new Date(curTime.getTime() + offset * 60 * 1000 + 8 * 60 * 60 * 1000); // 中国时间
localTime.setUTCHours(hour, 0, 0, 0); // 中国的几点
return localTime.getTime() - offset * 60 * 1000 - 8 * 60 * 60 * 1000; // 回到格林威治时间
}
export async function updateCe(roleId: string, hero: any ) {
let {hid, ce: oldCe, historyCe} = hero;
let actor = new Actor(hero);
let ce = actor.calculateCE();
if(ce != oldCe) {
// 更新总战力&最强五人战力
let role = await RoleModel.findByRoleId(roleId);
let distance = ce - oldCe;
let historyDistance = ce > historyCe ?ce - historyCe: 0;
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) { // 不在最强列表
if(topFive.length < 5) { // 不满5人
topFive.push({hid, ce});
} else if(topFive.length == 5){
if(ce > topFive[topFive.length - 1].ce) { // 跻身最强6人
topFive.pop();
topFive.push({hid, ce});
} else {
topFive[index].ce = ce;
}
} else {
topFive.splice(5, topFive.length - 5);
}
} else { // 原来就是最强5人
if(ce < topFive[topFive.length - 1].ce) { // 滑出最强
let heroes = await HeroModel.getTopHero(roleId, 5);
topFive = heroes.map(cur => {return {hid: cur.hid, ce: cur.ce}});
} else {
topFive[index].ce = ce;
}
}
let topFiveCe = topFive.reduce((pre, cur) => {
return pre + cur.ce
}, 0);
await RoleModel.findOneAndUpdate({roleId}, { topFive, topFiveCe, $inc: {ce: distance} });
await PvpDefenseModel.findOneAndUpdate({roleId, 'heroes.actorId': hid}, {$inc: {ce: distance}});
await HeroModel.findOneAndUpdate({roleId, hid}, {$inc:{ce: distance, historyCe: historyDistance}})
}
}