diff --git a/packages-user/data-base/src/enemy/context.ts b/packages-user/data-base/src/enemy/context.ts index 2b578d8..f00cf5c 100644 --- a/packages-user/data-base/src/enemy/context.ts +++ b/packages-user/data-base/src/enemy/context.ts @@ -1,4 +1,5 @@ import { IRange, logger } from '@motajs/common'; +import { ITileLocator } from '@user/types'; import { IAuraConverter, IAuraView, @@ -16,36 +17,42 @@ import { } from './types'; import { EnemyView } from './enemy'; import { MapLocIndexer } from './utils'; -import { ITileLocator } from '@user/types'; -export class EnemyContext implements IEnemyContext { - private readonly enemyViewMap: Map = new Map(); - private readonly enemyMap: Map = new Map(); - private readonly locatorViewMap: Map = new Map(); - private readonly locatorEnemyMap: Map = new Map(); - private readonly computedToView: Map = new Map(); +export class EnemyContext implements IEnemyContext { + private readonly enemyViewMap: Map> = new Map(); + private readonly enemyMap: Map> = new Map(); + private readonly locatorViewMap: Map, number> = new Map(); + private readonly locatorEnemyMap: Map, number> = new Map(); + private readonly computedToView: Map< + IReadonlyEnemy, + EnemyView + > = new Map(); - private readonly auraConverter: Set = new Set(); - private readonly converterStatus: Map = new Map(); - private readonly convertedAura: Map, IAuraView> = new Map(); - - private readonly commonQueryMap: Map = + private readonly auraConverter: Set> = new Set(); + private readonly converterStatus: Map, boolean> = new Map(); + private readonly convertedAura: Map, IAuraView> = + new Map(); + + private readonly commonQueryMap: Map< + number, + IEnemyCommonQueryEffect[] + > = new Map(); private readonly specialQueryEffects: Map< number, - IEnemySpecialQueryEffect[] + IEnemySpecialQueryEffect[] > = new Map(); - private readonly finalEffects: IEnemyFinalEffect[] = []; - private readonly globalAuraList: Set = new Set(); - private readonly sortedAura: Map> = new Map(); + private readonly finalEffects: IEnemyFinalEffect[] = []; + private readonly globalAuraList: Set> = new Set(); + private readonly sortedAura: Map>> = new Map(); - private readonly needTotallyRefresh: Set = new Set(); - private readonly requestedCommonContext: Set = new Set(); - private readonly dirtyEnemy: Set = new Set(); + private readonly needTotallyRefresh: Set> = new Set(); + private readonly requestedCommonContext: Set> = new Set(); + private readonly dirtyEnemy: Set> = new Set(); - private mapDamage: IMapDamage | null = null; + private mapDamage: IMapDamage | null = null; readonly indexer: MapLocIndexer = new MapLocIndexer(); private needUpdate: boolean = true; @@ -61,24 +68,27 @@ export class EnemyContext implements IEnemyContext { this.indexer.setWidth(width); } - registerAuraConverter(converter: IAuraConverter): void { + registerAuraConverter(converter: IAuraConverter): void { this.auraConverter.add(converter); this.converterStatus.set(converter, true); } - unregisterAuraConverter(converter: IAuraConverter): void { + unregisterAuraConverter(converter: IAuraConverter): void { this.auraConverter.delete(converter); this.converterStatus.delete(converter); } - setAuraConverterEnabled(converter: IAuraConverter, enabled: boolean): void { + setAuraConverterEnabled( + converter: IAuraConverter, + enabled: boolean + ): void { if (!this.auraConverter.has(converter)) return; this.converterStatus.set(converter, enabled); } registerCommonQueryEffect( code: number, - effect: IEnemyCommonQueryEffect + effect: IEnemyCommonQueryEffect ): void { const array = this.commonQueryMap.getOrInsert(code, []); array.push(effect); @@ -87,7 +97,7 @@ export class EnemyContext implements IEnemyContext { unregisterCommonQueryEffect( code: number, - effect: IEnemyCommonQueryEffect + effect: IEnemyCommonQueryEffect ): void { const array = this.commonQueryMap.get(code); if (!array) return; @@ -96,12 +106,14 @@ export class EnemyContext implements IEnemyContext { array.splice(index, 1); } - registerSpecialQueryEffect(effect: IEnemySpecialQueryEffect): void { + registerSpecialQueryEffect(effect: IEnemySpecialQueryEffect): void { const list = this.specialQueryEffects.getOrInsert(effect.priority, []); list.push(effect); } - unregisterSpecialQueryEffect(effect: IEnemySpecialQueryEffect): void { + unregisterSpecialQueryEffect( + effect: IEnemySpecialQueryEffect + ): void { const list = this.specialQueryEffects.get(effect.priority); if (!list) return; const index = list.indexOf(effect); @@ -113,41 +125,43 @@ export class EnemyContext implements IEnemyContext { } } - registerFinalEffect(effect: IEnemyFinalEffect): void { + registerFinalEffect(effect: IEnemyFinalEffect): void { this.finalEffects.push(effect); this.finalEffects.sort((a, b) => b.priority - a.priority); } - unregisterFinalEffect(effect: IEnemyFinalEffect): void { + unregisterFinalEffect(effect: IEnemyFinalEffect): void { const index = this.finalEffects.indexOf(effect); if (index !== -1) { this.finalEffects.splice(index, 1); } } - getEnemyLocator(enemy: IEnemy): Readonly | null { + getEnemyLocator(enemy: IEnemy): Readonly | null { const index = this.locatorEnemyMap.get(enemy); if (index === undefined) return null; return this.indexer.indexToLocator(index); } - getEnemyLocatorByView(view: IEnemyView): Readonly | null { + getEnemyLocatorByView( + view: IEnemyView + ): Readonly | null { const index = this.locatorViewMap.get(view); if (index === undefined) return null; return this.indexer.indexToLocator(index); } - getEnemyByLocator(locator: ITileLocator): IEnemyView | null { + getEnemyByLocator(locator: ITileLocator): IEnemyView | null { const index = this.indexer.locToIndex(locator.x, locator.y); return this.enemyViewMap.get(index) ?? null; } - getEnemyByLoc(x: number, y: number): IEnemyView | null { + getEnemyByLoc(x: number, y: number): IEnemyView | null { const index = this.indexer.locToIndex(x, y); return this.enemyViewMap.get(index) ?? null; } - getViewByComputed(enemy: IReadonlyEnemy): IEnemyView | null { + getViewByComputed(enemy: IReadonlyEnemy): IEnemyView | null { return this.computedToView.get(enemy) ?? null; } @@ -172,11 +186,11 @@ export class EnemyContext implements IEnemyContext { this.locatorEnemyMap.delete(enemy); } - setEnemyAt(locator: ITileLocator, enemy: IEnemy): void { + setEnemyAt(locator: ITileLocator, enemy: IEnemy): void { const index = this.indexer.locToIndex(locator.x, locator.y); this.deleteEnemyAt(index); - const view = new EnemyView(enemy, this); + const view = new EnemyView(enemy, this); this.enemyMap.set(index, enemy); this.enemyViewMap.set(index, view); this.locatorEnemyMap.set(enemy, index); @@ -194,7 +208,7 @@ export class EnemyContext implements IEnemyContext { private *internalScanRange( range: IRange, param: T - ): Iterable { + ): Iterable> { range.bindHost(this); const keys = new Set(this.enemyViewMap.keys()); const matched = range.autoDetect(keys, param); @@ -207,44 +221,44 @@ export class EnemyContext implements IEnemyContext { } } - scanRange(range: IRange, param: T): Iterable { + scanRange(range: IRange, param: T): Iterable> { return this.internalScanRange(range, param); } - *iterateEnemy(): Iterable<[ITileLocator, IEnemyView]> { + *iterateEnemy(): Iterable<[ITileLocator, IEnemyView]> { for (const [index, view] of this.enemyViewMap) { const locator = this.indexer.indexToLocator(index); yield [locator, view]; } } - addAura(aura: IAuraView): void { + addAura(aura: IAuraView): void { this.globalAuraList.add(aura); this.needUpdate = true; } - deleteAura(aura: IAuraView): void { + deleteAura(aura: IAuraView): void { this.globalAuraList.delete(aura); this.needUpdate = true; } - attachMapDamage(damage: IMapDamage | null): void { + attachMapDamage(damage: IMapDamage | null): void { this.mapDamage = damage; if (damage) { damage.refreshAll(); } } - getMapDamage(): IMapDamage | null { + getMapDamage(): IMapDamage | null { return this.mapDamage; } private convertSpecial( special: ISpecial, - enemy: IReadonlyEnemy, + enemy: IReadonlyEnemy, locator: ITileLocator - ): IEnemyAuraView | null { - let matched: IAuraConverter | null = null; + ): IEnemyAuraView | null { + let matched: IAuraConverter | null = null; for (const converter of this.auraConverter) { if (!this.converterStatus.get(converter)) continue; @@ -258,10 +272,10 @@ export class EnemyContext implements IEnemyContext { } if (!matched) return null; - return matched.convert(special, enemy, locator); + return matched.convert(special, enemy, locator, this); } - private insertIntoSortedAura(aura: IAuraView): void { + private insertIntoSortedAura(aura: IAuraView): void { const set = this.sortedAura.getOrInsertComputed( aura.priority, () => new Set() @@ -269,7 +283,7 @@ export class EnemyContext implements IEnemyContext { set.add(aura); } - private removeFromSortedAura(aura: IAuraView): void { + private removeFromSortedAura(aura: IAuraView): void { const set = this.sortedAura.get(aura.priority); if (set) { set.delete(aura); @@ -280,15 +294,15 @@ export class EnemyContext implements IEnemyContext { } private processSpecialModifier( - modifier: IEnemySpecialModifier, - enemy: IEnemy, + modifier: IEnemySpecialModifier, + enemy: IEnemy, locator: ITileLocator, currentPriority: number - ): Set { + ): Set> { const toAdd = modifier.add(enemy, locator); const toDelete = modifier.delete(enemy, locator); - const affectedAuras = new Set(); + const affectedAuras = new Set>(); if (toAdd.length > 0 && toDelete.length > 0) { logger.warn(100); @@ -351,7 +365,7 @@ export class EnemyContext implements IEnemyContext { } private processSpecialQuery( - effect: IEnemySpecialQueryEffect, + effect: IEnemySpecialQueryEffect, currentPriority: number ): void { const modifier = effect.for(this); @@ -377,7 +391,10 @@ export class EnemyContext implements IEnemyContext { } } - private processAuraSpecial(aura: IAuraView, currentPriority: number): void { + private processAuraSpecial( + aura: IAuraView, + currentPriority: number + ): void { const param = aura.getRangeParam(); for (const enemyView of this.internalScanRange(aura.range, param)) { @@ -410,7 +427,7 @@ export class EnemyContext implements IEnemyContext { const enemy = view.getComputingEnemy(); const locator = this.indexer.indexToLocator(index); - for (const special of enemy.specials) { + for (const special of enemy.iterateSpecials()) { const aura = this.convertSpecial(special, enemy, locator); if (!aura) continue; this.convertedAura.set(special, aura); @@ -484,7 +501,7 @@ export class EnemyContext implements IEnemyContext { queried = true; return this; }; - for (const special of enemy.specials) { + for (const special of enemy.iterateSpecials()) { const effects = this.commonQueryMap.get(special.code); if (!effects) continue; for (const effect of effects) { @@ -533,14 +550,14 @@ export class EnemyContext implements IEnemyContext { } } - markDirty(view: IEnemyView): void { + markDirty(view: IEnemyView): void { if (!this.locatorViewMap.has(view)) return; this.dirtyEnemy.add(view); } private refreshSpecialModifier( - modifier: IEnemySpecialModifier, - enemy: IEnemy, + modifier: IEnemySpecialModifier, + enemy: IEnemy, locator: ITileLocator ): void { const toAdd = modifier.add(enemy, locator); @@ -582,7 +599,7 @@ export class EnemyContext implements IEnemyContext { } } - private refreshEnemy(view: EnemyView): void { + private refreshEnemy(view: EnemyView): void { const locator = this.getEnemyLocatorByView(view); if (!locator) return; @@ -653,7 +670,7 @@ export class EnemyContext implements IEnemyContext { queried = true; return this; }; - for (const special of enemy.specials) { + for (const special of enemy.iterateSpecials()) { const effects = this.commonQueryMap.get(special.code); if (!effects) continue; for (const effect of effects) { @@ -675,7 +692,7 @@ export class EnemyContext implements IEnemyContext { } } - requestRefresh(view: IEnemyView): void { + requestRefresh(view: IEnemyView): void { if (!this.dirtyEnemy.has(view)) return; if (this.needTotallyRefresh.has(view)) { this.needUpdate = true; @@ -685,11 +702,11 @@ export class EnemyContext implements IEnemyContext { return; } - this.refreshEnemy(view as EnemyView); + this.refreshEnemy(view as EnemyView); for (const requestedView of this.requestedCommonContext) { if (requestedView === view) continue; - this.refreshEnemy(requestedView as EnemyView); + this.refreshEnemy(requestedView as EnemyView); } } diff --git a/packages-user/data-base/src/enemy/enemy.ts b/packages-user/data-base/src/enemy/enemy.ts index 1dc76c3..7f56efb 100644 --- a/packages-user/data-base/src/enemy/enemy.ts +++ b/packages-user/data-base/src/enemy/enemy.ts @@ -1,14 +1,13 @@ import { logger } from '@motajs/common'; import { IEnemy, - IEnemyAttributes, IEnemyContext, IReadonlyEnemy, ISpecial, IEnemyView } from './types'; -export class Enemy implements IEnemy { +export class Enemy implements IEnemy { readonly specials: Set> = new Set(); /** code -> ISpecial 映射,用于快速查找 */ private readonly specialMap: Map> = new Map(); @@ -16,7 +15,7 @@ export class Enemy implements IEnemy { constructor( readonly id: string, readonly code: number, - readonly attributes: IEnemyAttributes + private attributes: TAttr ) {} getSpecial(code: number): ISpecial | null { @@ -48,21 +47,20 @@ export class Enemy implements IEnemy { return this.specials; } - setAttribute( - key: K, - value: IEnemyAttributes[K] - ): void { + setAttribute(key: K, value: TAttr[K]): void { this.attributes[key] = value; } - getAttribute( - key: K - ): IEnemyAttributes[K] { + getAttribute(key: K): TAttr[K] { return this.attributes[key]; } - clone(): IEnemy { - const cloned = new Enemy( + cloneAttributes(): TAttr { + return structuredClone(this.attributes); + } + + clone(): IEnemy { + const cloned = new Enemy( this.id, this.code, structuredClone(this.attributes) @@ -73,10 +71,8 @@ export class Enemy implements IEnemy { return cloned; } - copy(enemy: IReadonlyEnemy): void { - ATTRIBUTE_KEYS.forEach(key => { - this.setAttribute(key, structuredClone(enemy.getAttribute(key))); - }); + copyFrom(enemy: IReadonlyEnemy): void { + this.attributes = enemy.cloneAttributes(); this.specials.clear(); this.specialMap.clear(); for (const special of enemy.iterateSpecials()) { @@ -85,25 +81,25 @@ export class Enemy implements IEnemy { } } -export class EnemyView implements IEnemyView { - private computedEnemy: IEnemy; +export class EnemyView implements IEnemyView { + private computedEnemy: IEnemy; constructor( - readonly baseEnemy: IEnemy, - readonly context: IEnemyContext + readonly baseEnemy: IEnemy, + readonly context: IEnemyContext ) { this.computedEnemy = baseEnemy.clone(); } reset(): void { - this.computedEnemy.copy(this.baseEnemy); + this.computedEnemy.copyFrom(this.baseEnemy); } - getBaseEnemy(): IReadonlyEnemy { + getBaseEnemy(): IReadonlyEnemy { return this.baseEnemy; } - getComputedEnemy(): IReadonlyEnemy { + getComputedEnemy(): IReadonlyEnemy { this.context.requestRefresh(this); return this.computedEnemy; } @@ -111,11 +107,11 @@ export class EnemyView implements IEnemyView { /** * 获取计算中怪物对象,这个接口不对外暴露,仅在系统内部的 EnemyContext 中使用。 */ - getComputingEnemy(): IEnemy { + getComputingEnemy(): IEnemy { return this.computedEnemy; } - getModifiableEnemy(): IEnemy { + getModifiableEnemy(): IEnemy { return this.baseEnemy; } @@ -123,12 +119,3 @@ export class EnemyView implements IEnemyView { this.context.markDirty(this); } } - -export const ATTRIBUTE_KEYS: (keyof IEnemyAttributes)[] = [ - 'hp', - 'atk', - 'def', - 'money', - 'exp', - 'point' -]; diff --git a/packages-user/data-base/src/enemy/manager.ts b/packages-user/data-base/src/enemy/manager.ts index f3bd8da..6908e56 100644 --- a/packages-user/data-base/src/enemy/manager.ts +++ b/packages-user/data-base/src/enemy/manager.ts @@ -1,30 +1,21 @@ import { logger } from '@motajs/common'; import { Enemy as EnemyImpl } from './enemy'; -import { - IEnemy, - IEnemyAttributes, - IEnemyManager, - ISpecial, - SpecialCreation -} from './types'; +import { IEnemy, IEnemyManager, SpecialCreation } from './types'; -export class EnemyManager implements IEnemyManager { +export class EnemyManager implements IEnemyManager { /** 特殊属性注册表,code -> 创建函数 */ - private readonly specialRegistry: Map> = + private readonly specialRegistry: Map> = new Map(); /** 自定义怪物属性注册表,name -> 默认值 */ private readonly attributeRegistry: Map = new Map(); /** 怪物模板表,code -> IEnemy */ - private readonly prefabByCode: Map = new Map(); + private readonly prefabByCode: Map> = new Map(); /** 怪物模板表,id -> IEnemy */ - private readonly prefabById: Map = new Map(); + private readonly prefabById: Map> = new Map(); /** 旧样板怪物 id 到 code 的映射,用于 fromLegacyEnemy 快速查找已有模板 */ private readonly legacyIdToCode: Map = new Map(); - registerSpecial( - code: number, - cons: (enemy: IEnemy) => ISpecial - ): void { + registerSpecial(code: number, cons: SpecialCreation): void { this.specialRegistry.set(code, cons); } @@ -41,7 +32,7 @@ export class EnemyManager implements IEnemyManager { this.attributeRegistry.set(name, defaultValue); } - fromLegacyEnemy(enemy: Enemy): IEnemy { + fromLegacyEnemy(enemy: Enemy): IEnemy { // 如果该旧样板怪物已经通过 addPrefabFromLegacy 注册为模板,直接克隆模板 const existingCode = this.legacyIdToCode.get(enemy.id); if (existingCode) { @@ -54,21 +45,36 @@ export class EnemyManager implements IEnemyManager { return this.convertLegacyEnemy(0, enemy); } + /** + * 根据旧样板怪物与注册过的默认属性构造属性对象 + * @param enemy 旧样板怪物对象 + */ + private createAttributes(enemy: Enemy): TAttr { + const attrs: Record = {}; + for (const [name, defaultValue] of this.attributeRegistry) { + attrs[name] = structuredClone(defaultValue); + } + attrs.hp = enemy.hp; + attrs.atk = enemy.atk; + attrs.def = enemy.def; + attrs.money = enemy.money; + attrs.exp = enemy.exp; + attrs.point = enemy.point; + return attrs as TAttr; + } + /** * 真正执行旧样板怪物到新怪物对象的转换 * @param code 怪物图块数字 * @param enemy 旧样板怪物对象 */ - private convertLegacyEnemy(code: number, enemy: Enemy): IEnemy { - const attrs: IEnemyAttributes = { - hp: enemy.hp, - atk: enemy.atk, - def: enemy.def, - money: enemy.money, - exp: enemy.exp, - point: enemy.point - }; - const result = new EnemyImpl(enemy.id, code, structuredClone(attrs)); + private convertLegacyEnemy(code: number, enemy: Enemy): IEnemy { + const attrs = this.createAttributes(enemy); + const result = new EnemyImpl( + enemy.id, + code, + structuredClone(attrs) + ); // 转换特殊属性 if (enemy.special) { @@ -84,19 +90,19 @@ export class EnemyManager implements IEnemyManager { return result; } - createEnemy(code: number): IEnemy | null { + createEnemy(code: number): IEnemy | null { const prefab = this.prefabByCode.get(code); if (!prefab) return null; return prefab.clone(); } - createEnemyById(id: string): IEnemy | null { + createEnemyById(id: string): IEnemy | null { const prefab = this.prefabById.get(id); if (!prefab) return null; return prefab.clone(); } - addPrefab(enemy: IEnemy): void { + addPrefab(enemy: IEnemy): void { if ( this.prefabByCode.has(enemy.code) || this.prefabById.has(enemy.id) @@ -118,11 +124,11 @@ export class EnemyManager implements IEnemyManager { this.legacyIdToCode.set(enemy.id, code); } - getPrefab(code: number): IEnemy | null { + getPrefab(code: number): IEnemy | null { return this.prefabByCode.get(code) ?? null; } - getPrefabById(id: string): IEnemy | null { + getPrefabById(id: string): IEnemy | null { return this.prefabById.get(id) ?? null; } @@ -136,7 +142,7 @@ export class EnemyManager implements IEnemyManager { this.prefabById.delete(prefab.id); } - changePrefab(code: number | string, enemy: IEnemy): void { + changePrefab(code: number | string, enemy: IEnemy): void { // 先删除旧的模板(如果存在) this.deletePrefab(code); // 再添加新的模板 diff --git a/packages-user/data-base/src/enemy/mapDamage.ts b/packages-user/data-base/src/enemy/mapDamage.ts index a38f588..8777a75 100644 --- a/packages-user/data-base/src/enemy/mapDamage.ts +++ b/packages-user/data-base/src/enemy/mapDamage.ts @@ -18,25 +18,25 @@ interface IPointInfo { readonly affectedBy: Set>; } -interface IViewStore { +interface IViewStore { /** 该地图伤害视图所影响的伤害信息 */ readonly damages: Map>; /** 当前视图所属的怪物视图 */ - readonly enemy: IEnemyView; + readonly enemy: IEnemyView; } -interface IDamageStore { +interface IDamageStore { /** 该地图伤害信息的地图伤害视图来源 */ readonly sourceView: IMapDamageView; /** 地图伤害信息的来源怪物 */ - readonly sourceEnemy: IEnemyView; + readonly sourceEnemy: IEnemyView; /** 该地图伤害信息所处的索引 */ readonly index: number; } -export class MapDamage implements IMapDamage { +export class MapDamage implements IMapDamage { /** 当前使用的地图伤害转换器 */ - private converter: IMapDamageConverter | null = null; + private converter: IMapDamageConverter | null = null; /** 当前使用的地图伤害合并器 */ private reducer: IMapDamageReducer | null = null; @@ -45,23 +45,27 @@ export class MapDamage implements IMapDamage { /** 有来源地图伤害,坐标 -> 点伤害信息 */ private readonly sourcedDamage: Map = new Map(); /** 地图伤害视图 -> 其信息对象 */ - private readonly viewStore: Map = new Map(); - /** 地图伤害信息 -> 其信息对象 */ - private readonly damageStore: Map = new Map(); - /** 怪物视图 -> 其影响对象 */ - private readonly enemyStore: Map> = + private readonly viewStore: Map, IViewStore> = new Map(); + /** 地图伤害信息 -> 其信息对象 */ + private readonly damageStore: Map> = + new Map(); + /** 怪物视图 -> 其影响对象 */ + private readonly enemyStore: Map< + IEnemyView, + Set> + > = new Map(); /** 需要延迟刷新的坐标索引 */ private readonly dirtyIndexes: Set = new Set(); /** 合并后伤害缓存,索引 -> 合并结果 */ private readonly reducedCache: Map = new Map(); constructor( - readonly context: IEnemyContext, + readonly context: IEnemyContext, readonly indexer: IMapLocIndexer ) {} - useConverter(converter: IMapDamageConverter): void { + useConverter(converter: IMapDamageConverter): void { this.converter = converter; this.refreshAll(); } @@ -102,7 +106,7 @@ export class MapDamage implements IMapDamage { this.markDirtyIndex(this.indexer.locaterToIndex(locator)); } - markEnemyDirty(view: IEnemyView): void { + markEnemyDirty(view: IEnemyView): void { const store = this.enemyStore.get(view); const locator = this.context.getEnemyLocatorByView(view); if (!store) { @@ -117,7 +121,7 @@ export class MapDamage implements IMapDamage { this.refreshEnemyAndClearCache(view, locator); } - deleteEnemy(view: IEnemyView): void { + deleteEnemy(view: IEnemyView): void { const store = this.enemyStore.get(view); if (!store) return; const collection = new Set(); @@ -206,7 +210,7 @@ export class MapDamage implements IMapDamage { * 移除指定怪物所产生的地图伤害 * @param view 怪物视图 */ - private removeEnemyAffecting(view: IEnemyView) { + private removeEnemyAffecting(view: IEnemyView) { const views = this.enemyStore.get(view); if (!views) return; views.forEach(viewItem => { @@ -227,7 +231,10 @@ export class MapDamage implements IMapDamage { /** * 刷新指定位置的怪物地图伤害,并执行刷新缓存的操作 */ - private refreshEnemyAndClearCache(view: IEnemyView, locator: ITileLocator) { + private refreshEnemyAndClearCache( + view: IEnemyView, + locator: ITileLocator + ) { this.removeEnemyAffecting(view); const enemy = view.getComputedEnemy(); const views = this.converter!.convert(enemy, locator, this.context); @@ -265,7 +272,7 @@ export class MapDamage implements IMapDamage { /** * 刷新指定位置的怪物地图伤害 */ - private refreshEnemy(view: IEnemyView, locator: ITileLocator) { + private refreshEnemy(view: IEnemyView, locator: ITileLocator) { this.removeEnemyAffecting(view); const enemy = view.getComputedEnemy(); const views = this.converter!.convert(enemy, locator, this.context); diff --git a/packages-user/data-base/src/enemy/special.ts b/packages-user/data-base/src/enemy/special.ts index 87cd8ed..7a7a66a 100644 --- a/packages-user/data-base/src/enemy/special.ts +++ b/packages-user/data-base/src/enemy/special.ts @@ -78,18 +78,18 @@ export class NonePropertySpecial implements ISpecial { } } -export function defineCommonSerializableSpecial( +export function defineCommonSerializableSpecial( code: number, value: T, config: ICommonSerializableSpecialConfig -): SpecialCreation { +): SpecialCreation { return () => new CommonSerializableSpecial(code, structuredClone(value), config); } -export function defineNonePropertySpecial( +export function defineNonePropertySpecial( code: number, config: ICommonSerializableSpecialConfig -): SpecialCreation { +): SpecialCreation { return () => new NonePropertySpecial(code, config); } diff --git a/packages-user/data-base/src/enemy/types.ts b/packages-user/data-base/src/enemy/types.ts index aa48cda..1b937ed 100644 --- a/packages-user/data-base/src/enemy/types.ts +++ b/packages-user/data-base/src/enemy/types.ts @@ -1,21 +1,6 @@ import { IRange } from '@motajs/common'; import { ITileLocator } from '@user/types'; -export interface IEnemyAttributes { - /** 怪物生命值 */ - hp: number; - /** 怪物攻击力 */ - atk: number; - /** 怪物防御力 */ - def: number; - /** 怪物金币 */ - money: number; - /** 怪物经验值 */ - exp: number; - /** 怪物加点量 */ - point: number; -} - export interface ISpecial { /** 特殊属性代码 */ readonly code: number; @@ -55,7 +40,7 @@ export interface ISpecial { clone(): ISpecial; } -export interface IReadonlyEnemy { +export interface IReadonlyEnemy { /** 怪物标识符 */ readonly id: string; /** 怪物在地图上的标识数字 */ @@ -82,24 +67,20 @@ export interface IReadonlyEnemy { * 获取怪物属性值 * @param key 属性名称 */ - getAttribute(key: K): IEnemyAttributes[K]; + getAttribute(key: K): TAttr[K]; + + /** + * 深拷贝怪物属性并将其返回 + */ + cloneAttributes(): TAttr; /** * 深拷贝此怪物对象 */ - clone(): IReadonlyEnemy; + clone(): IReadonlyEnemy; } -export interface IEnemy extends IReadonlyEnemy { - /** 怪物标识符 */ - readonly id: string; - /** 怪物在地图上的标识数字 */ - readonly code: number; - /** 怪物属性值 */ - readonly attributes: Readonly; - /** 怪物拥有的特殊属性列表 */ - readonly specials: Set>; - +export interface IEnemy extends IReadonlyEnemy { /** * 添加特殊属性 * @param special 特殊属性对象 @@ -117,32 +98,29 @@ export interface IEnemy extends IReadonlyEnemy { * @param key 属性名称 * @param value 新的属性值 */ - setAttribute( - key: K, - value: IEnemyAttributes[K] - ): void; + setAttribute(key: K, value: TAttr[K]): void; /** * 深拷贝此怪物对象 */ - clone(): IEnemy; + clone(): IEnemy; /** * 从一个怪物对象中将属性复制到当前对象 * @param enemy 怪物对象 */ - copy(enemy: IReadonlyEnemy): void; + copyFrom(enemy: IReadonlyEnemy): void; } -export type SpecialCreation = (enemy: IEnemy) => ISpecial; +export type SpecialCreation = (enemy: IEnemy) => ISpecial; -export interface IEnemyManager { +export interface IEnemyManager { /** * 注册一个特殊属性 * @param code 特殊属性代码 * @param cons 特殊属性创建函数 */ - registerSpecial(code: number, cons: SpecialCreation): void; + registerSpecial(code: number, cons: SpecialCreation): void; /** * 注册一个怪物属性 @@ -155,26 +133,26 @@ export interface IEnemyManager { * 根据旧样板怪物对象生成一个新的怪物对象 * @param enemy 旧样板怪物对象 */ - fromLegacyEnemy(enemy: Enemy): IEnemy; + fromLegacyEnemy(enemy: Enemy): IEnemy; /** * 创建怪物对象,如果对应数字的怪物不存在则会返回 `null` * @param code 怪物图块数字 */ - createEnemy(code: number): IEnemy | null; + createEnemy(code: number): IEnemy | null; /** * 根据怪物的 `id` 创建怪物对象,如果对应的怪物不存在则会返回 `null` * @param id 怪物 `id` */ - createEnemyById(id: string): IEnemy | null; + createEnemyById(id: string): IEnemy | null; /** * 添加怪物模板,如果 `id` 或 `code` 与已有的冲突,则不会做任何操作, * 如果需要修改怪物模板,请使用 {@link changePrefab} * @param enemy 怪物对象 */ - addPrefab(enemy: IEnemy): void; + addPrefab(enemy: IEnemy): void; /** * 从旧样板的怪物对象中添加怪物模板 @@ -187,13 +165,13 @@ export interface IEnemyManager { * 获取指定怪物的模板 * @param code 怪物图块数字 */ - getPrefab(code: number): IEnemy | null; + getPrefab(code: number): IEnemy | null; /** * 根据怪物的 `id` 获取对应的怪物模板 * @param id 怪物 `id` */ - getPrefabById(id: string): IEnemy | null; + getPrefabById(id: string): IEnemy | null; /** * 删除指定的怪物模板 @@ -206,7 +184,7 @@ export interface IEnemyManager { * @param code 怪物的图块数字或 `id` * @param enemy 新的怪物模板 */ - changePrefab(code: number | string, enemy: IEnemy): void; + changePrefab(code: number | string, enemy: IEnemy): void; } //#region 辅助接口 @@ -244,9 +222,9 @@ export interface IMapLocIndexer extends IMapLocHelper { //#region 怪物对象 -export interface IEnemyView { +export interface IEnemyView { /** 怪物视图所属的上下文 */ - readonly context: IEnemyContext; + readonly context: IEnemyContext; /** * 重置此怪物视图的状态,将计算后怪物对象恢复至初始状态 @@ -256,18 +234,18 @@ export interface IEnemyView { /** * 获取基本怪物对象 */ - getBaseEnemy(): IReadonlyEnemy; + getBaseEnemy(): IReadonlyEnemy; /** * 获取计算后的怪物对象,返回的怪物对象同引用 */ - getComputedEnemy(): IReadonlyEnemy; + getComputedEnemy(): IReadonlyEnemy; /** * 获取可修改的怪物对象。如果修改此方法获取的怪物对象,那么怪物的真实信息是不会刷新的, * 需要手动调用 markDirty 方法来刷新。 */ - getModifiableEnemy(): IEnemy; + getModifiableEnemy(): IEnemy; /** * 将此怪物标记为脏,需要更新 @@ -279,20 +257,23 @@ export interface IEnemyView { //#region 光环与查询 -export interface IEnemySpecialModifier { +export interface IEnemySpecialModifier { /** * 获取要添加到指定怪物身上的特殊属性 * @param enemy 怪物对象 * @param locator 怪物定位符 */ - add(enemy: IReadonlyEnemy, locator: ITileLocator): ISpecial[]; + add(enemy: IReadonlyEnemy, locator: ITileLocator): ISpecial[]; /** * 获取制定怪物身上要删除的特殊属性 * @param enemy 怪物对象 * @param locator 怪物定位符 */ - delete(enemy: IReadonlyEnemy, locator: ITileLocator): ISpecial[]; + delete( + enemy: IReadonlyEnemy, + locator: ITileLocator + ): ISpecial[]; /** * 修改一个怪物的特殊属性,如果真正进行了修改则返回 true,否则返回 false @@ -301,13 +282,13 @@ export interface IEnemySpecialModifier { * @param locator 怪物定位符 */ modify( - enemy: IReadonlyEnemy, + enemy: IReadonlyEnemy, special: ISpecial, locator: ITileLocator ): boolean; } -export interface IAuraView { +export interface IAuraView { /** 此光环视图的优先级 */ readonly priority: number; /** 此光环视图的影响范围 */ @@ -326,42 +307,44 @@ export interface IAuraView { /** * 对指定怪物对象施加修饰器 * @param enemy 怪物对象 + * @param baseEnemy 原始怪物对象,即未进行任何修改的怪物对象 * @param locator 怪物定位符 */ apply( - enemy: IEnemy, - baseEnemy: IReadonlyEnemy, + enemy: IEnemy, + baseEnemy: IReadonlyEnemy, locator: ITileLocator ): void; /** * 对指定怪物对象添加特殊属性修饰器 * @param enemy 怪物对象 + * @param baseEnemy 原始怪物对象,即未进行任何修改的怪物对象 * @param locator 怪物定位符 */ applySpecial( - enemy: IReadonlyEnemy, - baseEnemy: IReadonlyEnemy, + enemy: IReadonlyEnemy, + baseEnemy: IReadonlyEnemy, locator: ITileLocator - ): IEnemySpecialModifier | null; + ): IEnemySpecialModifier | null; } -export interface IEnemyAuraView extends IAuraView { +export interface IEnemyAuraView extends IAuraView { /** 此光环视图所属的怪物 */ - readonly enemy: IReadonlyEnemy; + readonly enemy: IReadonlyEnemy; /** 此光环视图所属的特殊属性 */ readonly special: ISpecial; /** 此光环视图所属怪物的定位符 */ readonly locator: ITileLocator; } -export interface IAuraConverter { +export interface IAuraConverter { /** * 判断一个特殊属性是否应该被当前光环转换器执行转换 */ shouldConvert( special: ISpecial, - enemy: IReadonlyEnemy, + enemy: IReadonlyEnemy, locator: ITileLocator ): boolean; @@ -370,29 +353,32 @@ export interface IAuraConverter { */ convert( special: ISpecial, - enemy: IReadonlyEnemy, - locator: ITileLocator - ): IEnemyAuraView; + enemy: IReadonlyEnemy, + locator: ITileLocator, + context: IEnemyContext + ): IEnemyAuraView; } -export interface IEnemySpecialQueryModifier extends IEnemySpecialModifier { +export interface IEnemySpecialQueryModifier< + TAttr +> extends IEnemySpecialModifier { /** * 判断一个怪物是否应该查询外部状态 */ - shouldQuery(enemy: IReadonlyEnemy, locator: ITileLocator): boolean; + shouldQuery(enemy: IReadonlyEnemy, locator: ITileLocator): boolean; } -export interface IEnemySpecialQueryEffect { +export interface IEnemySpecialQueryEffect { /** 效果优先级,与光环属性共用 */ readonly priority: number; /** * 根据传入的怪物上下文,获取对应的怪物特殊属性修饰器 */ - for(ctx: IEnemyContext): IEnemySpecialQueryModifier; + for(ctx: IEnemyContext): IEnemySpecialQueryModifier; } -export interface IEnemyCommonQueryEffect { +export interface IEnemyCommonQueryEffect { /** 优先级,越高的越先执行 */ readonly priority: number; @@ -400,21 +386,21 @@ export interface IEnemyCommonQueryEffect { * 对怪物的某个特殊属性施加常规查询效果 */ apply( - enemy: IEnemy, + enemy: IEnemy, special: ISpecial, - query: () => IEnemyContext, + query: () => IEnemyContext, locator: ITileLocator ): void; } -export interface IEnemyFinalEffect { +export interface IEnemyFinalEffect { /** 效果优先级,越高会越先被执行 */ readonly priority: number; /** * 向怪物施加最终修饰效果 */ - apply(enemy: IEnemy, locator: ITileLocator): void; + apply(enemy: IEnemy, locator: ITileLocator): void; } //#endregion @@ -438,10 +424,14 @@ export interface IMapDamageInfo { } export interface IMapDamageView { - /** 获取地图伤害影响范围 */ + /** + * 获取地图伤害影响范围 + */ getRange(): IRange; - /** 获取范围参数 */ + /** + * 获取范围参数 + */ getRangeParam(): T; /** @@ -451,7 +441,7 @@ export interface IMapDamageView { getDamageAt(locator: ITileLocator): Readonly | null; /** - * 获取指定位置的地图伤害,但是不会对坐标进行判断 + * 获取指定位置的地图伤害,会对坐标进行判断 * @param locator 伤害位置 */ getDamageWithoutCheck( @@ -459,32 +449,36 @@ export interface IMapDamageView { ): Readonly | null; } -export interface IMapDamageConverter { - /** 转换地图伤害视图 */ +export interface IMapDamageConverter { + /** + * 转换地图伤害视图 + */ convert( - enemy: IReadonlyEnemy, + enemy: IReadonlyEnemy, locator: ITileLocator, - context: IEnemyContext + context: IEnemyContext ): IMapDamageView[]; } export interface IMapDamageReducer { - /** 对伤害信息进行合并 */ + /** + * 对伤害信息进行合并 + */ reduce( info: Iterable>, locator: ITileLocator ): Readonly; } -export interface IMapDamage { +export interface IMapDamage { /** 当前绑定的怪物上下文 */ - readonly context: IEnemyContext; + readonly context: IEnemyContext; /** * 设置地图伤害转换器,并基于当前上下文重建所有地图伤害视图 * @param converter 地图伤害转换器 */ - useConverter(converter: IMapDamageConverter): void; + useConverter(converter: IMapDamageConverter): void; /** * 设置地图伤害合并器 @@ -516,7 +510,7 @@ export interface IMapDamage { * 将指定怪物对应的地图伤害标记为脏并刷新 * @param view 怪物视图 */ - markEnemyDirty(view: IEnemyView): void; + markEnemyDirty(view: IEnemyView): void; /** * 基于当前上下文重新刷新全部有来源地图伤害 @@ -527,7 +521,7 @@ export interface IMapDamage { * 删除指定怪物带来的全部地图伤害来源 * @param view 怪物视图 */ - deleteEnemy(view: IEnemyView): void; + deleteEnemy(view: IEnemyView): void; /** * 获取指定位置合并后的地图伤害 @@ -548,7 +542,7 @@ export interface IMapDamage { //#region 上下文 -export interface IEnemyContext { +export interface IEnemyContext { /** 怪物上下文宽度 */ readonly width: number; /** 怪物上下文高度 */ @@ -565,32 +559,35 @@ export interface IEnemyContext { * 注册一个光环转换器 * @param converter 光环转换器 */ - registerAuraConverter(converter: IAuraConverter): void; + registerAuraConverter(converter: IAuraConverter): void; /** * 注销一个光环转换器 * @param converter 光环转换器 */ - unregisterAuraConverter(converter: IAuraConverter): void; + unregisterAuraConverter(converter: IAuraConverter): void; /** * 设置光环转换器的启用状态 * @param converter 光环转换器 * @param enabled 是否启用 */ - setAuraConverterEnabled(converter: IAuraConverter, enabled: boolean): void; + setAuraConverterEnabled( + converter: IAuraConverter, + enabled: boolean + ): void; /** * 注册一个特殊属性查询效果 * @param effect 特殊属性查询效果 */ - registerSpecialQueryEffect(effect: IEnemySpecialQueryEffect): void; + registerSpecialQueryEffect(effect: IEnemySpecialQueryEffect): void; /** * 注销一个特殊属性查询效果 * @param effect 特殊属性查询效果 */ - unregisterSpecialQueryEffect(effect: IEnemySpecialQueryEffect): void; + unregisterSpecialQueryEffect(effect: IEnemySpecialQueryEffect): void; /** * 为指定特殊属性代码注册常规查询效果 @@ -599,7 +596,7 @@ export interface IEnemyContext { */ registerCommonQueryEffect( code: number, - effect: IEnemyCommonQueryEffect + effect: IEnemyCommonQueryEffect ): void; /** @@ -609,58 +606,60 @@ export interface IEnemyContext { */ unregisterCommonQueryEffect( code: number, - effect: IEnemyCommonQueryEffect + effect: IEnemyCommonQueryEffect ): void; /** * 注册一个最终效果 * @param effect 最终效果 */ - registerFinalEffect(effect: IEnemyFinalEffect): void; + registerFinalEffect(effect: IEnemyFinalEffect): void; /** * 注销一个最终效果 * @param effect 最终效果 */ - unregisterFinalEffect(effect: IEnemyFinalEffect): void; + unregisterFinalEffect(effect: IEnemyFinalEffect): void; /** * 获取指定怪物对象当前所在位置 * @param enemy 怪物对象 */ - getEnemyLocator(enemy: IEnemy): Readonly | null; + getEnemyLocator(enemy: IEnemy): Readonly | null; /** * 获取指定怪物视图当前所在位置 * @param view 怪物视图 */ - getEnemyLocatorByView(view: IEnemyView): Readonly | null; + getEnemyLocatorByView( + view: IEnemyView + ): Readonly | null; /** * 根据定位符获取怪物视图 * @param locator 地图定位符 */ - getEnemyByLocator(locator: ITileLocator): IEnemyView | null; + getEnemyByLocator(locator: ITileLocator): IEnemyView | null; /** * 根据坐标获取怪物视图 * @param x 横坐标 * @param y 纵坐标 */ - getEnemyByLoc(x: number, y: number): IEnemyView | null; + getEnemyByLoc(x: number, y: number): IEnemyView | null; /** * 根据计算后怪物对象反查怪物视图 * @param enemy 计算后怪物对象 */ - getViewByComputed(enemy: IReadonlyEnemy): IEnemyView | null; + getViewByComputed(enemy: IReadonlyEnemy): IEnemyView | null; /** * 在指定位置放置一个怪物对象 * @param locator 地图定位符 * @param enemy 怪物对象 */ - setEnemyAt(locator: ITileLocator, enemy: IEnemy): void; + setEnemyAt(locator: ITileLocator, enemy: IEnemy): void; /** * 删除指定位置的怪物 @@ -673,35 +672,35 @@ export interface IEnemyContext { * @param range 范围对象 * @param param 范围参数 */ - scanRange(range: IRange, param: T): Iterable; + scanRange(range: IRange, param: T): Iterable>; /** * 迭代上下文中的全部怪物 */ - iterateEnemy(): Iterable<[ITileLocator, IEnemyView]>; + iterateEnemy(): Iterable<[ITileLocator, IEnemyView]>; /** * 添加一个全局光环视图 * @param aura 光环视图 */ - addAura(aura: IAuraView): void; + addAura(aura: IAuraView): void; /** * 删除一个全局光环视图 * @param aura 光环视图 */ - deleteAura(aura: IAuraView): void; + deleteAura(aura: IAuraView): void; /** * 绑定地图伤害管理器 * @param damage 地图伤害管理器 */ - attachMapDamage(damage: IMapDamage | null): void; + attachMapDamage(damage: IMapDamage | null): void; /** * 获取当前绑定的地图伤害管理器 */ - getMapDamage(): IMapDamage | null; + getMapDamage(): IMapDamage | null; /** * 重建当前上下文中的全部怪物计算结果 @@ -717,13 +716,13 @@ export interface IEnemyContext { * 将指定怪物视图标记为脏 * @param view 怪物视图 */ - markDirty(view: IEnemyView): void; + markDirty(view: IEnemyView): void; /** * 申请刷新指定怪物视图 * @param view 怪物视图 */ - requestRefresh(view: IEnemyView): void; + requestRefresh(view: IEnemyView): void; /** * 清空当前上下文中的所有对象与运行状态 diff --git a/packages-user/data-state/src/data.ts b/packages-user/data-state/src/data.ts index 64669b0..826f730 100644 --- a/packages-user/data-state/src/data.ts +++ b/packages-user/data-state/src/data.ts @@ -1,12 +1,13 @@ import { EnemyManager, IEnemyManager } from '@user/data-base'; +import { IEnemyAttributes } from './enemy/types'; import { IGameDataState } from './types'; import { registerSpecials } from './enemy'; export class GameDataState implements IGameDataState { - readonly enemyManager: IEnemyManager; + readonly enemyManager: IEnemyManager; constructor() { - this.enemyManager = new EnemyManager(); + this.enemyManager = new EnemyManager(); registerSpecials(this.enemyManager); } } diff --git a/packages-user/data-state/src/enemy/aura.ts b/packages-user/data-state/src/enemy/aura.ts index 8835e29..0c23d4a 100644 --- a/packages-user/data-state/src/enemy/aura.ts +++ b/packages-user/data-state/src/enemy/aura.ts @@ -9,13 +9,16 @@ import { import { IAuraConverter, IEnemyAuraView, + IEnemyContext, IEnemySpecialModifier, + IEnemyView, IReadonlyEnemy, ISpecial, IEnemy } from '@user/data-base'; import { IHaloValue } from './special'; import { ITileLocator } from '@user/types'; +import { IEnemyAttributes } from './types'; const FULL_RANGE = new FullRange(); const RECT_RANGE = new RectRange(); @@ -23,32 +26,32 @@ const MANHATTAN_RANGE = new ManhattanRange(); //#region 25-光环 -export class CommonAuraConverter implements IAuraConverter { +export class CommonAuraConverter implements IAuraConverter { shouldConvert(special: ISpecial): boolean { return special.code === 25; } convert( special: ISpecial, - enemy: IReadonlyEnemy, + enemy: IReadonlyEnemy, locator: ITileLocator - ): IEnemyAuraView { + ): CommonAura { return new CommonAura(enemy, special as ISpecial, locator); } } export class CommonAura implements IEnemyAuraView< + IEnemyAttributes, IRectRangeParam | IManhattanRangeParam | void, IHaloValue > { readonly priority: number = 25; readonly couldApplyBase: boolean = true; readonly couldApplySpecial: boolean = false; - readonly range: IRange; constructor( - readonly enemy: IReadonlyEnemy, + readonly enemy: IReadonlyEnemy, readonly special: ISpecial, readonly locator: ITileLocator ) { @@ -85,7 +88,10 @@ export class CommonAura implements IEnemyAuraView< }; } - apply(enemy: IEnemy, baseEnemy: IReadonlyEnemy): void { + apply( + enemy: IEnemy, + baseEnemy: IReadonlyEnemy + ): void { const { hpBuff, atkBuff, defBuff } = this.special.value; if (hpBuff !== 0) { @@ -113,7 +119,78 @@ export class CommonAura implements IEnemyAuraView< } } - applySpecial(): IEnemySpecialModifier | null { + applySpecial(): IEnemySpecialModifier | null { + return null; + } +} + +//#endregion + +//#region 26-支援 + +export class GuardAuraConverter implements IAuraConverter { + shouldConvert(special: ISpecial): boolean { + return special.code === 26; + } + + convert( + special: ISpecial, + enemy: IReadonlyEnemy, + locator: ITileLocator, + context: IEnemyContext + ): GuardAura { + return new GuardAura( + context, + enemy, + special as ISpecial, + locator + ); + } +} + +export class GuardAura implements IEnemyAuraView< + IEnemyAttributes, + IRectRangeParam, + void +> { + readonly priority: number = 26; + readonly couldApplyBase: boolean = true; + readonly couldApplySpecial: boolean = false; + readonly range: IRange = RECT_RANGE; + + private readonly sourceView: IEnemyView | null; + + constructor( + context: IEnemyContext, + readonly enemy: IReadonlyEnemy, + readonly special: ISpecial, + readonly locator: ITileLocator + ) { + this.sourceView = context.getViewByComputed(enemy); + } + + getRangeParam(): IRectRangeParam { + return { + x: this.locator.x - 1, + y: this.locator.y - 1, + w: 3, + h: 3 + }; + } + + apply( + enemy: IEnemy, + _baseEnemy: IReadonlyEnemy, + locator: ITileLocator + ): void { + if (!this.sourceView) return; + if (locator.x === this.locator.x && locator.y === this.locator.y) { + return; + } + enemy.getAttribute('guard').add(this.sourceView); + } + + applySpecial(): IEnemySpecialModifier | null { return null; } } diff --git a/packages-user/data-state/src/enemy/mapSpecials.ts b/packages-user/data-state/src/enemy/mapSpecials.ts index 100355c..3499691 100644 --- a/packages-user/data-state/src/enemy/mapSpecials.ts +++ b/packages-user/data-state/src/enemy/mapSpecials.ts @@ -21,7 +21,7 @@ import { IMapDamageView } from '@user/data-base'; import { IZoneValue } from './special'; -import { MapDamageType } from './types'; +import { IEnemyAttributes, MapDamageType } from './types'; const RECT_RANGE = new RectRange(); const MANHATTAN_RANGE = new ManhattanRange(); @@ -33,7 +33,7 @@ const DIR4 = [...DIRECTION_MAPPER.map(InternalDirectionGroup.Dir4)]; //#region 地图伤害 abstract class BaseMapDamageView implements IMapDamageView { - constructor(protected readonly context: IEnemyContext) {} + constructor(protected readonly context: IEnemyContext) {} abstract getRange(): IRange; @@ -94,7 +94,7 @@ export class ZoneDamageView extends BaseMapDamageView< IRectRangeParam | IManhattanRangeParam > { constructor( - context: IEnemyContext, + context: IEnemyContext, private readonly locator: Readonly, private readonly special: Readonly> ) { @@ -131,7 +131,7 @@ export class ZoneDamageView extends BaseMapDamageView< export class RepulseDamageView extends BaseMapDamageView { constructor( - context: IEnemyContext, + context: IEnemyContext, private readonly locator: Readonly, private readonly special: Readonly> ) { @@ -165,7 +165,7 @@ export class RepulseDamageView extends BaseMapDamageView { export class LaserDamageView extends BaseMapDamageView { constructor( - context: IEnemyContext, + context: IEnemyContext, private readonly locator: Readonly, private readonly special: Readonly>, private readonly dir: IDirectionDescriptor[] = DIR4 @@ -200,7 +200,7 @@ export class BetweenDamageView extends BaseMapDamageView { private static readonly DAMAGE = 1; constructor( - context: IEnemyContext, + context: IEnemyContext, private readonly locator: Readonly ) { super(context); @@ -250,7 +250,7 @@ export class BetweenDamageView extends BaseMapDamageView { export class AmbushDamageView extends BaseMapDamageView { constructor( - context: IEnemyContext, + context: IEnemyContext, private readonly locator: Readonly ) { super(context); @@ -285,11 +285,11 @@ export class AmbushDamageView extends BaseMapDamageView { //#region 转换器 -export class MainMapDamageConverter implements IMapDamageConverter { +export class MainMapDamageConverter implements IMapDamageConverter { convert( - enemy: IReadonlyEnemy, + enemy: IReadonlyEnemy, locator: ITileLocator, - context: IEnemyContext + context: IEnemyContext ): IMapDamageView[] { const views: IMapDamageView[] = []; diff --git a/packages-user/data-state/src/enemy/special.ts b/packages-user/data-state/src/enemy/special.ts index 6690058..3f46fd3 100644 --- a/packages-user/data-state/src/enemy/special.ts +++ b/packages-user/data-state/src/enemy/special.ts @@ -4,6 +4,7 @@ import { IEnemyManager } from '@user/data-base'; import { getHeroStatusOn } from '../legacy/hero'; +import { IEnemyAttributes } from './types'; //#region 复合属性值类型 @@ -47,7 +48,11 @@ export interface IHaloValue { * 8. 重生属性:还在脚本编辑的 changingFloor * 9. 阻击 | 捕捉 的每步效果:packages-user/legacy-plugin-data/src/enemy/checkblock.ts */ -export function registerSpecials(manager: IEnemyManager): void { +export function registerSpecials( + manager: IEnemyManager +): void { + manager.registerAttribute('guard', new Set()); + // 0 - 空 manager.registerSpecial( 0, diff --git a/packages-user/data-state/src/enemy/types.ts b/packages-user/data-state/src/enemy/types.ts index 7a8c5d0..4e2ddda 100644 --- a/packages-user/data-state/src/enemy/types.ts +++ b/packages-user/data-state/src/enemy/types.ts @@ -1,3 +1,22 @@ +import { IEnemyView } from '@user/data-base'; + +export interface IEnemyAttributes { + /** 怪物生命值 */ + hp: number; + /** 怪物攻击力 */ + atk: number; + /** 怪物防御力 */ + def: number; + /** 怪物金币 */ + money: number; + /** 怪物经验值 */ + exp: number; + /** 怪物加点量 */ + point: number; + /** 支援来源怪物视图列表 */ + guard: Set>; +} + export const enum MapDamageType { /** 未知伤害 */ Unknown, diff --git a/packages-user/data-state/src/types.ts b/packages-user/data-state/src/types.ts index ba4fc5b..7565083 100644 --- a/packages-user/data-state/src/types.ts +++ b/packages-user/data-state/src/types.ts @@ -2,10 +2,11 @@ import { ILayerState } from './map'; import { IHeroFollower, IHeroState } from './hero'; import { IRoleFaceBinder } from './common'; import { IEnemyManager } from '@user/data-base'; +import { IEnemyAttributes } from './enemy/types'; export interface IGameDataState { /** 怪物管理器 */ - readonly enemyManager: IEnemyManager; + readonly enemyManager: IEnemyManager; } export interface IStateSaveData {