mirror of
https://github.com/motajs/template.git
synced 2026-05-02 12:23:13 +08:00
feat: 伤害计算系统
This commit is contained in:
parent
4c0960fff7
commit
0517da5000
@ -3,6 +3,7 @@ import { ITileLocator } from '@user/types';
|
|||||||
import {
|
import {
|
||||||
IAuraConverter,
|
IAuraConverter,
|
||||||
IAuraView,
|
IAuraView,
|
||||||
|
IDamageSystem,
|
||||||
IEnemy,
|
IEnemy,
|
||||||
IEnemyAuraView,
|
IEnemyAuraView,
|
||||||
IEnemyCommonQueryEffect,
|
IEnemyCommonQueryEffect,
|
||||||
@ -53,6 +54,7 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
private readonly dirtyEnemy: Set<IEnemyView<TAttr>> = new Set();
|
private readonly dirtyEnemy: Set<IEnemyView<TAttr>> = new Set();
|
||||||
|
|
||||||
private mapDamage: IMapDamage<TAttr> | null = null;
|
private mapDamage: IMapDamage<TAttr> | null = null;
|
||||||
|
private damageSystem: IDamageSystem<TAttr, unknown> | null = null;
|
||||||
readonly indexer: MapLocIndexer = new MapLocIndexer();
|
readonly indexer: MapLocIndexer = new MapLocIndexer();
|
||||||
|
|
||||||
private needUpdate: boolean = true;
|
private needUpdate: boolean = true;
|
||||||
@ -174,6 +176,9 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
if (this.mapDamage) {
|
if (this.mapDamage) {
|
||||||
this.mapDamage.deleteEnemy(view);
|
this.mapDamage.deleteEnemy(view);
|
||||||
}
|
}
|
||||||
|
if (this.damageSystem) {
|
||||||
|
this.damageSystem.deleteEnemy(view);
|
||||||
|
}
|
||||||
|
|
||||||
this.needTotallyRefresh.delete(view);
|
this.needTotallyRefresh.delete(view);
|
||||||
this.dirtyEnemy.delete(view);
|
this.dirtyEnemy.delete(view);
|
||||||
@ -253,6 +258,15 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
return this.mapDamage;
|
return this.mapDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachDamageSystem(system: IDamageSystem<TAttr, unknown>): void {
|
||||||
|
this.damageSystem = system;
|
||||||
|
system.markAllDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
getDamageSystem<THero>(): IDamageSystem<TAttr, THero> | null {
|
||||||
|
return this.damageSystem as IDamageSystem<TAttr, THero> | null;
|
||||||
|
}
|
||||||
|
|
||||||
private convertSpecial(
|
private convertSpecial(
|
||||||
special: ISpecial<any>,
|
special: ISpecial<any>,
|
||||||
enemy: IReadonlyEnemy<TAttr>,
|
enemy: IReadonlyEnemy<TAttr>,
|
||||||
@ -545,6 +559,10 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
this.buildupFinal();
|
this.buildupFinal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.damageSystem) {
|
||||||
|
this.damageSystem.markAllDirty();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.mapDamage) {
|
if (this.mapDamage) {
|
||||||
this.mapDamage.refreshAll();
|
this.mapDamage.refreshAll();
|
||||||
}
|
}
|
||||||
@ -553,6 +571,9 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
markDirty(view: IEnemyView<TAttr>): 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);
|
||||||
|
if (this.damageSystem) {
|
||||||
|
this.damageSystem.markDirty(view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private refreshSpecialModifier(
|
private refreshSpecialModifier(
|
||||||
@ -687,6 +708,10 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
|
|
||||||
this.dirtyEnemy.delete(view);
|
this.dirtyEnemy.delete(view);
|
||||||
|
|
||||||
|
if (this.damageSystem) {
|
||||||
|
this.damageSystem.markDirty(view);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.mapDamage) {
|
if (this.mapDamage) {
|
||||||
this.mapDamage.markEnemyDirty(view);
|
this.mapDamage.markEnemyDirty(view);
|
||||||
}
|
}
|
||||||
@ -721,6 +746,9 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
this.needTotallyRefresh.clear();
|
this.needTotallyRefresh.clear();
|
||||||
this.requestedCommonContext.clear();
|
this.requestedCommonContext.clear();
|
||||||
this.dirtyEnemy.clear();
|
this.dirtyEnemy.clear();
|
||||||
|
if (this.damageSystem) {
|
||||||
|
this.damageSystem.markAllDirty();
|
||||||
|
}
|
||||||
if (this.mapDamage) {
|
if (this.mapDamage) {
|
||||||
this.mapDamage.refreshAll();
|
this.mapDamage.refreshAll();
|
||||||
}
|
}
|
||||||
@ -729,6 +757,7 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
destroy(): void {
|
destroy(): void {
|
||||||
this.clear();
|
this.clear();
|
||||||
this.attachMapDamage(null);
|
this.attachMapDamage(null);
|
||||||
|
this.damageSystem = null;
|
||||||
this.auraConverter.clear();
|
this.auraConverter.clear();
|
||||||
this.commonQueryMap.clear();
|
this.commonQueryMap.clear();
|
||||||
this.specialQueryEffects.clear();
|
this.specialQueryEffects.clear();
|
||||||
|
|||||||
211
packages-user/data-base/src/enemy/damage.ts
Normal file
211
packages-user/data-base/src/enemy/damage.ts
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
import { logger } from '@motajs/common';
|
||||||
|
import {
|
||||||
|
CriticalableHeroStatus,
|
||||||
|
IDamageCalculator,
|
||||||
|
IDamageSystem,
|
||||||
|
IEnemyContext,
|
||||||
|
IEnemyCritical,
|
||||||
|
IEnemyDamageInfo,
|
||||||
|
IEnemyView,
|
||||||
|
IReadonlyEnemy
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
interface ICriticalSearchResult {
|
||||||
|
/** 此临界点的属性值 */
|
||||||
|
readonly value: number;
|
||||||
|
/** 此临界点的伤害信息 */
|
||||||
|
readonly info: IEnemyDamageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DamageSystem<TAttr, THero> implements IDamageSystem<TAttr, THero> {
|
||||||
|
/** 当前正在使用的计算器 */
|
||||||
|
private calculator: IDamageCalculator<TAttr, THero> | null = null;
|
||||||
|
/** 当前勇士属性 */
|
||||||
|
private heroStatus: Readonly<THero> | null = null;
|
||||||
|
/** 怪物伤害缓存 */
|
||||||
|
private readonly cache: Map<IEnemyView<TAttr>, IEnemyDamageInfo> =
|
||||||
|
new Map();
|
||||||
|
|
||||||
|
constructor(readonly context: IEnemyContext<TAttr>) {}
|
||||||
|
|
||||||
|
useCalculator(calculator: IDamageCalculator<TAttr, THero>): void {
|
||||||
|
this.calculator = calculator;
|
||||||
|
this.markAllDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
getCalculator(): IDamageCalculator<TAttr, THero> | null {
|
||||||
|
return this.calculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindHeroStatus(hero: Readonly<THero>): void {
|
||||||
|
this.heroStatus = hero;
|
||||||
|
this.markAllDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 深拷贝勇士属性
|
||||||
|
*/
|
||||||
|
private cloneHeroStatus(): THero | null {
|
||||||
|
if (!this.heroStatus) return null;
|
||||||
|
else return structuredClone(this.heroStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在修改勇士属性的情况下计算怪物伤害
|
||||||
|
* @param enemy 怪物属性
|
||||||
|
* @param attribute 修改的属性键名
|
||||||
|
* @param value 修改为的属性值
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
private calculateDamageWithModified(
|
||||||
|
enemy: IReadonlyEnemy<TAttr>,
|
||||||
|
attribute: CriticalableHeroStatus<THero>,
|
||||||
|
value: number
|
||||||
|
): IEnemyDamageInfo {
|
||||||
|
const hero = this.cloneHeroStatus()!;
|
||||||
|
// @ts-expect-error 之后会进行修复
|
||||||
|
hero[attribute] = value;
|
||||||
|
return this.calculator!.calculate(hero, enemy);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDamageInfo(enemy: IEnemyView<TAttr>): IEnemyDamageInfo | null {
|
||||||
|
if (!this.heroStatus) {
|
||||||
|
logger.warn(107);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!this.calculator) {
|
||||||
|
logger.warn(106);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const hero = this.cloneHeroStatus()!;
|
||||||
|
|
||||||
|
const cached = this.cache.get(enemy);
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
const info = this.calculator.calculate(hero, enemy.getComputedEnemy());
|
||||||
|
this.cache.set(enemy, info);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
markDirty(enemy: IEnemyView<TAttr>): void {
|
||||||
|
this.cache.delete(enemy);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteEnemy(enemy: IEnemyView<TAttr>): void {
|
||||||
|
this.cache.delete(enemy);
|
||||||
|
}
|
||||||
|
|
||||||
|
markAllDirty(): void {
|
||||||
|
this.cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
*calculateCritical(
|
||||||
|
view: IEnemyView<TAttr>,
|
||||||
|
attribute: CriticalableHeroStatus<THero>,
|
||||||
|
precision: number
|
||||||
|
): Generator<IEnemyCritical, void, void> {
|
||||||
|
if (!this.heroStatus) {
|
||||||
|
logger.warn(107);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.calculator) {
|
||||||
|
logger.warn(106);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentInfo = this.getDamageInfo(view);
|
||||||
|
if (!currentInfo) return;
|
||||||
|
|
||||||
|
const enemy = view.getComputedEnemy();
|
||||||
|
const hero = this.cloneHeroStatus()!;
|
||||||
|
const currentValue = hero[attribute] as number;
|
||||||
|
|
||||||
|
const upperLimit = Math.floor(
|
||||||
|
this.calculator.getCriticalLimit(hero, enemy, attribute)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentValue >= upperLimit) return;
|
||||||
|
|
||||||
|
const maxIterations = Math.max(0, Math.floor(precision));
|
||||||
|
let baseValue = currentValue;
|
||||||
|
let baseInfo = currentInfo;
|
||||||
|
|
||||||
|
while (baseValue < upperLimit) {
|
||||||
|
const next = this.findNextCritical(
|
||||||
|
enemy,
|
||||||
|
attribute,
|
||||||
|
baseValue,
|
||||||
|
upperLimit,
|
||||||
|
baseInfo.damage,
|
||||||
|
maxIterations
|
||||||
|
);
|
||||||
|
if (!next) return;
|
||||||
|
|
||||||
|
yield {
|
||||||
|
nextValue: next.value,
|
||||||
|
baseValue: currentValue,
|
||||||
|
nextDiff: next.value - currentValue,
|
||||||
|
baseInfo: currentInfo,
|
||||||
|
info: next.info,
|
||||||
|
damageDiff: next.info.damage - currentInfo.damage
|
||||||
|
};
|
||||||
|
|
||||||
|
baseValue = next.value;
|
||||||
|
baseInfo = next.info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算下一个临界点
|
||||||
|
* @param enemy 怪物对象
|
||||||
|
* @param attribute 勇士属性名
|
||||||
|
* @param currentValue 当前勇士属性值
|
||||||
|
* @param upperLimit 二分上界
|
||||||
|
* @param referenceDamage 参考伤害值
|
||||||
|
* @param maxIterations 最大迭代数量
|
||||||
|
*/
|
||||||
|
private findNextCritical(
|
||||||
|
enemy: IReadonlyEnemy<TAttr>,
|
||||||
|
attribute: CriticalableHeroStatus<THero>,
|
||||||
|
currentValue: number,
|
||||||
|
upperLimit: number,
|
||||||
|
referenceDamage: number,
|
||||||
|
maxIterations: number
|
||||||
|
): ICriticalSearchResult | null {
|
||||||
|
let left = currentValue;
|
||||||
|
let right = upperLimit;
|
||||||
|
let rightInfo = this.calculateDamageWithModified(
|
||||||
|
enemy,
|
||||||
|
attribute,
|
||||||
|
right
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rightInfo.damage >= referenceDamage) return null;
|
||||||
|
|
||||||
|
let iter = 0;
|
||||||
|
while (iter < maxIterations) {
|
||||||
|
const middle = Math.floor((left + right) / 2);
|
||||||
|
const middleInfo = this.calculateDamageWithModified(
|
||||||
|
enemy,
|
||||||
|
attribute,
|
||||||
|
middle
|
||||||
|
);
|
||||||
|
if (middleInfo.damage < referenceDamage) {
|
||||||
|
right = middle;
|
||||||
|
rightInfo = middleInfo;
|
||||||
|
} else {
|
||||||
|
left = middle;
|
||||||
|
}
|
||||||
|
if (right - left <= 1) break;
|
||||||
|
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: right,
|
||||||
|
info: rightInfo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
export * from './enemy';
|
export * from './enemy';
|
||||||
export * from './context';
|
export * from './context';
|
||||||
|
export * from './damage';
|
||||||
export * from './mapDamage';
|
export * from './mapDamage';
|
||||||
export * from './manager';
|
export * from './manager';
|
||||||
export * from './special';
|
export * from './special';
|
||||||
|
|||||||
@ -60,10 +60,12 @@ export class MapDamage<TAttr> implements IMapDamage<TAttr> {
|
|||||||
/** 合并后伤害缓存,索引 -> 合并结果 */
|
/** 合并后伤害缓存,索引 -> 合并结果 */
|
||||||
private readonly reducedCache: Map<number, IMapDamageInfo> = new Map();
|
private readonly reducedCache: Map<number, IMapDamageInfo> = new Map();
|
||||||
|
|
||||||
constructor(
|
/** 坐标索引对象 */
|
||||||
readonly context: IEnemyContext<TAttr>,
|
private readonly indexer: IMapLocIndexer;
|
||||||
readonly indexer: IMapLocIndexer
|
|
||||||
) {}
|
constructor(readonly context: IEnemyContext<TAttr>) {
|
||||||
|
this.indexer = context.indexer;
|
||||||
|
}
|
||||||
|
|
||||||
useConverter(converter: IMapDamageConverter<TAttr>): void {
|
useConverter(converter: IMapDamageConverter<TAttr>): void {
|
||||||
this.converter = converter;
|
this.converter = converter;
|
||||||
|
|||||||
@ -540,6 +540,117 @@ export interface IMapDamage<TAttr> {
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region 伤害系统
|
||||||
|
|
||||||
|
export interface IEnemyDamageInfo {
|
||||||
|
/** 战斗伤害值 */
|
||||||
|
readonly damage: number;
|
||||||
|
/** 战斗回合数 */
|
||||||
|
readonly turn: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IEnemyCritical {
|
||||||
|
/** 此临界点中指定勇士属性的值 */
|
||||||
|
readonly nextValue: number;
|
||||||
|
/** 当前勇士指定属性的值 */
|
||||||
|
readonly baseValue: number;
|
||||||
|
/** 此临界点中指定勇士数值的值与当前值的差,即 `nextValue - baseValue` */
|
||||||
|
readonly nextDiff: number;
|
||||||
|
/** 当前状态下怪物的伤害信息 */
|
||||||
|
readonly baseInfo: IEnemyDamageInfo;
|
||||||
|
/** 此临界点下怪物的伤害信息 */
|
||||||
|
readonly info: IEnemyDamageInfo;
|
||||||
|
/** 此临界点的伤害值与当前伤害值的差 */
|
||||||
|
readonly damageDiff: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CriticalableHeroStatus<THero> = keyof {
|
||||||
|
[P in keyof THero as THero[P] extends number ? P : never]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface IDamageCalculator<TAttr, THero> {
|
||||||
|
/**
|
||||||
|
* 计算战斗伤害信息
|
||||||
|
* @param hero 勇士信息
|
||||||
|
* @param enemy 怪物信息
|
||||||
|
*/
|
||||||
|
calculate(
|
||||||
|
hero: Readonly<THero>,
|
||||||
|
enemy: IReadonlyEnemy<TAttr>
|
||||||
|
): IEnemyDamageInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取临界计算的上界
|
||||||
|
* @param hero 勇士信息
|
||||||
|
* @param enemy 怪物信息
|
||||||
|
* @param attribute 勇士的临界属性
|
||||||
|
*/
|
||||||
|
getCriticalLimit(
|
||||||
|
hero: Readonly<THero>,
|
||||||
|
enemy: IReadonlyEnemy<TAttr>,
|
||||||
|
attribute: CriticalableHeroStatus<THero>
|
||||||
|
): number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IDamageSystem<TAttr, THero> {
|
||||||
|
/** 伤害系统所属的上下文 */
|
||||||
|
readonly context: IEnemyContext<TAttr>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前伤害计算系统使用的伤害计算器
|
||||||
|
* @param calculator 伤害计算器
|
||||||
|
*/
|
||||||
|
useCalculator(calculator: IDamageCalculator<TAttr, THero>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前使用的伤害计算器
|
||||||
|
*/
|
||||||
|
getCalculator(): IDamageCalculator<TAttr, THero> | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定勇士信息
|
||||||
|
* @param hero 勇士信息
|
||||||
|
*/
|
||||||
|
bindHeroStatus(hero: Readonly<THero>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取战斗伤害信息
|
||||||
|
* @param enemy 怪物视图
|
||||||
|
*/
|
||||||
|
getDamageInfo(enemy: IEnemyView<TAttr>): IEnemyDamageInfo | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的怪物标记为脏
|
||||||
|
* @param enemy 怪物视图
|
||||||
|
*/
|
||||||
|
markDirty(enemy: IEnemyView<TAttr>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定的怪物
|
||||||
|
* @param enemy 怪物视图
|
||||||
|
*/
|
||||||
|
deleteEnemy(enemy: IEnemyView<TAttr>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将所有怪物标记为脏
|
||||||
|
*/
|
||||||
|
markAllDirty(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算怪物在指定勇士属性下的临界
|
||||||
|
* @param enemy 怪物视图
|
||||||
|
* @param attribute 计算临界的目标勇士属性,比如计算攻击临界、自定义属性的临界等等
|
||||||
|
* @param precision 临界计算精度,表示会进行多少次二分计算,一般填写 `12-16` 之间的数即可
|
||||||
|
*/
|
||||||
|
calculateCritical(
|
||||||
|
enemy: IEnemyView<TAttr>,
|
||||||
|
attribute: CriticalableHeroStatus<THero>,
|
||||||
|
precision: number
|
||||||
|
): Generator<IEnemyCritical, void, void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
//#region 上下文
|
//#region 上下文
|
||||||
|
|
||||||
export interface IEnemyContext<TAttr> {
|
export interface IEnemyContext<TAttr> {
|
||||||
@ -547,6 +658,8 @@ export interface IEnemyContext<TAttr> {
|
|||||||
readonly width: number;
|
readonly width: number;
|
||||||
/** 怪物上下文高度 */
|
/** 怪物上下文高度 */
|
||||||
readonly height: number;
|
readonly height: number;
|
||||||
|
/** 此上下文使用的索引对象 */
|
||||||
|
readonly indexer: IMapLocIndexer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调整上下文尺寸,并清空当前上下文中的所有怪物与状态
|
* 调整上下文尺寸,并清空当前上下文中的所有怪物与状态
|
||||||
@ -702,6 +815,17 @@ export interface IEnemyContext<TAttr> {
|
|||||||
*/
|
*/
|
||||||
getMapDamage(): IMapDamage<TAttr> | null;
|
getMapDamage(): IMapDamage<TAttr> | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定伤害计算系统
|
||||||
|
* @param system 伤害系统
|
||||||
|
*/
|
||||||
|
attachDamageSystem(system: IDamageSystem<TAttr, unknown>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前绑定的伤害计算系统
|
||||||
|
*/
|
||||||
|
getDamageSystem<THero>(): IDamageSystem<TAttr, THero> | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重建当前上下文中的全部怪物计算结果
|
* 重建当前上下文中的全部怪物计算结果
|
||||||
*
|
*
|
||||||
|
|||||||
@ -3,6 +3,19 @@ import { IHeroState, HeroState } from './hero';
|
|||||||
import { ILayerState, LayerState } from './map';
|
import { ILayerState, LayerState } from './map';
|
||||||
import { IRoleFaceBinder, RoleFaceBinder } from './common';
|
import { IRoleFaceBinder, RoleFaceBinder } from './common';
|
||||||
import { GameDataState } from './data';
|
import { GameDataState } from './data';
|
||||||
|
import {
|
||||||
|
DamageSystem,
|
||||||
|
EnemyContext,
|
||||||
|
IEnemyContext,
|
||||||
|
MapDamage
|
||||||
|
} from '@user/data-base';
|
||||||
|
import { IEnemyAttributes } from './enemy/types';
|
||||||
|
import {
|
||||||
|
CommonAuraConverter,
|
||||||
|
GuardAuraConverter,
|
||||||
|
MainMapDamageConverter,
|
||||||
|
MainMapDamageReducer
|
||||||
|
} from './enemy';
|
||||||
|
|
||||||
export class CoreState implements ICoreState {
|
export class CoreState implements ICoreState {
|
||||||
readonly layer: ILayerState;
|
readonly layer: ILayerState;
|
||||||
@ -11,6 +24,7 @@ export class CoreState implements ICoreState {
|
|||||||
readonly data: IGameDataState;
|
readonly data: IGameDataState;
|
||||||
readonly idNumberMap: Map<string, number>;
|
readonly idNumberMap: Map<string, number>;
|
||||||
readonly numberIdMap: Map<number, string>;
|
readonly numberIdMap: Map<number, string>;
|
||||||
|
readonly enemyContext: IEnemyContext<IEnemyAttributes>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.layer = new LayerState();
|
this.layer = new LayerState();
|
||||||
@ -19,6 +33,19 @@ export class CoreState implements ICoreState {
|
|||||||
this.idNumberMap = new Map();
|
this.idNumberMap = new Map();
|
||||||
this.numberIdMap = new Map();
|
this.numberIdMap = new Map();
|
||||||
this.data = new GameDataState();
|
this.data = new GameDataState();
|
||||||
|
|
||||||
|
// 怪物上下文初始化
|
||||||
|
const enemyContext = new EnemyContext<IEnemyAttributes>();
|
||||||
|
const damageSystem = new DamageSystem(enemyContext);
|
||||||
|
const mapDamage = new MapDamage(enemyContext);
|
||||||
|
mapDamage.useConverter(new MainMapDamageConverter());
|
||||||
|
mapDamage.useReducer(new MainMapDamageReducer());
|
||||||
|
enemyContext.attachDamageSystem(damageSystem);
|
||||||
|
enemyContext.attachMapDamage(mapDamage);
|
||||||
|
enemyContext.registerAuraConverter(new CommonAuraConverter());
|
||||||
|
enemyContext.registerAuraConverter(new GuardAuraConverter());
|
||||||
|
enemyContext.resize(core._WIDTH_, core._HEIGHT_);
|
||||||
|
this.enemyContext = enemyContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveState(): IStateSaveData {
|
saveState(): IStateSaveData {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { ILayerState } from './map';
|
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 { IEnemyContext, IEnemyManager } from '@user/data-base';
|
||||||
import { IEnemyAttributes } from './enemy/types';
|
import { IEnemyAttributes } from './enemy/types';
|
||||||
|
|
||||||
export interface IGameDataState {
|
export interface IGameDataState {
|
||||||
@ -28,6 +28,9 @@ export interface ICoreState {
|
|||||||
/** 图块数字到 id 的映射 */
|
/** 图块数字到 id 的映射 */
|
||||||
readonly numberIdMap: Map<number, string>;
|
readonly numberIdMap: Map<number, string>;
|
||||||
|
|
||||||
|
/** 怪物上下文 */
|
||||||
|
readonly enemyContext: IEnemyContext<IEnemyAttributes>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存状态
|
* 保存状态
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -161,6 +161,8 @@
|
|||||||
"103": "Map damage reducer is missing, reduced map damage is unavailable.",
|
"103": "Map damage reducer is missing, reduced map damage is unavailable.",
|
||||||
"104": "Enemy dirty marking failed since specific enemy is not in current context.",
|
"104": "Enemy dirty marking failed since specific enemy is not in current context.",
|
||||||
"105": "No specific map damage view stored, which seems like an internal bug of map damage system.",
|
"105": "No specific map damage view stored, which seems like an internal bug of map damage system.",
|
||||||
|
"106": "Damage calculator is missing, damage calculation is unavailable.",
|
||||||
|
"107": "Hero status is not bound, damage calculation is unavailable.",
|
||||||
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency."
|
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user