214 lines
7.0 KiB
TypeScript
214 lines
7.0 KiB
TypeScript
import { prop } from '@typegoose/typegoose';
|
|
import { HERO_CE_RATIO, getAtrrNameById, CE_CONST, HERO_SUB_ATTR_RATIO, ABI_TYPE_MAIN } from '../../consts';
|
|
import { decodeArrayListStr, reduceCe } from '../../pubUtils/util';
|
|
|
|
// hero表内属性基础格式
|
|
export class CeAttrData {
|
|
@prop({ required: true })
|
|
id: number = 0;
|
|
@prop({ required: true })
|
|
base: number = 0;
|
|
@prop({ required: true })
|
|
ratioUp: number = 0;
|
|
@prop({ required: true })
|
|
fixUp: number = 0;
|
|
@prop({ required: true })
|
|
equipUp: number = 0;
|
|
|
|
constructor(id: number) {
|
|
this.id = id;
|
|
}
|
|
}
|
|
|
|
// role表属性格式
|
|
export class CeAttrDataRole {
|
|
@prop({ required: true })
|
|
id: number = 0;
|
|
@prop({ required: true })
|
|
ratioUp: number = 0;
|
|
@prop({ required: true })
|
|
fixUp: number = 0;
|
|
|
|
constructor(id: number) {
|
|
this.id = id;
|
|
}
|
|
}
|
|
|
|
export class AttributeCal {
|
|
attrs: Map<number, number> = new Map<number, number>();
|
|
ce?: number = 0;
|
|
|
|
public setByDbData(roleAttrs: CeAttrDataRole[], heroAttrs: CeAttrData[]) {
|
|
for(let { id, fixUp: roleFix, ratioUp: roleRatio } of roleAttrs) {
|
|
let heroAttr = heroAttrs.find(heroAttr => heroAttr.id == id);
|
|
if(heroAttr) {
|
|
let { fixUp: heroFix, base: heroBase, ratioUp: heroRatio, equipUp: heroEquip } = heroAttr;
|
|
let value = this.calAttrValue(roleFix, roleRatio, heroBase, heroFix, heroRatio, heroEquip);
|
|
this.attrs.set(id, value);
|
|
} else {
|
|
let value = this.calAttrValue(roleFix, roleRatio, 0, 0, 0, 0);
|
|
this.attrs.set(id, value);
|
|
}
|
|
}
|
|
|
|
for(let { id, base: heroBase, fixUp: heroFix, ratioUp: heroRatio, equipUp: heroEquip } of heroAttrs) {
|
|
let roleAttr = roleAttrs.find(roleAttr => roleAttr.id == id);
|
|
if(!roleAttr) {
|
|
let value = this.calAttrValue(0, 0, heroBase, heroFix, heroRatio, heroEquip);
|
|
this.attrs.set(id, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public setByWarJson( attributes: {id: number, val: number}[], ratio: number = 1) {
|
|
for(let {id, val} of attributes) {
|
|
if(ABI_TYPE_MAIN.includes(id)) {
|
|
this.attrs.set(id, Math.floor(val * ratio * HERO_CE_RATIO * HERO_CE_RATIO));
|
|
} else {
|
|
this.attrs.set(id, Math.floor(val * HERO_CE_RATIO * HERO_CE_RATIO));
|
|
}
|
|
}
|
|
}
|
|
|
|
public setByMap( attributes: Map<number, number>, ratio: number = 1 ) {
|
|
for(let [id, val] of attributes) {
|
|
if(ABI_TYPE_MAIN.includes(id)) {
|
|
this.attrs.set(id, Math.floor(val * ratio * HERO_CE_RATIO * HERO_CE_RATIO));
|
|
} else {
|
|
this.attrs.set(id, Math.floor(val * HERO_CE_RATIO * HERO_CE_RATIO));
|
|
}
|
|
}
|
|
}
|
|
|
|
private calAttrValue(roleFix: number = 0, roleRatio: number = 0, heroBase: number = 0, heroFix: number = 0, heroRatio: number = 0, heroEquip: number = 0) {
|
|
return (heroFix + heroEquip + roleFix) * HERO_CE_RATIO + heroBase * ( HERO_CE_RATIO + heroRatio + roleRatio );
|
|
}
|
|
|
|
private getRealAttrToMap() {
|
|
let newMap = new Map<number, number>();
|
|
for(let [id, val] of this.attrs) {
|
|
if(ABI_TYPE_MAIN.includes(id)) { // 主属性
|
|
newMap.set(id, val / HERO_CE_RATIO / HERO_CE_RATIO);
|
|
} else {
|
|
newMap.set(id, val / HERO_SUB_ATTR_RATIO / HERO_CE_RATIO / HERO_CE_RATIO);
|
|
}
|
|
}
|
|
return newMap;
|
|
}
|
|
|
|
private getReduceAttrMap() {
|
|
let newMap = new Map<number, number>();
|
|
for(let [id, val] of this.attrs) {
|
|
newMap.set(id, reduceCe(val));
|
|
}
|
|
return newMap
|
|
}
|
|
|
|
public getReduceAttributes() {
|
|
let attrs = new Attribute();
|
|
attrs.setByMap(this.getReduceAttrMap());
|
|
return attrs;
|
|
}
|
|
|
|
public getReduceAttributesToArr() {
|
|
let arr: {id: number, val: number}[] = [];
|
|
for(let [id, val] of this.getReduceAttrMap()) {
|
|
arr.push({ id, val });
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
public getReduceAttributesToString() {
|
|
let arr = this.getReduceAttributesToArr();
|
|
return arr.map(cur => `${cur.id}&${cur.val}`).join('|');
|
|
}
|
|
|
|
public getReduceMainAttributes() {
|
|
let attribute = this.getReduceAttributes();
|
|
return attribute.getMainAttr();
|
|
}
|
|
|
|
// 战力计算
|
|
public calCe() {
|
|
let attrMap = this.getRealAttrToMap();
|
|
let attrs = new Attribute();
|
|
attrs.setByMap(attrMap);
|
|
|
|
let { hp, atk, def, mdef, cri, flee, damageIncrease, damageDecrease, damageCri } = attrs;
|
|
|
|
let putHit = CE_CONST.PUT_HIT / HERO_SUB_ATTR_RATIO;
|
|
let putAntCri = CE_CONST.PUT_ANT_CRI / HERO_SUB_ATTR_RATIO;
|
|
|
|
let hitRate = CE_CONST.HIT_RATE_BASE + putHit/2 - flee; // 命中率
|
|
if(hitRate > CE_CONST.HIT_RATE_MAX) hitRate = CE_CONST.HIT_RATE_MAX;
|
|
if(hitRate < CE_CONST.HIT_RATE_MIN) hitRate = CE_CONST.HIT_RATE_MIN;
|
|
let fleeRate = 1 - hitRate; // 格挡率
|
|
|
|
let criRate = CE_CONST.CRI_RATE_BASE + cri - putAntCri/2;
|
|
if(criRate > CE_CONST.CRI_RATE_MAX) criRate = CE_CONST.CRI_RATE_MAX;
|
|
if(criRate < CE_CONST.CRI_RATE_MIN) criRate = CE_CONST.CRI_RATE_MIN;
|
|
|
|
let criValue = CE_CONST.CRI_VALUE_BASE + damageCri;
|
|
|
|
let validHp = hp + (def + mdef) * 0.5 / ((1 - fleeRate * CE_CONST.FLEE_VALUE) * (1 - damageDecrease)); // 有效生命
|
|
let validAtk = atk * hitRate * ( 1 + criRate * criValue) * ( 1 + damageIncrease); // 有效输出
|
|
let ce = Math.floor(validHp * validAtk * HERO_CE_RATIO * HERO_CE_RATIO / 1000);
|
|
return ce > 0? ce: 1;
|
|
}
|
|
|
|
public calCelAndReduce() {
|
|
return Math.floor(this.calCe() / HERO_CE_RATIO / HERO_CE_RATIO);
|
|
}
|
|
}
|
|
|
|
export class Attribute {
|
|
hp: number = 0;
|
|
atk: number = 0;
|
|
def: number = 0;
|
|
mdef: number = 0;
|
|
speed: number = 0;
|
|
hit: number = 0;
|
|
cri: number = 0;
|
|
flee: number = 0;
|
|
antCri: number = 0;
|
|
damageIncrease: number = 0;
|
|
damageDecrease: number = 0;
|
|
defIngnore: number = 0;
|
|
bloodSuck: number = 0;
|
|
ap: number = 0;
|
|
damageCri: number = 0;
|
|
physicaldamageInc: number = 0;
|
|
magicdamageInc: number = 0;
|
|
physicaldamageDec: number = 0;
|
|
magicdamageDec: number = 0;
|
|
treatmentInc: number = 0;
|
|
treatmentDec: number = 0;
|
|
acceptTreatmentInc: number = 0;
|
|
acceptTreatmentDec: number = 0;
|
|
bloodRebound: number = 0;
|
|
strikeBack: number = 0;
|
|
|
|
setByMap( attributes: Map<number, number> ) {
|
|
for(let [id, val] of attributes) {
|
|
let attrName = getAtrrNameById(id);
|
|
if(attrName in this) this[attrName] = val;
|
|
}
|
|
}
|
|
|
|
setByStr(str: string) { // id&val|...
|
|
let arr = decodeArrayListStr(str);
|
|
for(let [id, val] of arr) {
|
|
let attrName = getAtrrNameById(parseInt(id));
|
|
if(attrName in this) this[attrName] = parseInt(val);
|
|
}
|
|
}
|
|
|
|
getMainAttr() {
|
|
return {
|
|
hp: this.hp,
|
|
atk: this.atk,
|
|
def: this.def,
|
|
mdef: this.mdef
|
|
}
|
|
}
|
|
} |