mirror of
				https://github.com/unanmed/HumanBreak.git
				synced 2025-11-04 15:12:58 +08:00 
			
		
		
		
	伤害计算函数
This commit is contained in:
		
							parent
							
								
									f96ce0f8b0
								
							
						
					
					
						commit
						b72bf33815
					
				@ -5,7 +5,7 @@ import {
 | 
				
			|||||||
    ServerResponse,
 | 
					    ServerResponse,
 | 
				
			||||||
    createServer as http
 | 
					    createServer as http
 | 
				
			||||||
} from 'http';
 | 
					} from 'http';
 | 
				
			||||||
import { isNil, some } from 'lodash-es';
 | 
					import { isNil } from 'lodash-es';
 | 
				
			||||||
import config from '../mota.config.js';
 | 
					import config from '../mota.config.js';
 | 
				
			||||||
import fs from 'fs-extra';
 | 
					import fs from 'fs-extra';
 | 
				
			||||||
import { resolve, basename } from 'path';
 | 
					import { resolve, basename } from 'path';
 | 
				
			||||||
 | 
				
			|||||||
@ -20,10 +20,17 @@ interface EnemyInfo {
 | 
				
			|||||||
    defBuff: number;
 | 
					    defBuff: number;
 | 
				
			||||||
    hpBuff: number;
 | 
					    hpBuff: number;
 | 
				
			||||||
    together: number;
 | 
					    together: number;
 | 
				
			||||||
 | 
					    enemy: Enemy;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface DamageInfo {
 | 
					interface DamageInfo {
 | 
				
			||||||
    damage: number;
 | 
					    damage: number;
 | 
				
			||||||
 | 
					    /** 从勇士位置指向怪物的方向 */
 | 
				
			||||||
 | 
					    dir: Dir | 'none';
 | 
				
			||||||
 | 
					    x?: number;
 | 
				
			||||||
 | 
					    y?: number;
 | 
				
			||||||
 | 
					    /** 自动切换技能时使用的技能 */
 | 
				
			||||||
 | 
					    skill?: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type HaloFn = (info: EnemyInfo, enemy: Enemy) => void;
 | 
					type HaloFn = (info: EnemyInfo, enemy: Enemy) => void;
 | 
				
			||||||
@ -53,6 +60,8 @@ export class EnemyCollection implements RangeCollection<DamageEnemy> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    calDamage(noCache: boolean = false) {}
 | 
					    calDamage(noCache: boolean = false) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    calMapDamage(noCache: boolean = false) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 向怪物施加光环
 | 
					     * 向怪物施加光环
 | 
				
			||||||
     * @param type 光环的范围类型
 | 
					     * @param type 光环的范围类型
 | 
				
			||||||
@ -110,7 +119,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
 | 
				
			|||||||
    /** 是否需要计算属性 */
 | 
					    /** 是否需要计算属性 */
 | 
				
			||||||
    needCalculate: boolean = true;
 | 
					    needCalculate: boolean = true;
 | 
				
			||||||
    /** 怪物伤害 */
 | 
					    /** 怪物伤害 */
 | 
				
			||||||
    damage?: DamageInfo;
 | 
					    damage?: DamageInfo[];
 | 
				
			||||||
    /** 是否需要计算伤害 */
 | 
					    /** 是否需要计算伤害 */
 | 
				
			||||||
    needCalDamage: boolean = true;
 | 
					    needCalDamage: boolean = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -137,7 +146,8 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
 | 
				
			|||||||
            atkBuff: 0,
 | 
					            atkBuff: 0,
 | 
				
			||||||
            defBuff: 0,
 | 
					            defBuff: 0,
 | 
				
			||||||
            hpBuff: 0,
 | 
					            hpBuff: 0,
 | 
				
			||||||
            together: 0
 | 
					            together: 0,
 | 
				
			||||||
 | 
					            enemy: this.enemy
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        this.needCalculate = true;
 | 
					        this.needCalculate = true;
 | 
				
			||||||
        this.needCalDamage = 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!;
 | 
					        if (!this.needCalDamage) return this.damage!;
 | 
				
			||||||
        const info = this.getRealInfo();
 | 
					        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取
 | 
					 * 计算伤害时会用到的勇士属性,攻击防御,其余的不会有buff加成,直接从core.status.hero取
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const realStatus: (keyof HeroStatus)[] = ['atk', 'def'];
 | 
					const realStatus: (keyof HeroStatus)[] = ['atk', 'def'];
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 主动技能列表
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const skills = [
 | 
				
			||||||
 | 
					    ['bladeOn', 'blade'],
 | 
				
			||||||
 | 
					    ['shieldOn', 'shield']
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 获取需要计算怪物伤害的方向
 | 
					 * 获取需要计算怪物伤害的方向
 | 
				
			||||||
@ -308,32 +372,26 @@ const realStatus: (keyof HeroStatus)[] = ['atk', 'def'];
 | 
				
			|||||||
 * @param floorId 怪物所在楼层
 | 
					 * @param floorId 怪物所在楼层
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export function getNeedCalDir(
 | 
					export function getNeedCalDir(
 | 
				
			||||||
    x: number,
 | 
					    x?: number,
 | 
				
			||||||
    y: number,
 | 
					    y?: number,
 | 
				
			||||||
    floorId: FloorIds,
 | 
					    floorId: FloorIds = core.status.floorId,
 | 
				
			||||||
    hero: Partial<HeroStatus> = core.status.hero
 | 
					    hero: Partial<HeroStatus> = core.status.hero
 | 
				
			||||||
): [Dir | 'none', Partial<HeroStatus>][] {
 | 
					): (Dir | 'none')[] {
 | 
				
			||||||
    // 第一章或序章,用不到这个函数
 | 
					    // 第一章或序章,或者没有指定怪物位置,或者没开自动定位,用不到这个函数
 | 
				
			||||||
    if (flags.chapter < 2) {
 | 
					    if (flags.chapter < 2 || !has(x) || !has(y)) {
 | 
				
			||||||
        return [['none', getHeroStatusOf(hero, realStatus, x, y, floorId)]];
 | 
					        return ['none'];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 如果指定了勇士坐标
 | 
					    // 如果指定了勇士坐标
 | 
				
			||||||
    if (has(hero.x) && has(hero.y)) {
 | 
					    if (has(hero.x) && has(hero.y)) {
 | 
				
			||||||
        const { x, y, floorId } = hero;
 | 
					        return ['none'];
 | 
				
			||||||
        if (has(floorId)) {
 | 
					 | 
				
			||||||
            return [['none', getHeroStatusOf(hero, realStatus, x, y, floorId)]];
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            return [['none', getHeroStatusOf(hero, realStatus, x, y, floorId)]];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const needMap: Dir[] = ['left', 'down', 'right', 'up'];
 | 
					    const needMap: Dir[] = ['left', 'down', 'right', 'up'];
 | 
				
			||||||
    const { width, height } = core.status.maps[floorId];
 | 
					    const { width, height } = core.status.maps[floorId];
 | 
				
			||||||
    const blocks = core.getMapBlocksObj(floorId);
 | 
					    const blocks = core.getMapBlocksObj(floorId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return needMap
 | 
					    return needMap.filter(v => {
 | 
				
			||||||
        .filter(v => {
 | 
					 | 
				
			||||||
        const [tx, ty] = ofDir(x, y, v);
 | 
					        const [tx, ty] = ofDir(x, y, v);
 | 
				
			||||||
        if (tx < 0 || ty < 0 || tx >= width || ty >= height) return false;
 | 
					        if (tx < 0 || ty < 0 || tx >= width || ty >= height) return false;
 | 
				
			||||||
        const index = `${tx},${ty}` as LocString;
 | 
					        const index = `${tx},${ty}` as LocString;
 | 
				
			||||||
@ -342,14 +400,93 @@ export function getNeedCalDir(
 | 
				
			|||||||
        if (!core.canMoveHero(tx, ty, backDir(v), floorId)) return false;
 | 
					        if (!core.canMoveHero(tx, ty, backDir(v), floorId)) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return true;
 | 
					        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 {
 | 
					declare global {
 | 
				
			||||||
    interface PluginDeclaration {
 | 
					    interface PluginDeclaration {
 | 
				
			||||||
        damage: {
 | 
					        damage: {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								src/types/enemy.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								src/types/enemy.d.ts
									
									
									
									
										vendored
									
									
								
							@ -20,7 +20,11 @@ type PartialNumbericEnemyProperty =
 | 
				
			|||||||
    | 'iceCore'
 | 
					    | 'iceCore'
 | 
				
			||||||
    | 'fireCore'
 | 
					    | 'fireCore'
 | 
				
			||||||
    | 'together'
 | 
					    | 'together'
 | 
				
			||||||
    | 'hungry';
 | 
					    | 'hungry'
 | 
				
			||||||
 | 
					    | 'ice'
 | 
				
			||||||
 | 
					    | 'crit'
 | 
				
			||||||
 | 
					    | 'courage'
 | 
				
			||||||
 | 
					    | 'charge';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type BooleanEnemyProperty =
 | 
					type BooleanEnemyProperty =
 | 
				
			||||||
    | 'zoneSquare'
 | 
					    | 'zoneSquare'
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user