伤害计算函数

This commit is contained in:
unanmed 2023-05-14 21:59:36 +08:00
parent f96ce0f8b0
commit b72bf33815
3 changed files with 174 additions and 33 deletions

View File

@ -5,7 +5,7 @@ import {
ServerResponse,
createServer as http
} from 'http';
import { isNil, some } from 'lodash-es';
import { isNil } from 'lodash-es';
import config from '../mota.config.js';
import fs from 'fs-extra';
import { resolve, basename } from 'path';

View File

@ -20,10 +20,17 @@ interface EnemyInfo {
defBuff: number;
hpBuff: number;
together: number;
enemy: Enemy;
}
interface DamageInfo {
damage: number;
/** 从勇士位置指向怪物的方向 */
dir: Dir | 'none';
x?: number;
y?: number;
/** 自动切换技能时使用的技能 */
skill?: number;
}
type HaloFn = (info: EnemyInfo, enemy: Enemy) => void;
@ -53,6 +60,8 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
calDamage(noCache: boolean = false) {}
calMapDamage(noCache: boolean = false) {}
/**
*
* @param type
@ -110,7 +119,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
/** 是否需要计算属性 */
needCalculate: boolean = true;
/** 怪物伤害 */
damage?: DamageInfo;
damage?: DamageInfo[];
/** 是否需要计算伤害 */
needCalDamage: boolean = true;
@ -137,7 +146,8 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
atkBuff: 0,
defBuff: 0,
hpBuff: 0,
together: 0
together: 0,
enemy: this.enemy
};
this.needCalculate = true;
this.needCalDamage = true;
@ -290,16 +300,70 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
/**
*
*/
calDamage() {
calDamage(hero: Partial<HeroStatus> = core.status.hero) {
if (!this.needCalDamage) return this.damage!;
const info = this.getRealInfo();
const dirs = getNeedCalDir(this.x, this.y, this.floorId, hero);
const damageCache: Record<string, number> = {};
return (this.damage = dirs.map(dir => {
const status = getHeroStatusOf(hero, realStatus);
let damage = calDamageWith(info, status) ?? Infinity;
let skill = -1;
if (flags.autoSkill) {
for (let i = 0; i < skills.length; i++) {
const [unlock, condition] = skills[i];
if (!flags[unlock]) continue;
flags[condition] = true;
const status = getHeroStatusOf(hero, realStatus);
const id = `${status.atk},${status.def}`;
const d =
id in damageCache
? damageCache[id]
: calDamageWith(info, status) ?? Infinity;
if (d < damage) {
damage = d;
skill = i;
}
flags[condition] = false;
damageCache[id] = d;
}
}
let x = this.x;
let y = this.y;
if (has(this.x) && has(this.y)) {
if (dir !== 'none') {
[x, y] = ofDir(this.x, this.y, dir);
}
}
return {
damage,
dir,
skill,
x,
y
};
}));
}
calMapDamage() {}
}
/**
* buff加成core.status.hero取
*/
const realStatus: (keyof HeroStatus)[] = ['atk', 'def'];
/**
*
*/
const skills = [
['bladeOn', 'blade'],
['shieldOn', 'shield']
];
/**
*
@ -308,32 +372,26 @@ const realStatus: (keyof HeroStatus)[] = ['atk', 'def'];
* @param floorId
*/
export function getNeedCalDir(
x: number,
y: number,
floorId: FloorIds,
x?: number,
y?: number,
floorId: FloorIds = core.status.floorId,
hero: Partial<HeroStatus> = core.status.hero
): [Dir | 'none', Partial<HeroStatus>][] {
// 第一章或序章,用不到这个函数
if (flags.chapter < 2) {
return [['none', getHeroStatusOf(hero, realStatus, x, y, floorId)]];
): (Dir | 'none')[] {
// 第一章或序章,或者没有指定怪物位置,或者没开自动定位,用不到这个函数
if (flags.chapter < 2 || !has(x) || !has(y)) {
return ['none'];
}
// 如果指定了勇士坐标
if (has(hero.x) && has(hero.y)) {
const { x, y, floorId } = hero;
if (has(floorId)) {
return [['none', getHeroStatusOf(hero, realStatus, x, y, floorId)]];
} else {
return [['none', getHeroStatusOf(hero, realStatus, x, y, floorId)]];
}
return ['none'];
}
const needMap: Dir[] = ['left', 'down', 'right', 'up'];
const { width, height } = core.status.maps[floorId];
const blocks = core.getMapBlocksObj(floorId);
return needMap
.filter(v => {
return needMap.filter(v => {
const [tx, ty] = ofDir(x, y, v);
if (tx < 0 || ty < 0 || tx >= width || ty >= height) return false;
const index = `${tx},${ty}` as LocString;
@ -342,14 +400,93 @@ export function getNeedCalDir(
if (!core.canMoveHero(tx, ty, backDir(v), floorId)) return false;
return true;
})
.map(v => {
const [tx, ty] = ofDir(x, y, v);
const status = getHeroStatusOf(hero, realStatus, tx, ty, floorId);
return [v, status];
});
}
/**
*
* @param info
* @param hero
*/
export function calDamageWith(
info: EnemyInfo,
hero: Partial<HeroStatus>
): number | null {
const { hp, hpmax, mana, mdef } = core.status.hero;
let { atk, def } = hero as HeroStatus;
const { hp: monHp, atk: monAtk, def: monDef, special, enemy } = info;
let damage = 0;
// 饥渴
if (special.includes(7)) {
atk *= 1 - enemy.hungry! / 100;
}
let heroPerDamage: number;
// 绝对防御
if (special.includes(9)) {
heroPerDamage = atk + mana - monDef;
if (heroPerDamage <= 0) return null;
} else {
heroPerDamage = atk - monDef;
if (heroPerDamage > 0) heroPerDamage += mana;
else return null;
}
let enemyPerDamage: number;
// 魔攻
if (special.includes(2) || special.includes(13)) {
enemyPerDamage = monAtk;
} else {
enemyPerDamage = monAtk - def;
if (enemyPerDamage < 0) enemyPerDamage = 0;
}
// 连击
if (special.includes(4)) enemyPerDamage *= 2;
if (special.includes(5)) enemyPerDamage *= 3;
if (special.includes(6)) enemyPerDamage *= enemy.n!;
// 霜冻
if (special.includes(20) && !core.hasEquip('I589')) {
heroPerDamage *= 1 - enemy.ice! / 100;
}
heroPerDamage *= 1 - info.damageDecline;
let turn = Math.ceil(monHp / heroPerDamage);
// 致命一击
if (special.includes(1)) {
const times = Math.floor(turn / 5);
damage += ((times * (enemy.crit! - 100)) / 100) * enemyPerDamage;
}
// 勇气之刃
if (turn > 1 && special.includes(10)) {
damage += (enemy.courage! / 100 - 1) * enemyPerDamage;
}
// 勇气冲锋
if (special.includes(11)) {
damage += (enemy.charge! / 100) * enemyPerDamage;
turn += 5;
}
damage += (turn - 1) * enemyPerDamage;
// 无上之盾
if (core.hasFlag('superSheild')) {
damage -= mdef / 10;
}
// 生命回复
damage -= hpmax * turn;
if (flags.hard === 1) damage *= 0.9;
return damage;
}
declare global {
interface PluginDeclaration {
damage: {

View File

@ -20,7 +20,11 @@ type PartialNumbericEnemyProperty =
| 'iceCore'
| 'fireCore'
| 'together'
| 'hungry';
| 'hungry'
| 'ice'
| 'crit'
| 'courage'
| 'charge';
type BooleanEnemyProperty =
| 'zoneSquare'