refactor: 怪物特殊属性适应新接口

This commit is contained in:
unanmed 2026-10-12 17:05:58 +08:00
parent 80d3a21ba1
commit c1ebd25892
6 changed files with 157 additions and 64 deletions

View File

@ -17,21 +17,21 @@ import {
IReadonlyEnemyHandler
} from '@user/data-system';
import { IReadonlyEnemy, ISpecial } from '@user/data-base';
import { ISpecial23Value } from './special';
import { ISpecial23Value, ISpecial26Value } from './special';
import { IHeroAttr, IEnemyAttr } from '@user/data-common';
const FULL_RANGE = new FullRange();
const RECT_RANGE = new RectRange();
const MANHATTAN_RANGE = new ManhattanRange();
//#region 25-光环
//#region 23-光环
export class CommonAuraConverter implements IAuraConverter<
IEnemyAttr,
IHeroAttr
> {
shouldConvert(special: ISpecial<any>): boolean {
return special.code === 25;
return special.code === 23;
}
convert(
@ -47,7 +47,7 @@ export class CommonAura implements IEnemyAuraView<
IRectRangeParam | IManhattanRangeParam | void,
ISpecial23Value
> {
readonly priority: number = 25;
readonly priority: number = 10;
readonly couldApplyBase: boolean = true;
readonly couldApplySpecial: boolean = false;
readonly range: IRange<IRectRangeParam | IManhattanRangeParam | void>;
@ -63,30 +63,30 @@ export class CommonAura implements IEnemyAuraView<
private createRange(): IRange<
IRectRangeParam | IManhattanRangeParam | void
> {
const { range: haloRange, square: haloSquare } = this.special.value;
if (haloRange <= 0) {
const { range, square } = this.special.value;
if (range <= 0) {
return FULL_RANGE;
}
return haloSquare ? RECT_RANGE : MANHATTAN_RANGE;
return square ? RECT_RANGE : MANHATTAN_RANGE;
}
getRangeParam(): IRectRangeParam | IManhattanRangeParam | void {
const { range: haloRange, square: haloSquare } = this.special.value;
if (haloRange <= 0) {
const { range, square } = this.special.value;
if (range <= 0) {
return undefined;
}
if (haloSquare) {
if (square) {
return {
x: this.locator.x - haloRange,
y: this.locator.y - haloRange,
w: haloRange * 2 + 1,
h: haloRange * 2 + 1
x: this.locator.x - range,
y: this.locator.y - range,
w: range * 2 + 1,
h: range * 2 + 1
};
}
return {
cx: this.locator.x,
cy: this.locator.y,
radius: haloRange
radius: range
};
}
@ -120,14 +120,14 @@ export class CommonAura implements IEnemyAuraView<
//#endregion
//#region 26-支援
//#region 24-支援
export class GuardAuraConverter implements IAuraConverter<
IEnemyAttr,
IHeroAttr
> {
shouldConvert(special: ISpecial<any>): boolean {
return special.code === 26;
return special.code === 24;
}
convert(
@ -144,7 +144,7 @@ export class GuardAura implements IEnemyAuraView<
IRectRangeParam,
void
> {
readonly priority: number = 26;
readonly priority: number = 5;
readonly couldApplyBase: boolean = true;
readonly couldApplySpecial: boolean = false;
readonly range: IRange<IRectRangeParam> = RECT_RANGE;
@ -184,3 +184,118 @@ export class GuardAura implements IEnemyAuraView<
}
//#endregion
//#region 26-特殊光环
export class SpecialAuraConverter implements IAuraConverter<
IEnemyAttr,
IHeroAttr
> {
shouldConvert(special: ISpecial<any>): boolean {
return special.code === 26;
}
convert(
special: ISpecial<ISpecial26Value>,
handler: IReadonlyEnemyHandler<IEnemyAttr, IHeroAttr>
): SpecialAura {
return new SpecialAura(handler.enemy, special, handler.locator);
}
}
export class SpecialAuraModifier implements IEnemySpecialModifier<IEnemyAttr> {
constructor(readonly special: ISpecial<ISpecial26Value>) {}
add(handler: IReadonlyEnemyHandler<IEnemyAttr, any>): ISpecial<any>[] {
const manager = handler.state.enemyManager;
const list: ISpecial<any>[] = [];
for (const [code, param] of this.special.value.specials) {
if (handler.enemy.hasSpecial(code)) continue;
const sp = manager.getSpecial(code)?.();
if (!sp) continue;
sp.setValue(param);
list.push(sp);
}
return list;
}
delete(): ISpecial<any>[] {
// 特殊光环不删除特殊属性
return [];
}
modify(
_handler: IEnemyHandler<IEnemyAttr, any>,
special: ISpecial<any>
): boolean {
const sp = this.special.value.specials.find(v => v[0] === special.code);
if (!sp) return false;
const param = sp[1];
if (typeof param !== 'number') return false;
if (this.special.value.mulAdd) {
special.setValue(special.value * param);
} else {
special.setValue(special.value + param);
}
return true;
}
}
export class SpecialAura implements IEnemyAuraView<
IEnemyAttr,
IRectRangeParam | IManhattanRangeParam | void,
ISpecial26Value
> {
readonly priority: number = 20;
readonly couldApplyBase: boolean = true;
readonly couldApplySpecial: boolean = false;
readonly range: IRange<IRectRangeParam | IManhattanRangeParam | void>;
constructor(
readonly enemy: IReadonlyEnemy<IEnemyAttr>,
readonly special: ISpecial<ISpecial26Value>,
readonly locator: ITileLocator
) {
this.range = this.createRange();
}
private createRange(): IRange<
IRectRangeParam | IManhattanRangeParam | void
> {
const { range, square } = this.special.value;
if (range <= 0) {
return FULL_RANGE;
}
return square ? RECT_RANGE : MANHATTAN_RANGE;
}
getRangeParam(): IRectRangeParam | IManhattanRangeParam | void {
const { range, square } = this.special.value;
if (range <= 0) {
return undefined;
}
if (square) {
return {
x: this.locator.x - range,
y: this.locator.y - range,
w: range * 2 + 1,
h: range * 2 + 1
};
}
return {
cx: this.locator.x,
cy: this.locator.y,
radius: range
};
}
apply(): void {
// 特殊光环不修改基本属性
}
applySpecial(): IEnemySpecialModifier<IEnemyAttr> | null {
return new SpecialAuraModifier(this.special);
}
}
//#endregion

View File

@ -31,7 +31,7 @@ export class MainDamageCalculator implements IDamageCalculator<
// 无敌
if (
enemy.hasSpecial(20) &&
(handler.state.hero.items.getItemState('cross')?.count ?? 0) < 1
handler.state.hero.items.itemCount('cross') < 1
) {
return { damage: Infinity, turn: 0 };
}
@ -51,7 +51,7 @@ export class MainDamageCalculator implements IDamageCalculator<
}
// 吸血
const vampire = enemy.getSpecial<ISpecial9Value>(11);
const vampire = enemy.getSpecial<ISpecial9Value>(9);
if (vampire) {
const value = (vampire.value.vampire / 100) * hp;
damage += value;
@ -68,11 +68,7 @@ export class MainDamageCalculator implements IDamageCalculator<
enemyPerDamage = monAtk - def;
}
// 连击
if (enemy.hasSpecial(4)) enemyPerDamage *= 2;
if (enemy.hasSpecial(5)) enemyPerDamage *= 3;
const multiHit = enemy.getSpecial<number>(6);
const multiHit = enemy.getSpecial<number>(4);
if (multiHit) {
enemyPerDamage *= multiHit.value;
}
@ -113,20 +109,20 @@ export class MainDamageCalculator implements IDamageCalculator<
}
// 破甲
const breakArmor = enemy.getSpecial<number>(7);
const breakArmor = enemy.getSpecial<number>(5);
if (breakArmor) {
damage += (breakArmor.value / 100) * def;
}
// 反击
const counterAttack = enemy.getSpecial<number>(8);
const counterAttack = enemy.getSpecial<number>(6);
if (counterAttack) {
// 反击是每回合生效,因此加到 enemyPerDamage 上
enemyPerDamage += (counterAttack.value / 100) * atk;
}
// 净化
const purify = enemy.getSpecial<number>(9);
const purify = enemy.getSpecial<number>(7);
if (purify) {
damage += purify.value * mdef;
}
@ -148,13 +144,13 @@ export class MainDamageCalculator implements IDamageCalculator<
}
// 固伤,无法被魔防减伤
const fixedDamage = enemy.getSpecial<number>(22);
const fixedDamage = enemy.getSpecial<number>(20);
if (fixedDamage) {
damage += fixedDamage.value;
}
// 仇恨,无法被魔防减伤
if (enemy.hasSpecial(17)) {
if (enemy.hasSpecial(15)) {
damage += handler.state.flags.getFieldValueDefaults('hatred', 0);
}

View File

@ -12,14 +12,14 @@ export class MainEnemyFinalEffect implements IEnemyFinalEffect<
const heroAtk = handler.hero.getFinalAttribute('atk');
const heroDef = handler.hero.getFinalAttribute('def');
// 3-坚固
// 3 - 坚固
if (enemy.hasSpecial(3)) {
const target = Math.max(enemy.getAttribute('def'), heroAtk - 1);
enemy.setAttribute('def', target);
}
// 10-模仿
if (enemy.hasSpecial(10)) {
// 8 - 模仿
if (enemy.hasSpecial(8)) {
enemy.setAttribute('atk', heroAtk);
enemy.setAttribute('def', heroDef);
}

View File

@ -1,19 +0,0 @@
import { IEnemyLegacyBridge } from '@user/data-base';
import { IEnemyAttr } from '@user/data-common';
export class EnemyLegacyBridge implements IEnemyLegacyBridge<IEnemyAttr> {
fromLegacyEnemy(
enemy: Enemy,
defaultAttr: Partial<IEnemyAttr>
): IEnemyAttr {
return {
hp: enemy.hp ?? defaultAttr.hp ?? 0,
atk: enemy.atk ?? defaultAttr.atk ?? 0,
def: enemy.def ?? defaultAttr.def ?? 0,
money: enemy.money ?? defaultAttr.money ?? 0,
exp: enemy.exp ?? defaultAttr.exp ?? 0,
point: enemy.point ?? defaultAttr.point ?? 0,
guard: defaultAttr.guard ?? new Set()
};
}
}

View File

@ -71,13 +71,14 @@ export interface ISpecial26Value {
* 注册所有怪物特殊属性到 enemyManager
*
* 属性实现位置一览('./'表示当前文件夹 '../'表示上一级文件夹):
* 1. 调参类属性 | 仅影响战斗过程的属性:./damage.ts calDamageWithTurn 函数
* 2. 地图伤害:./damage.ts DamageEnemy.calMapDamage 方法
* 3. 光环属性:./damage.ts DamageEnemy.provideHalo 方法
* 4. 中毒的每步效果:../state/move.ts HeroMover.onStepEnd 方法
* 5. 中毒的瞬移效果:还在脚本编辑的 moveDirectly
* 6. 衰弱效果:../state/hero.ts getHeroStatusOf 方法
* 7. 重生属性:还在脚本编辑的 changingFloor
* 1. 调参类属性 | 仅影响战斗过程的属性:./calculator.ts, MainDamageCalculator.calculate 方法
* 2. 坚固、模仿等仅影响自身基础属性的属性:./final.ts, MainEnemyFinalEffect.apply 方法
* 3. 地图伤害:./mapDamage.ts,具体写法参考文档
* 4. 光环属性:./aura.ts 具体写法参考文档
* 5. 中毒的每步效果:在插件系统中,目前暂未实装
* 6. 中毒的瞬移效果:在插件系统中,目前暂未实装
* 7. 衰弱效果:在插件系统中,目前尚未实装
* 8. 重生属性:在插件系统中,目前尚未实装
*/
export function createSpecials(
state: IStateSystem

View File

@ -99,19 +99,19 @@ export interface IComputingEnemyView<TEnemy> extends IEnemyView<TEnemy> {
export interface IEnemySpecialModifier<TEnemy> {
/**
* 获取要添加到指定怪物身上的特殊属性
* @param handler 信息对象
* @param handler 目标怪物信息对象
*/
add(handler: IReadonlyEnemyHandler<TEnemy, any>): ISpecial<any>[];
/**
* 获取制定怪物身上要删除的特殊属性
* @param handler 信息对象
* @param handler 目标怪物信息对象
*/
delete(handler: IReadonlyEnemyHandler<TEnemy, any>): ISpecial<any>[];
/**
* 修改一个怪物的特殊属性,如果真正进行了修改则返回 true,否则返回 false
* @param handler 信息对象
* @param handler 目标怪物信息对象
* @param special 要修改的怪物特殊属性
*/
modify(
@ -138,7 +138,7 @@ export interface IAuraView<TEnemy, TRange = any> {
/**
* 对指定怪物对象施加修饰器
* @param handler 信息对象
* @param handler 目标怪物信息对象
* @param baseEnemy 原始怪物对象,即未进行任何修改的怪物对象
*/
apply(
@ -148,7 +148,7 @@ export interface IAuraView<TEnemy, TRange = any> {
/**
* 对指定怪物对象添加特殊属性修饰器
* @param handler 信息对象
* @param handler 目标怪物信息对象
* @param baseEnemy 原始怪物对象,即未进行任何修改的怪物对象
*/
applySpecial(