From 604c77f7c7fca6b27808ca97a038fdada3adcd0e Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Fri, 12 Jun 2026 22:55:08 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=80=AA=E7=89=A9=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=8B=93=E5=B1=95=E8=87=AA=20IStateBaseExtended?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data-state/src/enemy/calculator.ts | 2 +- .../data-state/src/enemy/mapDamage.ts | 2 +- .../data-system/src/combat/context.ts | 4 +- .../data-system/src/combat/damage.ts | 39 +++-- .../data-system/src/combat/mapDamage.ts | 6 +- packages-user/data-system/src/combat/types.ts | 156 +++++++++++++++--- prompt.md | 6 +- 7 files changed, 170 insertions(+), 45 deletions(-) diff --git a/packages-user/data-state/src/enemy/calculator.ts b/packages-user/data-state/src/enemy/calculator.ts index edd5bb5..35149d8 100644 --- a/packages-user/data-state/src/enemy/calculator.ts +++ b/packages-user/data-state/src/enemy/calculator.ts @@ -97,7 +97,7 @@ export class MainDamageCalculator implements IDamageCalculator< context: handler.context, locator, hero, - data: handler.data + state: handler.state }); turn += extraInfo.turn; damage += extraInfo.damage; diff --git a/packages-user/data-state/src/enemy/mapDamage.ts b/packages-user/data-state/src/enemy/mapDamage.ts index ca10d4f..4e876bb 100644 --- a/packages-user/data-state/src/enemy/mapDamage.ts +++ b/packages-user/data-state/src/enemy/mapDamage.ts @@ -311,7 +311,7 @@ export class MainMapDamageConverter implements IMapDamageConverter< const laser = enemy.getSpecial(24); if (laser) { - const face = handler.data.faceManager.get(FaceGroup.Dir4)!; + const face = handler.state.faceManager.get(FaceGroup.Dir4)!; views.push(new LaserDamageView(context, locator, laser, face)); } diff --git a/packages-user/data-system/src/combat/context.ts b/packages-user/data-system/src/combat/context.ts index af6746d..b102de9 100644 --- a/packages-user/data-system/src/combat/context.ts +++ b/packages-user/data-system/src/combat/context.ts @@ -100,7 +100,7 @@ export class EnemyContext implements IEnemyContext< width: number = 0; height: number = 0; - constructor(readonly dataState: IStateBase) {} + constructor(readonly state: IStateBase) {} resize(width: number, height: number): void { this.clear(); @@ -215,7 +215,7 @@ export class EnemyContext implements IEnemyContext< context: this, locator, hero: this.bindedHero!, - data: this.dataState + state: this.state }; } diff --git a/packages-user/data-system/src/combat/damage.ts b/packages-user/data-system/src/combat/damage.ts index 423ac6d..9b4fea7 100644 --- a/packages-user/data-system/src/combat/damage.ts +++ b/packages-user/data-system/src/combat/damage.ts @@ -9,7 +9,8 @@ import { IEnemyCritical, IEnemyDamageInfo, IReadonlyEnemyHandler, - IEnemyView + IEnemyView, + IEnemyDamageInfoBase } from './types'; import { IHeroAttribute, @@ -22,7 +23,7 @@ interface ICriticalSearchResult { /** 此临界点的属性值 */ readonly value: number; /** 此临界点的伤害信息 */ - readonly info: IEnemyDamageInfo; + readonly info: IEnemyDamageInfoBase; } export class DamageContext implements IDamageContext< @@ -34,14 +35,14 @@ export class DamageContext implements IDamageContext< /** 当前勇士属性 */ protected heroStatus: IReadonlyHeroAttribute | null; - readonly dataState: IStateBase; + readonly state: IStateBase; constructor( readonly context: IEnemyContext, calculator: IDamageCalculator | null = null, heroStatus: IReadonlyHeroAttribute | null = null ) { - this.dataState = context.dataState; + this.state = context.state; this.calculator = calculator; this.heroStatus = heroStatus; } @@ -62,11 +63,13 @@ export class DamageContext implements IDamageContext< context: this.context, locator, hero, - data: this.dataState + state: this.state }; } - getDamageInfo(enemy: IEnemyView): IEnemyDamageInfo | null { + getDamageInfo( + enemy: IEnemyView + ): IEnemyDamageInfo | null { if (!this.heroStatus) { logger.warn(107); return null; @@ -82,12 +85,15 @@ export class DamageContext implements IDamageContext< const computed = enemy.getComputedEnemy(); const handler = this.createReadonlyHandler(computed, locator, hero); - return this.calculator.calculate(handler); + return { + handler, + ...this.calculator.calculate(handler) + }; } getDamageInfoByComputed( enemy: IReadonlyEnemy - ): IEnemyDamageInfo | null { + ): IEnemyDamageInfo | null { if (!this.heroStatus) { logger.warn(107); return null; @@ -105,7 +111,10 @@ export class DamageContext implements IDamageContext< const handler = this.createReadonlyHandler(enemy, locator, hero); - return this.calculator.calculate(handler); + return { + handler, + ...this.calculator.calculate(handler) + }; } *calculateCritical( @@ -224,8 +233,10 @@ export class DamageSystem implements IDamageSystem { /** 怪物伤害缓存 */ - private readonly cache: Map, IEnemyDamageInfo> = - new Map(); + private readonly cache: Map< + IEnemyView, + IEnemyDamageInfo + > = new Map(); constructor(context: IEnemyContext) { super(context); @@ -245,7 +256,9 @@ export class DamageSystem this.markAllDirty(); } - getDamageInfo(enemy: IEnemyView): IEnemyDamageInfo | null { + getDamageInfo( + enemy: IEnemyView + ): IEnemyDamageInfo | null { const cached = this.cache.get(enemy); if (cached) { return cached; @@ -260,7 +273,7 @@ export class DamageSystem getDamageInfoByComputed( enemy: IReadonlyEnemy - ): IEnemyDamageInfo | null { + ): IEnemyDamageInfo | null { const view = this.context.getViewByComputed(enemy); if (view) { const cached = this.cache.get(view); diff --git a/packages-user/data-system/src/combat/mapDamage.ts b/packages-user/data-system/src/combat/mapDamage.ts index 6cfb22d..6348e35 100644 --- a/packages-user/data-system/src/combat/mapDamage.ts +++ b/packages-user/data-system/src/combat/mapDamage.ts @@ -64,11 +64,11 @@ export class MapDamage implements IMapDamage { /** 坐标索引对象 */ private readonly indexer: ILocationHelper; - readonly dataState: IStateBase; + readonly state: IStateBase; constructor(readonly context: IEnemyContext) { this.indexer = context.indexer; - this.dataState = context.dataState; + this.state = context.state; } useConverter(converter: IMapDamageConverter): void { @@ -92,7 +92,7 @@ export class MapDamage implements IMapDamage { context: this.context, locator, hero, - data: this.context.dataState + state: this.state }; } diff --git a/packages-user/data-system/src/combat/types.ts b/packages-user/data-system/src/combat/types.ts index 171d58f..51671b2 100644 --- a/packages-user/data-system/src/combat/types.ts +++ b/packages-user/data-system/src/combat/types.ts @@ -1,11 +1,12 @@ -import { ITileLocator, IRange } from '@motajs/common'; +import { ITileLocator, IRange, IHookable, IHookBase } from '@motajs/common'; import { IEnemy, IReadonlyEnemy, ISpecial, IReadonlyHeroAttribute, IHeroAttribute, - IStateBase + IStateBase, + IStateBaseExtended } from '@user/data-base'; import { ILocationHelper } from '@user/data-common'; @@ -21,7 +22,7 @@ export interface IEnemyHandler { /** 勇士属性信息 */ readonly hero: IReadonlyHeroAttribute; /** 当前全局状态对象 */ - readonly data: IStateBase; + readonly state: IStateBase; } export interface IReadonlyEnemyHandler { @@ -34,7 +35,7 @@ export interface IReadonlyEnemyHandler { /** 勇士属性信息 */ readonly hero: IReadonlyHeroAttribute; /** 当前全局状态对象 */ - readonly data: IStateBase; + readonly state: IStateBase; } //#endregion @@ -282,11 +283,9 @@ export interface IMapDamageReducer { ): Readonly; } -export interface IMapDamage { +export interface IMapDamage extends IStateBaseExtended { /** 当前绑定的怪物上下文 */ readonly context: IEnemyContext; - /** 地图伤害系统绑定的全局状态对象 */ - readonly dataState: IStateBase; /** * 设置地图伤害转换器,并基于当前上下文重建所有地图伤害视图 @@ -356,13 +355,18 @@ export interface IMapDamage { //#region 伤害系统 -export interface IEnemyDamageInfo { +export interface IEnemyDamageInfoBase { /** 战斗伤害值 */ readonly damage: number; /** 战斗回合数 */ readonly turn: number; } +export interface IEnemyDamageInfo extends IEnemyDamageInfoBase { + /** 信息对象 */ + readonly handler: IReadonlyEnemyHandler; +} + export interface IEnemyCritical { /** 此临界点中指定勇士属性的值 */ readonly nextValue: number; @@ -371,9 +375,9 @@ export interface IEnemyCritical { /** 此临界点中指定勇士数值的值与当前值的差,即 `nextValue - baseValue` */ readonly nextDiff: number; /** 当前状态下怪物的伤害信息 */ - readonly baseInfo: IEnemyDamageInfo; + readonly baseInfo: IEnemyDamageInfoBase; /** 此临界点下怪物的伤害信息 */ - readonly info: IEnemyDamageInfo; + readonly info: IEnemyDamageInfoBase; /** 此临界点的伤害值与当前伤害值的差 */ readonly damageDiff: number; } @@ -387,7 +391,9 @@ export interface IDamageCalculator { * 计算战斗伤害信息 * @param handler 信息对象 */ - calculate(handler: IReadonlyEnemyHandler): IEnemyDamageInfo; + calculate( + handler: IReadonlyEnemyHandler + ): IEnemyDamageInfoBase; /** * 获取临界计算的上界 @@ -400,15 +406,14 @@ export interface IDamageCalculator { ): number; } -export interface IDamageContext { - /** 伤害上下文所属的全局状态对象 */ - readonly dataState: IStateBase; - +export interface IDamageContext extends IStateBaseExtended { /** * 获取战斗伤害信息 * @param enemy 怪物视图 */ - getDamageInfo(enemy: IEnemyView): IEnemyDamageInfo | null; + getDamageInfo( + enemy: IEnemyView + ): IEnemyDamageInfo | null; /** * 根据怪物对象获取战斗伤害信息 @@ -416,7 +421,7 @@ export interface IDamageContext { */ getDamageInfoByComputed( enemy: IReadonlyEnemy - ): IEnemyDamageInfo | null; + ): IEnemyDamageInfo | null; /** * 计算怪物在指定勇士属性下的临界 @@ -483,15 +488,16 @@ export interface IDamageSystem extends IDamageContext< //#region 上下文 -export interface IReadonlyEnemyContext { +export interface IReadonlyEnemyContext< + TEnemy, + THero +> extends IStateBaseExtended { /** 怪物上下文宽度 */ readonly width: number; /** 怪物上下文高度 */ readonly height: number; /** 此上下文使用的索引对象 */ readonly indexer: ILocationHelper; - /** 当前怪物上下文绑定的全局状态对象 */ - readonly dataState: IStateBase; /** * 获取当前绑定的勇士属性对象 @@ -567,8 +573,6 @@ export interface IEnemyContext extends IReadonlyEnemyContext< readonly height: number; /** 此上下文使用的索引对象 */ readonly indexer: ILocationHelper; - /** 当前怪物上下文绑定的全局状态对象 */ - readonly dataState: IStateBase; /** * 调整上下文尺寸,并清空当前上下文中的所有怪物与状态 @@ -724,3 +728,111 @@ export interface IEnemyContext extends IReadonlyEnemyContext< } //#endregion + +//#region 战斗流程 + +export interface ICombatFlowHandler { + /** 战斗的怪物是否在地图上 */ + readonly onMap: boolean; + /** 可修改勇士对象 */ + readonly hero: IHeroAttribute; + /** 可修改怪物对象 */ + readonly enemy: IEnemy; + /** 怪物上下文 */ + readonly context: IEnemyContext; + /** 怪物位置 */ + readonly locator: ITileLocator; + /** 全局状态对象 */ + readonly state: IStateBase; +} + +export interface ICombatFlowHook extends IHookBase { + /** + * 战前脚本 + * @param info 战斗伤害信息 + */ + onBeforeCombat?(info: IEnemyDamageInfo): Promise; + + /** + * 战后脚本 + * @param info 战斗伤害信息 + */ + onAfterCombat?(info: IEnemyDamageInfo): Promise; +} + +export interface ICombatScript { + /** 此脚本的优先级 */ + readonly priority: number; + + /** + * 战前执行的内容,返回 `false` 会立刻停止后续战前内容的执行,并放弃此次战斗 + * @param info 战斗伤害信息 + * @param handler 信息对象 + */ + before( + info: IEnemyDamageInfo, + handler: ICombatFlowHandler + ): Promise; + + /** + * 战后执行的内容 + * @param info 战斗伤害信息 + * @param handler 信息对象 + */ + after( + info: IEnemyDamageInfo, + handler: ICombatFlowHandler + ): Promise; +} + +export interface ICombatFlow + extends IHookable>, IStateBaseExtended { + /** 勇士属性对象 */ + readonly hero: IReadonlyHeroAttribute | null; + /** 怪物上下文对象 */ + readonly context: IReadonlyEnemyContext | null; + /** 伤害上下文 */ + readonly damage: IDamageContext | null; + + /** + * 绑定勇士属性对象 + * @param hero 勇士属性对象 + */ + bindHero(hero: IHeroAttribute | null): void; + + /** + * 绑定怪物上下文 + * @param context 怪物上下文 + */ + bindContext(context: IReadonlyEnemyContext | null): void; + + /** + * 绑定伤害上下文 + * @param damage 伤害上下文 + */ + bindDamage(damage: IDamageContext | null): void; + + /** + * 与指定怪物战斗 + * @param enemy 怪物视图对象 + */ + battle( + enemy: IEnemyView + ): Promise | null>; + + /** + * 与指定怪物战斗 + * @param enemy 怪物对象 + */ + battleComputed( + enemy: IReadonlyEnemy + ): Promise | null>; + + /** + * 添加战前战后脚本 + * @param script 战前战后脚本 + */ + addCombatScript(script: ICombatScript): void; +} + +//#endregion diff --git a/prompt.md b/prompt.md index 66eddf0..30330d9 100644 --- a/prompt.md +++ b/prompt.md @@ -34,7 +34,7 @@ ## 示例文档 -对于新增接口/彻底性地重构接口,大致按照以下格式编写,其余需求按照自己的理解去写即可。如某部分需要详细描述,可单独开设标题;若某个接口内容较多,也可以在文档中为其单独开一个章节进行讲述。我会使用引用块的形式在文档中提出建议或回答。Markdown 文档不需要刻意换行,我的编辑器有自动换行功能,正常写没有问题。 +对于新增接口/彻底性地重构接口,按照以下格式编写,其余需求按照自己的理解去写即可。如某部分需要详细描述,可单独开设标题;若某个接口内容较多,也可以在文档中为其单独开一个章节进行讲述。我会使用引用块的形式在文档中提出建议或回答。Markdown 文档不需要刻意换行,我的编辑器有自动换行功能,正常写没有问题。文档保证简洁,不要过于啰嗦,但必须包含所有的必要信息,控制在 100-250 行以内。 ```md # 需求综述 @@ -43,7 +43,7 @@ # 接口设计与预期 -这是相当重要的一章。需要按接口逐一列出其方法与成员,分析每个成员和方法的预期使用频率(高 / 中 / 低)并说明判断依据;对于中频和高频成员,还需列出至少一个典型使用场景。 +这是相当重要的一章。需要按接口逐一列出其方法与成员,分析每个成员和方法的预期使用频率(高 / 中 / 低)并说明判断依据;对于中频和高频成员,还需列出至少一个典型使用场景。必须认真分析频率,想明白**用户**调用的频率,而不是**引擎**调用的频率,比如战斗函数在引擎中可能是中频,但是对用户来说,用户一般会使用系统默认行为来战斗,而**不会**自己调用,因此属于低频。 **命名长度原则**:频率越高,成员名应越短。高频成员以一个单词为宜,最多不超过两个单词;中频成员不超过三个单词;低频成员可以稍长,但不宜过长。 @@ -68,7 +68,7 @@ ## 可能风险 -在任何时候,需要修改已有接口时,必须在文档中写明修改这一接口的风险。这里的已有接口指的是本次设计新增接口之外的接口,即所有已存在于代码中的接口。 +在任何时候,需要修改已有接口时,必须在文档中写明修改这一接口的风险。这里的已有接口指的是本次设计新增接口之外的接口,即所有已存在于代码中的接口。本章节**只写**关于修改已有接口可能导致的风险,**不写任何关于实现的风险**,关于实现的风险应该写到最后的问题节,而不是这里。 # 实现思路