refactor: 战斗系统文件结构

This commit is contained in:
unanmed 2026-05-12 17:11:33 +08:00
parent 8ea0c12024
commit 0da19e1697
13 changed files with 863 additions and 805 deletions

View File

@ -0,0 +1,54 @@
# 怪物系统文件结构重构
**目的:** 使 `IEnemyHandler` 能持有 `IStateBase` 引用而不产生循环引用。
**循环根源:** `enemy/types.ts` 混写了两层接口,`data-base/src/types.ts` 经由 `./enemy` index 引入 `IEnemyManager`,导致无法反向引用。
## 接口归属
**`enemy/types.ts`Layer 1 — 存档/管理层,保留)**
只保留以下接口,其余全部迁出:
- `IEnemySaveState`、`IEnemyManagerSaveState`、`IEnemyComparer`
- `ISpecial`、`IReadonlyEnemy`、`IEnemy`
- `SpecialCreation`、`IEnemyLegacyBridge`、`IEnemyManager`
只允许引用 `@motajs/common`、`../common`,不得引用 `../types`
**`enemy/utils.ts`Layer 0 — 工具层,与实现类并列)**
`enemy/types.ts` 迁出以下接口(实现类 `MapLocIndexer` 已在此文件):
- `IMapLocHelper`、`IMapLocIndexer`
**`combat/types.ts`Layer 2 — 战斗/上下文层,现为空文件)**
`enemy/types.ts` 迁入以下接口:
- `IEnemyHandler`、`IReadonlyEnemyHandler`、`IEnemyView`
- `IEnemySpecialModifier`、`IAuraView`、`IEnemyAuraView`、`IAuraConverter`
- `IEnemySpecialQueryModifier`、`IEnemySpecialQueryEffect`、`IEnemyCommonQueryEffect`、`IEnemyFinalEffect`
- `IMapDamageInfoExtra`、`IMapDamageInfo`、`IMapDamageView`、`IMapDamageConverter`、`IMapDamageReducer`、`IMapDamage`
- `IEnemyDamageInfo`、`IEnemyCritical`、`CriticalableHeroStatus`、`IDamageCalculator`、`IDamageContext`、`IDamageSystem`
- `IEnemyContext`
需引用 `../enemy/types`Layer 1、`../enemy/utils`Layer 0、`../types``IStateBase`,现在无循环)。在 `IEnemyHandler``IReadonlyEnemyHandler` 中新增 `readonly state: IStateBase<TAttr, THero>`
## 文件修改清单
| 文件 | 操作 |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `combat/types.ts` | 迁入所有 Layer 2 接口;新增三条 import`../enemy/types`、`../enemy/utils`、`../types``IEnemyHandler` 系列加 `state` 字段 |
| `combat/context.ts` | 从 `enemy/context.ts` **移动**import 路径改为从 `./types`、`../enemy/types`、`../enemy/utils` 引入 |
| `combat/damage.ts` | 从 `enemy/damage.ts` **移动**import 路径同上 |
| `combat/mapDamage.ts` | 从 `enemy/mapDamage.ts` **移动**import 路径同上 |
| `combat/index.ts` | 新建,`export * from './types/context/damage/mapDamage'` |
| `enemy/types.ts` | 删除所有 Layer 2 接口(迁出后仅剩 Layer 1 内容) |
| `enemy/utils.ts` | 新增 `IMapLocHelper`、`IMapLocIndexer` 接口定义 |
| `enemy/index.ts` | 删除对 `context`、`damage`、`mapDamage` 的导出 |
| `data-base/src/index.ts` | 新增 `export * from './combat'` |
| `data-base/src/types.ts` | `import { IEnemyManager }` 改从 `./enemy/types` 直接引入(`enemy/types.ts` 不再引用 `../types`,无循环) |
| `enemy/enemy.ts` | import 路径无需改动(`IEnemy` 等仍在 `./types` |
| `enemy/manager.ts` | import 路径无需改动(全部 Layer 1 接口仍在 `./types` |
| `enemy/special.ts` | import 路径无需改动 |

View File

@ -3,7 +3,6 @@ import {
IAuraConverter,
IAuraView,
IDamageSystem,
IEnemy,
IEnemyAuraView,
IEnemyCommonQueryEffect,
IEnemyContext,
@ -13,13 +12,12 @@ import {
IEnemySpecialQueryEffect,
IEnemyView,
IMapDamage,
IReadonlyEnemy,
IReadonlyEnemyHandler,
ISpecial
IReadonlyEnemyHandler
} from './types';
import { EnemyView } from './enemy';
import { MapLocIndexer } from './utils';
import { IReadonlyHeroAttribute } from '../hero';
import { IEnemy, IReadonlyEnemy, ISpecial } from '../enemy';
import { EnemyView } from './enemy';
import { ILocationIndexer, MapLocIndexer } from '../common/indexer';
export class EnemyContext<TAttr, THero> implements IEnemyContext<TAttr, THero> {
/** 坐标索引 -> 怪物视图 */
@ -82,7 +80,7 @@ export class EnemyContext<TAttr, THero> implements IEnemyContext<TAttr, THero> {
private damageSystem: IDamageSystem<TAttr, THero> | null = null;
/** 索引工具 */
readonly indexer: MapLocIndexer = new MapLocIndexer();
readonly indexer: ILocationIndexer = new MapLocIndexer();
/** 当前是否需要全量刷新 */
private needUpdate: boolean = true;

View File

@ -1,3 +1,4 @@
import { clamp } from 'lodash-es';
import { ITileLocator, logger } from '@motajs/common';
import {
CriticalableHeroStatus,
@ -8,11 +9,10 @@ import {
IEnemyCritical,
IEnemyDamageInfo,
IReadonlyEnemyHandler,
IEnemyView,
IReadonlyEnemy
IEnemyView
} from './types';
import { IHeroAttribute, IReadonlyHeroAttribute } from '../hero';
import { clamp } from 'lodash-es';
import { IReadonlyEnemy } from '../enemy';
interface ICriticalSearchResult {
/** 此临界点的属性值 */

View File

@ -0,0 +1,42 @@
import { IEnemy, IReadonlyEnemy } from '../enemy';
import { IEnemyView, IEnemyContext } from './types';
export class EnemyView<TAttr> implements IEnemyView<TAttr> {
/** 计算后怪物 */
private readonly computedEnemy: IEnemy<TAttr>;
constructor(
readonly baseEnemy: IEnemy<TAttr>,
readonly context: IEnemyContext<TAttr, unknown>
) {
this.computedEnemy = baseEnemy.clone();
}
reset(): void {
this.computedEnemy.copyFrom(this.baseEnemy);
}
getBaseEnemy(): IReadonlyEnemy<TAttr> {
return this.baseEnemy;
}
getComputedEnemy(): IReadonlyEnemy<TAttr> {
this.context.requestRefresh(this);
return this.computedEnemy;
}
/**
* EnemyContext 使
*/
getComputingEnemy(): IEnemy<TAttr> {
return this.computedEnemy;
}
getModifiableEnemy(): IEnemy<TAttr> {
return this.baseEnemy;
}
markDirty(): void {
this.context.markDirty(this);
}
}

View File

@ -0,0 +1,5 @@
export * from './context';
export * from './damage';
export * from './enemy';
export * from './mapDamage';
export * from './types';

View File

@ -7,9 +7,9 @@ import {
IMapDamageConverter,
IMapDamageInfo,
IMapDamageReducer,
IMapDamageView,
IMapLocIndexer
IMapDamageView
} from './types';
import { ILocationHelper } from '../common/indexer';
interface IPointInfo {
/** 该点所有的地图伤害 */
@ -61,7 +61,7 @@ export class MapDamage<TAttr, THero> implements IMapDamage<TAttr, THero> {
private readonly reducedCache: Map<number, IMapDamageInfo> = new Map();
/** 坐标索引对象 */
private readonly indexer: IMapLocIndexer;
private readonly indexer: ILocationHelper;
constructor(readonly context: IEnemyContext<TAttr, THero>) {
this.indexer = context.indexer;

View File

@ -0,0 +1,688 @@
import { ITileLocator, IRange } from '@motajs/common';
import { IEnemy, IReadonlyEnemy, ISpecial } from '../enemy';
import { IReadonlyHeroAttribute, IHeroAttribute } from '../hero';
import { ILocationHelper } from '../common/indexer';
//#region 辅助接口
export interface IEnemyHandler<TAttr, THero> {
/** 怪物属性信息 */
readonly enemy: IEnemy<TAttr>;
/** 怪物定位符 */
readonly locator: ITileLocator;
/** 勇士属性信息 */
readonly hero: IReadonlyHeroAttribute<THero>;
}
export interface IReadonlyEnemyHandler<TAttr, THero> {
/** 怪物属性信息 */
readonly enemy: IReadonlyEnemy<TAttr>;
/** 怪物定位符 */
readonly locator: ITileLocator;
/** 勇士属性信息 */
readonly hero: IReadonlyHeroAttribute<THero>;
}
//#endregion
//#region 怪物对象
export interface IEnemyView<TAttr> {
/** 怪物视图所属的上下文 */
readonly context: IEnemyContext<TAttr, unknown>;
/**
*
*/
reset(): void;
/**
*
*/
getBaseEnemy(): IReadonlyEnemy<TAttr>;
/**
*
*/
getComputedEnemy(): IReadonlyEnemy<TAttr>;
/**
*
* markDirty
*/
getModifiableEnemy(): IEnemy<TAttr>;
/**
*
*/
markDirty(): void;
}
//#endregion
//#region 光环与查询
export interface IEnemySpecialModifier<TAttr> {
/**
*
* @param handler
*/
add(handler: IReadonlyEnemyHandler<TAttr, unknown>): ISpecial<any>[];
/**
*
* @param handler
*/
delete(handler: IReadonlyEnemyHandler<TAttr, unknown>): ISpecial<any>[];
/**
* true false
* @param handler
* @param special
*/
modify(
handler: IEnemyHandler<TAttr, unknown>,
special: ISpecial<any>
): boolean;
}
export interface IAuraView<TAttr, T = any> {
/** 此光环视图的优先级 */
readonly priority: number;
/** 此光环视图的影响范围 */
readonly range: IRange<T>;
/** 这个光环视图是否有可能修改怪物的基本属性 */
readonly couldApplyBase: boolean;
/** 这个光环视图是否有可能修改怪物的特殊属性 */
readonly couldApplySpecial: boolean;
/**
*
*/
getRangeParam(): T;
/**
*
* @param handler
* @param baseEnemy
*/
apply(
handler: IEnemyHandler<TAttr, unknown>,
baseEnemy: IReadonlyEnemy<TAttr>
): void;
/**
*
* @param handler
* @param baseEnemy
*/
applySpecial(
handler: IEnemyHandler<TAttr, unknown>,
baseEnemy: IReadonlyEnemy<TAttr>
): IEnemySpecialModifier<TAttr> | null;
}
export interface IEnemyAuraView<TAttr, R, S> extends IAuraView<TAttr, R> {
/** 此光环视图所属的怪物 */
readonly enemy: IReadonlyEnemy<TAttr>;
/** 此光环视图所属的特殊属性 */
readonly special: ISpecial<S>;
/** 此光环视图所属怪物的定位符 */
readonly locator: ITileLocator;
}
export interface IAuraConverter<TAttr, THero> {
/**
*
* @param special
* @param handler
*/
shouldConvert(
special: ISpecial<any>,
handler: IReadonlyEnemyHandler<TAttr, THero>
): boolean;
/**
*
*/
convert(
special: ISpecial<any>,
handler: IReadonlyEnemyHandler<TAttr, THero>,
context: IEnemyContext<TAttr, THero>
): IEnemyAuraView<TAttr, any, any>;
}
export interface IEnemySpecialQueryModifier<
TAttr,
THero
> extends IEnemySpecialModifier<TAttr> {
/**
*
*/
shouldQuery(handler: IReadonlyEnemyHandler<TAttr, THero>): boolean;
}
export interface IEnemySpecialQueryEffect<TAttr, THero> {
/** 效果优先级,与光环属性共用 */
readonly priority: number;
/**
*
*/
for(
ctx: IEnemyContext<TAttr, THero>
): IEnemySpecialQueryModifier<TAttr, THero>;
}
export interface IEnemyCommonQueryEffect<TAttr, THero> {
/** 优先级,越高的越先执行 */
readonly priority: number;
/**
*
*/
apply(
handler: IEnemyHandler<TAttr, THero>,
special: ISpecial<any>,
query: () => IEnemyContext<TAttr, THero>
): void;
}
export interface IEnemyFinalEffect<TAttr, THero> {
/** 效果优先级,越高会越先被执行 */
readonly priority: number;
/**
*
*/
apply(handler: IEnemyHandler<TAttr, THero>): void;
}
//#endregion
//#region 地图伤害
export interface IMapDamageInfoExtra {
/** 捕捉怪物信息 */
catch: Set<ITileLocator>;
/** 阻击怪物信息 */
repulse: Set<ITileLocator>;
}
export interface IMapDamageInfo {
/** 伤害值 */
damage: number;
/** 伤害类型 */
type: number;
/** 地图伤害额外信息 */
extra: IMapDamageInfoExtra;
}
export interface IMapDamageView<T = any> {
/**
*
*/
getRange(): IRange<T>;
/**
*
*/
getRangeParam(): T;
/**
*
* @param locator
*/
getDamageAt(locator: ITileLocator): Readonly<IMapDamageInfo> | null;
/**
*
* @param locator
*/
getDamageWithoutCheck(
locator: ITileLocator
): Readonly<IMapDamageInfo> | null;
}
export interface IMapDamageConverter<TAttr, THero> {
/**
*
*/
convert(
handler: IReadonlyEnemyHandler<TAttr, THero>,
context: IEnemyContext<TAttr, THero>
): IMapDamageView<any>[];
}
export interface IMapDamageReducer {
/**
*
*/
reduce(
info: Iterable<Readonly<IMapDamageInfo>>,
locator: ITileLocator
): Readonly<IMapDamageInfo>;
}
export interface IMapDamage<TAttr, THero> {
/** 当前绑定的怪物上下文 */
readonly context: IEnemyContext<TAttr, THero>;
/**
*
* @param converter
*/
useConverter(converter: IMapDamageConverter<TAttr, THero>): void;
/**
*
* @param reducer
*/
useReducer(reducer: IMapDamageReducer): void;
/**
*
* @param locator
* @param info
*/
addMapDamage(locator: ITileLocator, info: IMapDamageInfo): void;
/**
*
* @param locator
* @param info
*/
deleteMapDamage(locator: ITileLocator, info: IMapDamageInfo): void;
/**
* 访
* @param locator
*/
markDirty(locator: ITileLocator): void;
/**
*
* @param view
*/
markEnemyDirty(view: IEnemyView<TAttr>): void;
/**
*
*/
refreshAll(): void;
/**
*
* @param view
*/
deleteEnemy(view: IEnemyView<TAttr>): void;
/**
*
* @param locator
*/
getReducedDamage(locator: ITileLocator): Readonly<IMapDamageInfo> | null;
/**
*
* @param locator
*/
getSeparatedDamage(
locator: ITileLocator
): Iterable<Readonly<IMapDamageInfo>>;
}
//#endregion
//#region 伤害系统
export interface IEnemyDamageInfo {
/** 战斗伤害值 */
readonly damage: number;
/** 战斗回合数 */
readonly turn: number;
}
export interface IEnemyCritical {
/** 此临界点中指定勇士属性的值 */
readonly nextValue: number;
/** 当前勇士指定属性的值 */
readonly baseValue: number;
/** 此临界点中指定勇士数值的值与当前值的差,即 `nextValue - baseValue` */
readonly nextDiff: number;
/** 当前状态下怪物的伤害信息 */
readonly baseInfo: IEnemyDamageInfo;
/** 此临界点下怪物的伤害信息 */
readonly info: IEnemyDamageInfo;
/** 此临界点的伤害值与当前伤害值的差 */
readonly damageDiff: number;
}
export type CriticalableHeroStatus<THero> = keyof {
[P in keyof THero as THero[P] extends number ? P : never]: number;
};
export interface IDamageCalculator<TAttr, THero> {
/**
*
* @param handler
*/
calculate(handler: IReadonlyEnemyHandler<TAttr, THero>): IEnemyDamageInfo;
/**
*
* @param handler
* @param attribute
*/
getCriticalLimit(
handler: IReadonlyEnemyHandler<TAttr, THero>,
attribute: CriticalableHeroStatus<THero>
): number;
}
export interface IDamageContext<TAttr, THero> {
/**
*
* @param enemy
*/
getDamageInfo(enemy: IEnemyView<TAttr>): IEnemyDamageInfo | null;
/**
*
* @param enemy
*/
getDamageInfoByComputed(
enemy: IReadonlyEnemy<TAttr>
): IEnemyDamageInfo | null;
/**
*
* @param enemy
* @param attribute
* @param precision `12-16` 12
*/
calculateCritical(
enemy: IEnemyView<TAttr>,
attribute: CriticalableHeroStatus<THero>,
precision?: number
): Generator<IEnemyCritical, void, void>;
}
export interface IDamageSystem<TAttr, THero> extends IDamageContext<
TAttr,
THero
> {
/** 伤害系统所属的上下文 */
readonly context: IEnemyContext<TAttr, THero>;
/**
* 使
* @param calculator
*/
useCalculator(calculator: IDamageCalculator<TAttr, THero>): void;
/**
* 使
*/
getCalculator(): IDamageCalculator<TAttr, THero> | null;
/**
*
* @param hero
*/
bindHeroStatus(hero: IReadonlyHeroAttribute<THero> | null): void;
/**
*
* @param enemy
*/
markDirty(enemy: IEnemyView<TAttr>): void;
/**
*
* @param enemy
*/
deleteEnemy(enemy: IEnemyView<TAttr>): void;
/**
*
*/
markAllDirty(): void;
/**
*
* @param modify
*/
with(hero: IHeroAttribute<THero>): IDamageContext<TAttr, THero>;
}
//#endregion
//#region 上下文
export interface IEnemyContext<TAttr, THero> {
/** 怪物上下文宽度 */
readonly width: number;
/** 怪物上下文高度 */
readonly height: number;
/** 此上下文使用的索引对象 */
readonly indexer: ILocationHelper;
/**
*
* @param width
* @param height
*/
resize(width: number, height: number): void;
/**
*
* @param converter
*/
registerAuraConverter(converter: IAuraConverter<TAttr, THero>): void;
/**
*
* @param converter
*/
unregisterAuraConverter(converter: IAuraConverter<TAttr, THero>): void;
/**
*
* @param converter
* @param enabled
*/
setAuraConverterEnabled(
converter: IAuraConverter<TAttr, THero>,
enabled: boolean
): void;
/**
*
* @param effect
*/
registerSpecialQueryEffect(
effect: IEnemySpecialQueryEffect<TAttr, THero>
): void;
/**
*
* @param effect
*/
unregisterSpecialQueryEffect(
effect: IEnemySpecialQueryEffect<TAttr, THero>
): void;
/**
*
* @param code
* @param effect
*/
registerCommonQueryEffect(
code: number,
effect: IEnemyCommonQueryEffect<TAttr, THero>
): void;
/**
*
* @param code
* @param effect
*/
unregisterCommonQueryEffect(
code: number,
effect: IEnemyCommonQueryEffect<TAttr, THero>
): void;
/**
*
* @param effect
*/
registerFinalEffect(effect: IEnemyFinalEffect<TAttr, THero>): void;
/**
*
* @param effect
*/
unregisterFinalEffect(effect: IEnemyFinalEffect<TAttr, THero>): void;
/**
*
* @param hero
*/
bindHero(hero: IReadonlyHeroAttribute<THero> | null): void;
/**
*
*/
getBindedHero(): IReadonlyHeroAttribute<THero> | null;
/**
*
* @param enemy
*/
getEnemyLocator(enemy: IEnemy<TAttr>): Readonly<ITileLocator> | null;
/**
*
* @param view
*/
getEnemyLocatorByView(
view: IEnemyView<TAttr>
): Readonly<ITileLocator> | null;
/**
*
* @param locator
*/
getEnemyByLocator(locator: ITileLocator): IEnemyView<TAttr> | null;
/**
*
* @param x
* @param y
*/
getEnemyByLoc(x: number, y: number): IEnemyView<TAttr> | null;
/**
*
* @param enemy
*/
getViewByComputed(enemy: IReadonlyEnemy<TAttr>): IEnemyView<TAttr> | null;
/**
*
* @param locator
* @param enemy
*/
setEnemyAt(locator: ITileLocator, enemy: IEnemy<TAttr>): void;
/**
*
* @param locator
*/
deleteEnemy(locator: ITileLocator): void;
/**
*
* @param range
* @param param
*/
scanRange<T>(
range: IRange<T>,
param: T
): Iterable<[ITileLocator, IEnemyView<TAttr>]>;
/**
*
*/
iterateEnemy(): Iterable<[ITileLocator, IEnemyView<TAttr>]>;
/**
*
* @param aura
*/
addAura(aura: IAuraView<TAttr>): void;
/**
*
* @param aura
*/
deleteAura(aura: IAuraView<TAttr>): void;
/**
*
* @param damage
*/
attachMapDamage(damage: IMapDamage<TAttr, THero> | null): void;
/**
*
*/
getMapDamage(): IMapDamage<TAttr, THero> | null;
/**
*
* @param system
*/
attachDamageSystem(system: IDamageSystem<TAttr, unknown> | null): void;
/**
*
*/
getDamageSystem(): IDamageSystem<TAttr, THero> | null;
/**
*
*
* 1.
* 2.
* 3.
* 4.
*/
buildup(): void;
/**
*
* @param view
*/
markDirty(view: IEnemyView<TAttr>): void;
/**
*
* @param view
*/
requestRefresh(view: IEnemyView<TAttr>): void;
/**
*
*/
clear(): void;
/**
*
*/
destroy(): void;
}
//#endregion

View File

@ -0,0 +1,61 @@
import { ITileLocator } from '@motajs/common';
//#region 接口定义
export interface ILocationHelper {
/**
* ->
* @param x
* @param y
*/
locToIndex(x: number, y: number): number;
/**
* ->
* @param locator
*/
locaterToIndex(locator: ITileLocator): number;
/**
* ->
* @param index
*/
indexToLocator(index: number): ITileLocator;
}
export interface ILocationIndexer extends ILocationHelper {
/**
*
* @param width
*/
setWidth(width: number): void;
}
//#endregion
//#region 默认实现
export class MapLocIndexer implements ILocationIndexer {
private width: number = 0;
setWidth(width: number): void {
this.width = width;
}
locToIndex(x: number, y: number): number {
return y * this.width + x;
}
locaterToIndex(locator: ITileLocator): number {
return locator.y * this.width + locator.x;
}
indexToLocator(index: number): ITileLocator {
return {
x: index % this.width,
y: Math.floor(index / this.width)
};
}
}
//#endregion

View File

@ -1,12 +1,5 @@
import { logger } from '@motajs/common';
import {
IEnemy,
IEnemyContext,
IEnemySaveState,
IReadonlyEnemy,
ISpecial,
IEnemyView
} from './types';
import { IEnemy, IEnemySaveState, IReadonlyEnemy, ISpecial } from './types';
import { SaveCompression } from '../common/types';
export class Enemy<TAttr> implements IEnemy<TAttr> {
@ -113,43 +106,3 @@ export class Enemy<TAttr> implements IEnemy<TAttr> {
}
}
}
export class EnemyView<TAttr> implements IEnemyView<TAttr> {
/** 计算后怪物 */
private readonly computedEnemy: IEnemy<TAttr>;
constructor(
readonly baseEnemy: IEnemy<TAttr>,
readonly context: IEnemyContext<TAttr, unknown>
) {
this.computedEnemy = baseEnemy.clone();
}
reset(): void {
this.computedEnemy.copyFrom(this.baseEnemy);
}
getBaseEnemy(): IReadonlyEnemy<TAttr> {
return this.baseEnemy;
}
getComputedEnemy(): IReadonlyEnemy<TAttr> {
this.context.requestRefresh(this);
return this.computedEnemy;
}
/**
* EnemyContext 使
*/
getComputingEnemy(): IEnemy<TAttr> {
return this.computedEnemy;
}
getModifiableEnemy(): IEnemy<TAttr> {
return this.baseEnemy;
}
markDirty(): void {
this.context.markDirty(this);
}
}

View File

@ -1,8 +1,4 @@
export * from './enemy';
export * from './context';
export * from './damage';
export * from './mapDamage';
export * from './manager';
export * from './special';
export * from './types';
export * from './utils';

View File

@ -1,5 +1,3 @@
import { IRange, ITileLocator } from '@motajs/common';
import { IHeroAttribute, IReadonlyHeroAttribute } from '../hero';
import { ISaveableContent } from '../common/types';
//#region 怪物基础
@ -288,716 +286,3 @@ export interface IEnemyManager<TAttr> extends ISaveableContent<
}
//#endregion
//#region 辅助接口
export interface IMapLocHelper {
/**
* ->
* @param x
* @param y
*/
locToIndex(x: number, y: number): number;
/**
* ->
* @param locator
*/
locaterToIndex(locator: ITileLocator): number;
/**
* ->
* @param index
*/
indexToLocator(index: number): ITileLocator;
}
export interface IMapLocIndexer extends IMapLocHelper {
/**
*
* @param width
*/
setWidth(width: number): void;
}
export interface IEnemyHandler<TAttr, THero> {
/** 怪物属性信息 */
readonly enemy: IEnemy<TAttr>;
/** 怪物定位符 */
readonly locator: ITileLocator;
/** 勇士属性信息 */
readonly hero: IReadonlyHeroAttribute<THero>;
}
export interface IReadonlyEnemyHandler<TAttr, THero> {
/** 怪物属性信息 */
readonly enemy: IReadonlyEnemy<TAttr>;
/** 怪物定位符 */
readonly locator: ITileLocator;
/** 勇士属性信息 */
readonly hero: IReadonlyHeroAttribute<THero>;
}
//#endregion
//#region 怪物对象
export interface IEnemyView<TAttr> {
/** 怪物视图所属的上下文 */
readonly context: IEnemyContext<TAttr, unknown>;
/**
*
*/
reset(): void;
/**
*
*/
getBaseEnemy(): IReadonlyEnemy<TAttr>;
/**
*
*/
getComputedEnemy(): IReadonlyEnemy<TAttr>;
/**
*
* markDirty
*/
getModifiableEnemy(): IEnemy<TAttr>;
/**
*
*/
markDirty(): void;
}
//#endregion
//#region 光环与查询
export interface IEnemySpecialModifier<TAttr> {
/**
*
* @param handler
*/
add(handler: IReadonlyEnemyHandler<TAttr, unknown>): ISpecial<any>[];
/**
*
* @param handler
*/
delete(handler: IReadonlyEnemyHandler<TAttr, unknown>): ISpecial<any>[];
/**
* true false
* @param handler
* @param special
*/
modify(
handler: IEnemyHandler<TAttr, unknown>,
special: ISpecial<any>
): boolean;
}
export interface IAuraView<TAttr, T = any> {
/** 此光环视图的优先级 */
readonly priority: number;
/** 此光环视图的影响范围 */
readonly range: IRange<T>;
/** 这个光环视图是否有可能修改怪物的基本属性 */
readonly couldApplyBase: boolean;
/** 这个光环视图是否有可能修改怪物的特殊属性 */
readonly couldApplySpecial: boolean;
/**
*
*/
getRangeParam(): T;
/**
*
* @param handler
* @param baseEnemy
*/
apply(
handler: IEnemyHandler<TAttr, unknown>,
baseEnemy: IReadonlyEnemy<TAttr>
): void;
/**
*
* @param handler
* @param baseEnemy
*/
applySpecial(
handler: IEnemyHandler<TAttr, unknown>,
baseEnemy: IReadonlyEnemy<TAttr>
): IEnemySpecialModifier<TAttr> | null;
}
export interface IEnemyAuraView<TAttr, R, S> extends IAuraView<TAttr, R> {
/** 此光环视图所属的怪物 */
readonly enemy: IReadonlyEnemy<TAttr>;
/** 此光环视图所属的特殊属性 */
readonly special: ISpecial<S>;
/** 此光环视图所属怪物的定位符 */
readonly locator: ITileLocator;
}
export interface IAuraConverter<TAttr, THero> {
/**
*
* @param special
* @param handler
*/
shouldConvert(
special: ISpecial<any>,
handler: IReadonlyEnemyHandler<TAttr, THero>
): boolean;
/**
*
*/
convert(
special: ISpecial<any>,
handler: IReadonlyEnemyHandler<TAttr, THero>,
context: IEnemyContext<TAttr, THero>
): IEnemyAuraView<TAttr, any, any>;
}
export interface IEnemySpecialQueryModifier<
TAttr,
THero
> extends IEnemySpecialModifier<TAttr> {
/**
*
*/
shouldQuery(handler: IReadonlyEnemyHandler<TAttr, THero>): boolean;
}
export interface IEnemySpecialQueryEffect<TAttr, THero> {
/** 效果优先级,与光环属性共用 */
readonly priority: number;
/**
*
*/
for(
ctx: IEnemyContext<TAttr, THero>
): IEnemySpecialQueryModifier<TAttr, THero>;
}
export interface IEnemyCommonQueryEffect<TAttr, THero> {
/** 优先级,越高的越先执行 */
readonly priority: number;
/**
*
*/
apply(
handler: IEnemyHandler<TAttr, THero>,
special: ISpecial<any>,
query: () => IEnemyContext<TAttr, THero>
): void;
}
export interface IEnemyFinalEffect<TAttr, THero> {
/** 效果优先级,越高会越先被执行 */
readonly priority: number;
/**
*
*/
apply(handler: IEnemyHandler<TAttr, THero>): void;
}
//#endregion
//#region 地图伤害
export interface IMapDamageInfoExtra {
/** 捕捉怪物信息 */
catch: Set<ITileLocator>;
/** 阻击怪物信息 */
repulse: Set<ITileLocator>;
}
export interface IMapDamageInfo {
/** 伤害值 */
damage: number;
/** 伤害类型 */
type: number;
/** 地图伤害额外信息 */
extra: IMapDamageInfoExtra;
}
export interface IMapDamageView<T = any> {
/**
*
*/
getRange(): IRange<T>;
/**
*
*/
getRangeParam(): T;
/**
*
* @param locator
*/
getDamageAt(locator: ITileLocator): Readonly<IMapDamageInfo> | null;
/**
*
* @param locator
*/
getDamageWithoutCheck(
locator: ITileLocator
): Readonly<IMapDamageInfo> | null;
}
export interface IMapDamageConverter<TAttr, THero> {
/**
*
*/
convert(
handler: IReadonlyEnemyHandler<TAttr, THero>,
context: IEnemyContext<TAttr, THero>
): IMapDamageView<any>[];
}
export interface IMapDamageReducer {
/**
*
*/
reduce(
info: Iterable<Readonly<IMapDamageInfo>>,
locator: ITileLocator
): Readonly<IMapDamageInfo>;
}
export interface IMapDamage<TAttr, THero> {
/** 当前绑定的怪物上下文 */
readonly context: IEnemyContext<TAttr, THero>;
/**
*
* @param converter
*/
useConverter(converter: IMapDamageConverter<TAttr, THero>): void;
/**
*
* @param reducer
*/
useReducer(reducer: IMapDamageReducer): void;
/**
*
* @param locator
* @param info
*/
addMapDamage(locator: ITileLocator, info: IMapDamageInfo): void;
/**
*
* @param locator
* @param info
*/
deleteMapDamage(locator: ITileLocator, info: IMapDamageInfo): void;
/**
* 访
* @param locator
*/
markDirty(locator: ITileLocator): void;
/**
*
* @param view
*/
markEnemyDirty(view: IEnemyView<TAttr>): void;
/**
*
*/
refreshAll(): void;
/**
*
* @param view
*/
deleteEnemy(view: IEnemyView<TAttr>): void;
/**
*
* @param locator
*/
getReducedDamage(locator: ITileLocator): Readonly<IMapDamageInfo> | null;
/**
*
* @param locator
*/
getSeparatedDamage(
locator: ITileLocator
): Iterable<Readonly<IMapDamageInfo>>;
}
//#endregion
//#region 伤害系统
export interface IEnemyDamageInfo {
/** 战斗伤害值 */
readonly damage: number;
/** 战斗回合数 */
readonly turn: number;
}
export interface IEnemyCritical {
/** 此临界点中指定勇士属性的值 */
readonly nextValue: number;
/** 当前勇士指定属性的值 */
readonly baseValue: number;
/** 此临界点中指定勇士数值的值与当前值的差,即 `nextValue - baseValue` */
readonly nextDiff: number;
/** 当前状态下怪物的伤害信息 */
readonly baseInfo: IEnemyDamageInfo;
/** 此临界点下怪物的伤害信息 */
readonly info: IEnemyDamageInfo;
/** 此临界点的伤害值与当前伤害值的差 */
readonly damageDiff: number;
}
export type CriticalableHeroStatus<THero> = keyof {
[P in keyof THero as THero[P] extends number ? P : never]: number;
};
export interface IDamageCalculator<TAttr, THero> {
/**
*
* @param handler
*/
calculate(handler: IReadonlyEnemyHandler<TAttr, THero>): IEnemyDamageInfo;
/**
*
* @param handler
* @param attribute
*/
getCriticalLimit(
handler: IReadonlyEnemyHandler<TAttr, THero>,
attribute: CriticalableHeroStatus<THero>
): number;
}
export interface IDamageContext<TAttr, THero> {
/**
*
* @param enemy
*/
getDamageInfo(enemy: IEnemyView<TAttr>): IEnemyDamageInfo | null;
/**
*
* @param enemy
*/
getDamageInfoByComputed(
enemy: IReadonlyEnemy<TAttr>
): IEnemyDamageInfo | null;
/**
*
* @param enemy
* @param attribute
* @param precision `12-16` 12
*/
calculateCritical(
enemy: IEnemyView<TAttr>,
attribute: CriticalableHeroStatus<THero>,
precision?: number
): Generator<IEnemyCritical, void, void>;
}
export interface IDamageSystem<TAttr, THero> extends IDamageContext<
TAttr,
THero
> {
/** 伤害系统所属的上下文 */
readonly context: IEnemyContext<TAttr, THero>;
/**
* 使
* @param calculator
*/
useCalculator(calculator: IDamageCalculator<TAttr, THero>): void;
/**
* 使
*/
getCalculator(): IDamageCalculator<TAttr, THero> | null;
/**
*
* @param hero
*/
bindHeroStatus(hero: IReadonlyHeroAttribute<THero> | null): void;
/**
*
* @param enemy
*/
markDirty(enemy: IEnemyView<TAttr>): void;
/**
*
* @param enemy
*/
deleteEnemy(enemy: IEnemyView<TAttr>): void;
/**
*
*/
markAllDirty(): void;
/**
*
* @param modify
*/
with(hero: IHeroAttribute<THero>): IDamageContext<TAttr, THero>;
}
//#endregion
//#region 上下文
export interface IEnemyContext<TAttr, THero> {
/** 怪物上下文宽度 */
readonly width: number;
/** 怪物上下文高度 */
readonly height: number;
/** 此上下文使用的索引对象 */
readonly indexer: IMapLocIndexer;
/**
*
* @param width
* @param height
*/
resize(width: number, height: number): void;
/**
*
* @param converter
*/
registerAuraConverter(converter: IAuraConverter<TAttr, THero>): void;
/**
*
* @param converter
*/
unregisterAuraConverter(converter: IAuraConverter<TAttr, THero>): void;
/**
*
* @param converter
* @param enabled
*/
setAuraConverterEnabled(
converter: IAuraConverter<TAttr, THero>,
enabled: boolean
): void;
/**
*
* @param effect
*/
registerSpecialQueryEffect(
effect: IEnemySpecialQueryEffect<TAttr, THero>
): void;
/**
*
* @param effect
*/
unregisterSpecialQueryEffect(
effect: IEnemySpecialQueryEffect<TAttr, THero>
): void;
/**
*
* @param code
* @param effect
*/
registerCommonQueryEffect(
code: number,
effect: IEnemyCommonQueryEffect<TAttr, THero>
): void;
/**
*
* @param code
* @param effect
*/
unregisterCommonQueryEffect(
code: number,
effect: IEnemyCommonQueryEffect<TAttr, THero>
): void;
/**
*
* @param effect
*/
registerFinalEffect(effect: IEnemyFinalEffect<TAttr, THero>): void;
/**
*
* @param effect
*/
unregisterFinalEffect(effect: IEnemyFinalEffect<TAttr, THero>): void;
/**
*
* @param hero
*/
bindHero(hero: IReadonlyHeroAttribute<THero> | null): void;
/**
*
*/
getBindedHero(): IReadonlyHeroAttribute<THero> | null;
/**
*
* @param enemy
*/
getEnemyLocator(enemy: IEnemy<TAttr>): Readonly<ITileLocator> | null;
/**
*
* @param view
*/
getEnemyLocatorByView(
view: IEnemyView<TAttr>
): Readonly<ITileLocator> | null;
/**
*
* @param locator
*/
getEnemyByLocator(locator: ITileLocator): IEnemyView<TAttr> | null;
/**
*
* @param x
* @param y
*/
getEnemyByLoc(x: number, y: number): IEnemyView<TAttr> | null;
/**
*
* @param enemy
*/
getViewByComputed(enemy: IReadonlyEnemy<TAttr>): IEnemyView<TAttr> | null;
/**
*
* @param locator
* @param enemy
*/
setEnemyAt(locator: ITileLocator, enemy: IEnemy<TAttr>): void;
/**
*
* @param locator
*/
deleteEnemy(locator: ITileLocator): void;
/**
*
* @param range
* @param param
*/
scanRange<T>(
range: IRange<T>,
param: T
): Iterable<[ITileLocator, IEnemyView<TAttr>]>;
/**
*
*/
iterateEnemy(): Iterable<[ITileLocator, IEnemyView<TAttr>]>;
/**
*
* @param aura
*/
addAura(aura: IAuraView<TAttr>): void;
/**
*
* @param aura
*/
deleteAura(aura: IAuraView<TAttr>): void;
/**
*
* @param damage
*/
attachMapDamage(damage: IMapDamage<TAttr, THero> | null): void;
/**
*
*/
getMapDamage(): IMapDamage<TAttr, THero> | null;
/**
*
* @param system
*/
attachDamageSystem(system: IDamageSystem<TAttr, unknown> | null): void;
/**
*
*/
getDamageSystem(): IDamageSystem<TAttr, THero> | null;
/**
*
*
* 1.
* 2.
* 3.
* 4.
*/
buildup(): void;
/**
*
* @param view
*/
markDirty(view: IEnemyView<TAttr>): void;
/**
*
* @param view
*/
requestRefresh(view: IEnemyView<TAttr>): void;
/**
*
*/
clear(): void;
/**
*
*/
destroy(): void;
}
//#endregion

View File

@ -1,25 +0,0 @@
import { ITileLocator } from '@motajs/common';
import { IMapLocIndexer } from './types';
export class MapLocIndexer implements IMapLocIndexer {
private width: number = 0;
setWidth(width: number): void {
this.width = width;
}
locToIndex(x: number, y: number): number {
return y * this.width + x;
}
locaterToIndex(locator: ITileLocator): number {
return locator.y * this.width + locator.x;
}
indexToLocator(index: number): ITileLocator {
return {
x: index % this.width,
y: Math.floor(index / this.width)
};
}
}

View File

@ -1,3 +1,4 @@
export * from './combat';
export * from './common';
export * from './enemy';
export * from './flag';