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