创建武将

This commit is contained in:
陆莹
2022-03-25 14:14:36 +08:00
parent a394bae03e
commit 1bdace30f9
17 changed files with 747 additions and 357 deletions
+13 -11
View File
@@ -2,12 +2,12 @@ import BaseModel from './BaseModel';
import { index, getModelForClass, prop, Ref, mongoose, DocumentType } from '@typegoose/typegoose';
// import Equip, { } from './Equip';
import { CounterModel } from './Counter';
import { COUNTER, HERO_CE_RATIO } from '../consts';
import { COUNTER, DEFAULT_HERO_LV, HERO_CE_RATIO } from '../consts';
import { reduceCe } from '../pubUtils/util';
import Skin from './Skin';
import Skin, { SkinUpdate } from './Skin';
import { SearchHeroParam } from '../domain/backEndField/search';
import { Reward } from '../domain/battleField/pvp';
import { getHeroInitTalent } from '../pubUtils/data';
import { gameData, getHeroExpByLv, getHeroInitTalent } from '../pubUtils/data';
type CeAttrUpdate = Partial<CeAttrData>;
export class CeAttrData {
@@ -88,12 +88,12 @@ export class HeroSkin {
@prop({ required: true })
usedTalentPoint: number; // 已使用的天赋点数
constructor(id: number, skinId: number, skin: string, enable: boolean) {
this.id = id;
this.skinId = skinId;
this.skin = skin;
constructor(skin: SkinUpdate, enable = true) {
this.id = skin.id;
this.skinId = skin.skinId;
this.skin = skin._id;
this.enable = enable;
this.talent = getHeroInitTalent(skinId);
this.talent = getHeroInitTalent(skin.skinId);
this.usedTalentPoint = 0;
}
}
@@ -274,16 +274,18 @@ export default class Hero extends BaseModel {
return hero;
}
public static getInitInfo(heroInfo: HeroUpdate = {}): HeroUpdate {
public static getInitInfo(hid: number, heroInfo: HeroUpdate = {}): HeroUpdate {
let dicHero = gameData.hero.get(hid)
let { quality, initialStars: star, jobid: job, name: hName } = dicHero;
const doc = new HeroModel();
const update = { ...doc.toJSON(), ...heroInfo};
const update = { ...doc.toJSON(), hid, skinId: hid, hName, star, quality, job, lv: DEFAULT_HERO_LV, exp: getHeroExpByLv(DEFAULT_HERO_LV - 1) || 0, ...heroInfo};
delete update._id;
return update
}
public static async createHero(heroInfo: HeroUpdate, lean = true) {
const seqId = await CounterModel.getNewCounter(COUNTER.HID) || -1;
const update = this.getInitInfo({ ...heroInfo, seqId });
const update = this.getInitInfo(heroInfo.hid, { ...heroInfo, seqId });
const hero: HeroType = await HeroModel.findOneAndUpdate({ roleId: heroInfo.roleId, hid: heroInfo.hid }, update, { upsert: true, new: true }).lean(lean);
return hero;
}
+98
View File
@@ -0,0 +1,98 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
// 全局加成
export class GlobalAttr {
@prop({ required: true })
attrId: number; // 属性id
@prop({ required: true })
values: number[]; // 战力公式中的全局加成的数据,查表后的结果
}
// 单武将加成
export class HeroAttr {
@prop({ required: true })
hid: number; // 武将id
@prop({ required: true })
lv: number;
@prop({ required: true, type: () => HeroAttrCell, _id: false })
attrs: HeroAttrCell[];
}
export class HeroAttrCell {
@prop({ required: true })
attrId: number; // 属性id
@prop({ required: true })
values: number[]; // 战力公式中的武将加成的数据,查表后的结果
}
// 装备加成
class EquipAttr {
@prop({ required: true })
hid: number; // 武将id
@prop({ required: true })
eplaceId: number; // 装备位置
@prop({ required: true })
attrId: number; // 属性id
@prop({ required: true })
values: number[]; // 战力公式中的武将加成的数据,查表后的结果
}
// 百家学宫加成
class SchoolAttr {
@prop({ required: true })
hid: number; // 武将id
@prop({ required: true })
attrId: number; // 属性id
@prop({ required: true })
value: number; // 百家学宫有多个武将,单独拎出来方便计算,计算之后结果存到globaAttrs的global1
}
// 名将谱加成
class ScrollAttr {
@prop({ required: true })
hid: number; // 武将id
@prop({ required: true })
attrId: number; // 属性id
@prop({ required: true })
value: number; // 百家学宫有多个武将,单独拎出来方便计算,计算之后结果存到globaAttrs的global1
}
/**
* 属性表
*/
@index({ roleId: 1 })
@index({ roleId: 1 })
export default class RoleCe extends BaseModel {
@prop({ required: true })
roleId: string; // 角色 id
@prop({ required: true, type: GlobalAttr, _id: false })
globalAttrs: GlobalAttr[]
@prop({ required: true, type: HeroAttr, _id: false })
heroAttrs: HeroAttr[]
@prop({ required: true, type: EquipAttr, _id: false })
equipAttrs: EquipAttr[]
@prop({ required: true, type: SchoolAttr, _id: false })
schoolAttr: SchoolAttr[];
@prop({ required: true, type: ScrollAttr, _id: false })
scrollAttrs: ScrollAttr[];
public static async findByRoleId(roleId: string) {
let result: RoleCeType[] = await RoleCeModel.find({ roleId }).lean();
return result;
}
}
export const RoleCeModel = getModelForClass(RoleCe);
export interface RoleCeType extends Pick<DocumentType<RoleCe>, keyof RoleCe> { };
export type RoleCeUpdate = Partial<RoleCeType>;
+10
View File
@@ -1,5 +1,6 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose';
import { gameData } from '../pubUtils/data';
@index({ roleId: 1, id: 1 })
@index({ seqId: 1 })
@modelOptions({ schemaOptions: { id: false } })
@@ -28,6 +29,15 @@ export default class Skin extends BaseModel {
return rec;
}
public static getInitInfo(hid: number): SkinUpdate {
let dicHero = gameData.hero.get(hid);
let dicFashion = gameData.fashion.get(dicHero.initialSkin)
const doc = new SkinModel();
const update = { ...doc.toJSON(), id: dicFashion.id, skinId: dicFashion.heroId, skinName: dicFashion.name, hid};
delete update._id;
return update
}
public static async insertSkins(roleId: string, roleName: string, skinInfos: SkinUpdate[]) {
let insertInfos: SkinUpdate[] = [];
for(let skinInfo of skinInfos) {
-249
View File
@@ -1,249 +0,0 @@
import { ABI_STAGE, ABI_STAGE_TO_TYPE, ABI_TYPE, ABI_TYPE_MAIN, HERO_CE_RATIO, HERO_SYSTEM_TYPE, SEID_TYPE } from "../../consts";
import { HeroModel, HeroUpdate, CeAttrData } from "../../db/Hero";
import { CeAttrDataRole, RoleUpdate } from "../../db/Role";
import { gameData, getHeroStarByQuality, getHeroWakeByQuality } from "../../pubUtils/data";
import { DicRandomEffectPool } from "../../pubUtils/dictionary/DicRandomEffectPool";
import { DicSe } from "../../pubUtils/dictionary/DicSe";
import { deepCopy } from "../../pubUtils/util";
import { AttributeCal } from "./attribute";
export class CalRoleCe {
private roleInfo: RoleUpdate;
private roleCeWithAttr: Map<ABI_TYPE, CeAttrDataRole> = new Map();
constructor(roleInfo?: RoleUpdate) {
this.roleInfo = roleInfo;
}
public cal(type: HERO_SYSTEM_TYPE) {
switch (type) {
case HERO_SYSTEM_TYPE.INIT:
this.calTitleAbility();
this.calTeraphMainAttr();
break;
}
return this.getRoleAttr();
}
private calTitleAbility() {
let { title } = this.roleInfo;
let dicTitle = gameData.title.get(title)||{ mainAttrValue: new Map(), assiAttrValue: new Map() };
for (let i = ABI_TYPE.ABI_HP; i < ABI_TYPE.ABI_MAX; i++) {
if (dicTitle.mainAttrValue.has(i)) {
let fixUp = dicTitle.mainAttrValue.get(i) || 0;
this.getSingleAttrObj(i).updateAttr({ inc: { fixUp } });
}
if (dicTitle.assiAttrValue.has(i)) {
let fixUp = dicTitle.assiAttrValue.get(i) || 0;
this.getSingleAttrObj(i).updateAttr({ inc: { fixUp } });
}
}
}
private calTeraphMainAttr(id?: number) {
let { teraphs = [] } = this.roleInfo;
for(let teraph of teraphs) {
if(id == undefined || teraph.id == id) {
for(let [attrId, val] of teraph.attr) {
this.getSingleAttrObj(attrId).updateAttr({ inc: { fixUp: val } });
}
}
}
}
// 获取一个CeAttrData对象,没有就新建
public getSingleAttrObj(attrId: ABI_TYPE) {
if(!this.roleCeWithAttr.has(attrId)) {
let calSingleAttr = new CeAttrDataRole(attrId);
this.roleCeWithAttr.set(attrId, calSingleAttr);
}
return this.roleCeWithAttr.get(attrId);
}
private getRoleAttr() {
let attr: CeAttrDataRole[] = [];
this.roleCeWithAttr.forEach(value => {
if(value.ratioUp > 0 || value.fixUp > 0) {
attr.push(value);
}
});
return attr;
}
}
export class CalHeroCe {
private hid: number;
private heroInfo: HeroUpdate;
private heroCeWithAttr: Map<ABI_TYPE, CeAttrData> = new Map();
constructor(hid: number, heroInfo?: HeroUpdate) {
this.hid = hid;
if(heroInfo) this.heroInfo = heroInfo;
}
public async setHeroInfoByHid(roleId: string) {
let hero = await HeroModel.findByHidAndRole(this.hid, roleId);
this.heroInfo = hero;
}
// 主要接口
public cal(type: HERO_SYSTEM_TYPE) {
switch (type) {
case HERO_SYSTEM_TYPE.INIT:
case HERO_SYSTEM_TYPE.REBIRTH:
this.calBaseAbility();
this.calSkinSeid();
this.calJobAbility();
break;
}
return this.getHeroAttr()
}
// 计算基础属性
private calBaseAbility() {
let { star, starStage, quality, colorStar, colorStarStage, lv, skinId } = this.heroInfo;
const dicHero = gameData.hero.get(skinId);
if(!dicHero) {
console.error(`not found hero: ${skinId}`);
return;
}
for (let stage = ABI_STAGE.START + 1; stage <= ABI_STAGE.END; stage++) {
let attrId = ABI_STAGE_TO_TYPE.get(stage);
const isWake = colorStar > 0; // 是否觉醒,只要激活了觉醒,彩星就会 > 1
// console.log('*isUpstar', isUpStar, originStar, star, originColorStar, colorStar)
const dicStar = isWake ? getHeroWakeByQuality(dicHero.jobClass, dicHero.quality, colorStarStage < stage? colorStar - 1: colorStar) : getHeroStarByQuality(dicHero.jobClass, quality, starStage < stage? star - 1: star); // 星级表
let heroAttr = dicHero.baseAbilityArr.get(attrId); // 武将表hp等
let heroUpAttr = dicHero.baseAbilityUpArr.get(attrId); // 武将表hp_up等
let starUp = 0; // 星级成长
if (!!dicStar && !!dicStar.ceAttr) {
starUp = dicStar.ceAttr.get(stage);
}
let base = heroAttr + lv * (heroUpAttr + starUp);
this.getSingleAttrObj(attrId).updateAttr({ set: { base } });
};
}
// 计算职业属性
private calJobAbility() {
let { job, jobStage } = this.heroInfo;
const dicJob = gameData.job.get(job);
for(let i = 1; i <= dicJob.maxStage; i++) {
if(jobStage >= i) {
let { id, attr } = dicJob.ceAttr.get(i);
this.getSingleAttrObj(id).updateAttr({ inc: { fixUp: attr } });
}
}
}
// 计算皮肤属性
private calSkinSeid() {
let { skinId, star: _star, colorStar: _colorStar } = this.heroInfo;
let seidList = new Map<number, number>(); // type => seid
let dicHero = gameData.hero.get(skinId);
let { starSeidArr, colorStarSeidArr } = gameData.heroSkill.get(dicHero.skill);
for (let { star, value, type } of starSeidArr) {
if (_star >= star) {
seidList.set(type, value);
}
}
for (let { star, value, type } of colorStarSeidArr) {
if (_colorStar >= star) {
seidList.set(type, value);
}
}
let list: number[] = [];
for(let [_type, value] of seidList) list.push(value);
addSeidEffect.bind(this, list);
}
public getHeroAttr() {
let attr: CeAttrData[] = [];
this.heroCeWithAttr.forEach(value => {
if(value.base > 0 || value.equipUp > 0 || value.fixUp > 0 || value.ratioUp > 0) {
attr.push(value);
}
});
return attr;
}
// 获取一个CeAttrData对象,没有就新建
public getSingleAttrObj(attrId: ABI_TYPE) {
if(!this.heroCeWithAttr.has(attrId)) {
let calSingleAttr = new CeAttrData(attrId);
this.heroCeWithAttr.set(attrId, calSingleAttr);
}
return this.heroCeWithAttr.get(attrId);
}
public getCalculatedCe(roleAttr: CeAttrDataRole[]) {
let attrCal = new AttributeCal();
attrCal.setLv(this.heroInfo.lv);
attrCal.setByDbData(roleAttr, this.getHeroAttr());
return attrCal.calCe();
}
}
// 添加技能增加的被动属性
function addSeidEffect(this: CalRoleCe|CalHeroCe, seidList: number[]) {
// console.log('******addSeidEffect',this, seidList)
// console.log('addSeidList', addSeidList.join())
// console.log('removeSeidList', removeSeidList.join())
let effectList: DicSe[] = []; // any: dic_zyz_se表内容
for (let ii = 0; ii < seidList.length; ii += 2) {
let seid = seidList[ii];
let rand = seidList[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) { // 加值
this.getSingleAttrObj(ability).updateAttr({ inc: { fixUp: value } });
} else if (type == SEID_TYPE.TYPE103) { // 主属性加百分比
if(ABI_TYPE_MAIN.includes(ability)) {
this.getSingleAttrObj(ability).updateAttr({ inc: {ratioUp: value / 1000} });
}
} else if (type == SEID_TYPE.TYPE104) { // 次级属性加百分比
if(!ABI_TYPE_MAIN.includes(ability)) {
this.getSingleAttrObj(ability).updateAttr({ inc: { fixUp: value * 100 * HERO_CE_RATIO } });
}
}
}
}
// 获取dic_zyz_se内容
function addSeid(effectList: (DicSe | DicRandomEffectPool)[], seidId: number, rand: number, seidValue: 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);
}
+1 -48
View File
@@ -4,7 +4,7 @@
import { HERO_SYSTEM_TYPE, ABI_TYPE, HERO_CE_RATIO, LINEUP_NUM, TALENT_RELATION_TYPE } from '../consts';
import { cal, deepCopy, getAllAttrStage, reduceCe } from './util';
import { cal, calculatetopLineup, deepCopy, getAllAttrStage, reduceCe } from './util';
import { HeroModel, HeroType, HeroUpdate, CeAttrData, EPlace, Stone, Talent } from '../db/Hero';
import { RoleModel, RoleType, RoleUpdate, CeAttrDataRole } from '../db/Role';
import { AttributeCal } from '../domain/roleField/attribute';
@@ -209,53 +209,6 @@ export async function calPlayerCe(hero: HeroType, update: HeroUpdate, type: numb
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 };
}
/**
* 添加皮肤全局加成
+58 -1
View File
@@ -6,13 +6,14 @@ import { isNumber } from 'underscore';
const csprng = require('csprng');
import fs = require('fs');
import path = require('path');
import { HERO_CE_RATIO, ABI_STAGE, GACHA_TO_FLOOR, REFRESH_TIME, ROBOT_SYS_TYPE, ITEM_CHANGE_REASON, WAR_TYPE } from '../consts';
import { HERO_CE_RATIO, ABI_STAGE, GACHA_TO_FLOOR, REFRESH_TIME, ROBOT_SYS_TYPE, ITEM_CHANGE_REASON, WAR_TYPE, LINEUP_NUM } from '../consts';
import { findIndex } from 'underscore';
import { getTimeFunM } from './timeUtil';
import { Floor } from '../domain/activityField/gachaField';
import { WhiteListModel } from '../db/RegionWhiteList';
import { RewardInter } from './interface';
import { RoleType } from '../db/Role';
const randomName = require("chinese-random-name");
const moment = require('moment');
const crypto = require('crypto');
@@ -788,3 +789,59 @@ export function stringToRewardInter(rewardStr: string): Array<RewardInter> {
}
return result
}
export function addToMap<T>(map: Map<T, number>, id: T, value: number) {
if(!map.has(id)) {
map.set(id, value);
} else {
map.set(id, map.get(id) + value);
}
}
/**
* 计算最强阵容战力
* @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 };
}