mirror of
https://github.com/motajs/template.git
synced 2026-05-21 10:21:13 +08:00
Compare commits
4 Commits
4c0960fff7
...
39e91b241f
| Author | SHA1 | Date | |
|---|---|---|---|
| 39e91b241f | |||
| 6c1acb990e | |||
| 63e1a01fab | |||
| 0517da5000 |
@ -1,8 +1,8 @@
|
|||||||
import { IRange, logger } from '@motajs/common';
|
import { IRange, ITileLocator, logger } from '@motajs/common';
|
||||||
import { ITileLocator } from '@user/types';
|
|
||||||
import {
|
import {
|
||||||
IAuraConverter,
|
IAuraConverter,
|
||||||
IAuraView,
|
IAuraView,
|
||||||
|
IDamageSystem,
|
||||||
IEnemy,
|
IEnemy,
|
||||||
IEnemyAuraView,
|
IEnemyAuraView,
|
||||||
IEnemyCommonQueryEffect,
|
IEnemyCommonQueryEffect,
|
||||||
@ -53,6 +53,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 +175,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 +257,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 +558,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 +570,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 +707,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 +745,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 +756,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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -51,6 +51,13 @@ export class Enemy<TAttr> implements IEnemy<TAttr> {
|
|||||||
this.attributes[key] = value;
|
this.attributes[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addAttribute<K extends SelectKey<TAttr, number>>(
|
||||||
|
key: K,
|
||||||
|
value: number
|
||||||
|
): void {
|
||||||
|
(this.attributes[key] as number) += value;
|
||||||
|
}
|
||||||
|
|
||||||
getAttribute<K extends keyof TAttr>(key: K): TAttr[K] {
|
getAttribute<K extends keyof TAttr>(key: K): TAttr[K] {
|
||||||
return this.attributes[key];
|
return this.attributes[key];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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';
|
||||||
|
|||||||
@ -1,13 +1,18 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { Enemy as EnemyImpl } from './enemy';
|
import { Enemy as EnemyImpl } from './enemy';
|
||||||
import { IEnemy, IEnemyManager, SpecialCreation } from './types';
|
import {
|
||||||
|
IEnemy,
|
||||||
|
IEnemyManager,
|
||||||
|
IEnemyLegacyBridge,
|
||||||
|
SpecialCreation
|
||||||
|
} from './types';
|
||||||
|
|
||||||
export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
|
export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
|
||||||
/** 特殊属性注册表,code -> 创建函数 */
|
/** 特殊属性注册表,code -> 创建函数 */
|
||||||
private readonly specialRegistry: Map<number, SpecialCreation<any, TAttr>> =
|
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<keyof TAttr, any> = new Map();
|
||||||
/** 怪物模板表,code -> IEnemy */
|
/** 怪物模板表,code -> IEnemy */
|
||||||
private readonly prefabByCode: Map<number, IEnemy<TAttr>> = new Map();
|
private readonly prefabByCode: Map<number, IEnemy<TAttr>> = new Map();
|
||||||
/** 怪物模板表,id -> IEnemy */
|
/** 怪物模板表,id -> IEnemy */
|
||||||
@ -15,11 +20,16 @@ export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
|
|||||||
/** 旧样板怪物 id 到 code 的映射,用于 fromLegacyEnemy 快速查找已有模板 */
|
/** 旧样板怪物 id 到 code 的映射,用于 fromLegacyEnemy 快速查找已有模板 */
|
||||||
private readonly legacyIdToCode: Map<string, number> = new Map();
|
private readonly legacyIdToCode: Map<string, number> = new Map();
|
||||||
|
|
||||||
|
constructor(readonly bridge: IEnemyLegacyBridge<TAttr>) {}
|
||||||
|
|
||||||
registerSpecial(code: number, cons: SpecialCreation<any, TAttr>): void {
|
registerSpecial(code: number, cons: SpecialCreation<any, TAttr>): void {
|
||||||
this.specialRegistry.set(code, cons);
|
this.specialRegistry.set(code, cons);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerAttribute(name: string, defaultValue: any): void {
|
setAttributeDefaults<K extends keyof TAttr>(
|
||||||
|
name: K,
|
||||||
|
defaultValue: TAttr[K]
|
||||||
|
): void {
|
||||||
if (
|
if (
|
||||||
typeof defaultValue === 'function' ||
|
typeof defaultValue === 'function' ||
|
||||||
typeof defaultValue === 'symbol' ||
|
typeof defaultValue === 'symbol' ||
|
||||||
@ -50,16 +60,13 @@ export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
|
|||||||
* @param enemy 旧样板怪物对象
|
* @param enemy 旧样板怪物对象
|
||||||
*/
|
*/
|
||||||
private createAttributes(enemy: Enemy): TAttr {
|
private createAttributes(enemy: Enemy): TAttr {
|
||||||
const attrs: Record<string, any> = {};
|
const attrs: Partial<TAttr> = {};
|
||||||
for (const [name, defaultValue] of this.attributeRegistry) {
|
for (const [name, defaultValue] of this.attributeRegistry) {
|
||||||
attrs[name] = structuredClone(defaultValue);
|
attrs[name] = structuredClone(defaultValue);
|
||||||
}
|
}
|
||||||
attrs.hp = enemy.hp;
|
|
||||||
attrs.atk = enemy.atk;
|
Object.assign(attrs, this.bridge.fromLegacyEnemy(enemy, attrs));
|
||||||
attrs.def = enemy.def;
|
|
||||||
attrs.money = enemy.money;
|
|
||||||
attrs.exp = enemy.exp;
|
|
||||||
attrs.point = enemy.point;
|
|
||||||
return attrs as TAttr;
|
return attrs as TAttr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger, ITileLocator } from '@motajs/common';
|
||||||
import { ITileLocator } from '@user/types';
|
|
||||||
import {
|
import {
|
||||||
IEnemyContext,
|
IEnemyContext,
|
||||||
IEnemyView,
|
IEnemyView,
|
||||||
@ -60,10 +59,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;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { IRange } from '@motajs/common';
|
import { IRange, ITileLocator } from '@motajs/common';
|
||||||
import { ITileLocator } from '@user/types';
|
|
||||||
|
//#region 怪物基础
|
||||||
|
|
||||||
export interface ISpecial<T = void> {
|
export interface ISpecial<T = void> {
|
||||||
/** 特殊属性代码 */
|
/** 特殊属性代码 */
|
||||||
@ -100,6 +101,16 @@ export interface IEnemy<TAttr> extends IReadonlyEnemy<TAttr> {
|
|||||||
*/
|
*/
|
||||||
setAttribute<K extends keyof TAttr>(key: K, value: TAttr[K]): void;
|
setAttribute<K extends keyof TAttr>(key: K, value: TAttr[K]): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对一个数字类型的属性值进行增减操作
|
||||||
|
* @param key 属性名称
|
||||||
|
* @param value 要增加的属性值,可以是负值
|
||||||
|
*/
|
||||||
|
addAttribute<K extends SelectKey<TAttr, number>>(
|
||||||
|
key: K,
|
||||||
|
value: number
|
||||||
|
): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 深拷贝此怪物对象
|
* 深拷贝此怪物对象
|
||||||
*/
|
*/
|
||||||
@ -112,8 +123,20 @@ export interface IEnemy<TAttr> extends IReadonlyEnemy<TAttr> {
|
|||||||
copyFrom(enemy: IReadonlyEnemy<TAttr>): void;
|
copyFrom(enemy: IReadonlyEnemy<TAttr>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 怪物管理器
|
||||||
|
|
||||||
export type SpecialCreation<T, TAttr> = (enemy: IEnemy<TAttr>) => ISpecial<T>;
|
export type SpecialCreation<T, TAttr> = (enemy: IEnemy<TAttr>) => ISpecial<T>;
|
||||||
|
|
||||||
|
export interface IEnemyLegacyBridge<TAttr> {
|
||||||
|
/**
|
||||||
|
* 从旧样板的怪物对象中获取其属性
|
||||||
|
* @param enemy 旧样板怪物对象
|
||||||
|
*/
|
||||||
|
fromLegacyEnemy(enemy: Enemy, defaultValue: Partial<TAttr>): TAttr;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IEnemyManager<TAttr> {
|
export interface IEnemyManager<TAttr> {
|
||||||
/**
|
/**
|
||||||
* 注册一个特殊属性
|
* 注册一个特殊属性
|
||||||
@ -127,7 +150,10 @@ export interface IEnemyManager<TAttr> {
|
|||||||
* @param name 属性名称
|
* @param name 属性名称
|
||||||
* @param defaultValue 属性默认值
|
* @param defaultValue 属性默认值
|
||||||
*/
|
*/
|
||||||
registerAttribute(name: string, defaultValue: any): void;
|
setAttributeDefaults<K extends keyof TAttr>(
|
||||||
|
name: K,
|
||||||
|
defaultValue: TAttr[K]
|
||||||
|
): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据旧样板怪物对象生成一个新的怪物对象
|
* 根据旧样板怪物对象生成一个新的怪物对象
|
||||||
@ -187,6 +213,8 @@ export interface IEnemyManager<TAttr> {
|
|||||||
changePrefab(code: number | string, enemy: IEnemy<TAttr>): void;
|
changePrefab(code: number | string, enemy: IEnemy<TAttr>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
//#region 辅助接口
|
//#region 辅助接口
|
||||||
|
|
||||||
export interface IMapLocHelper {
|
export interface IMapLocHelper {
|
||||||
@ -540,6 +568,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 +686,8 @@ export interface IEnemyContext<TAttr> {
|
|||||||
readonly width: number;
|
readonly width: number;
|
||||||
/** 怪物上下文高度 */
|
/** 怪物上下文高度 */
|
||||||
readonly height: number;
|
readonly height: number;
|
||||||
|
/** 此上下文使用的索引对象 */
|
||||||
|
readonly indexer: IMapLocIndexer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调整上下文尺寸,并清空当前上下文中的所有怪物与状态
|
* 调整上下文尺寸,并清空当前上下文中的所有怪物与状态
|
||||||
@ -702,6 +843,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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重建当前上下文中的全部怪物计算结果
|
* 重建当前上下文中的全部怪物计算结果
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { ITileLocator } from '@user/types';
|
import { ITileLocator } from '@motajs/common';
|
||||||
import { IMapLocIndexer } from './types';
|
import { IMapLocIndexer } from './types';
|
||||||
|
|
||||||
export class MapLocIndexer implements IMapLocIndexer {
|
export class MapLocIndexer implements IMapLocIndexer {
|
||||||
|
|||||||
@ -6,4 +6,4 @@
|
|||||||
"@user/data-base": "workspace:*",
|
"@user/data-base": "workspace:*",
|
||||||
"@user/data-utils": "workspace:*"
|
"@user/data-utils": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +1,71 @@
|
|||||||
import { ICoreState, IGameDataState, IStateSaveData } from './types';
|
import { ICoreState, IStateSaveData } from './types';
|
||||||
import { IHeroState, HeroState } from './hero';
|
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 {
|
||||||
|
DamageSystem,
|
||||||
|
EnemyContext,
|
||||||
|
EnemyManager,
|
||||||
|
IEnemyContext,
|
||||||
|
IEnemyManager,
|
||||||
|
MapDamage
|
||||||
|
} from '@user/data-base';
|
||||||
|
import { IEnemyAttributes } from './enemy/types';
|
||||||
|
import {
|
||||||
|
CommonAuraConverter,
|
||||||
|
EnemyLegacyBridge,
|
||||||
|
GuardAuraConverter,
|
||||||
|
MainEnemyFinalEffect,
|
||||||
|
MainMapDamageConverter,
|
||||||
|
MainMapDamageReducer,
|
||||||
|
registerSpecials
|
||||||
|
} from './enemy';
|
||||||
|
import { TILE_HEIGHT, TILE_WIDTH } from './shared';
|
||||||
|
|
||||||
export class CoreState implements ICoreState {
|
export class CoreState implements ICoreState {
|
||||||
readonly layer: ILayerState;
|
readonly layer: ILayerState;
|
||||||
readonly hero: IHeroState;
|
readonly hero: IHeroState;
|
||||||
readonly roleFace: IRoleFaceBinder;
|
readonly roleFace: IRoleFaceBinder;
|
||||||
readonly data: IGameDataState;
|
|
||||||
readonly idNumberMap: Map<string, number>;
|
readonly idNumberMap: Map<string, number>;
|
||||||
readonly numberIdMap: Map<number, string>;
|
readonly numberIdMap: Map<number, string>;
|
||||||
|
|
||||||
|
readonly enemyManager: IEnemyManager<IEnemyAttributes>;
|
||||||
|
readonly enemyContext: IEnemyContext<IEnemyAttributes>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.layer = new LayerState();
|
this.layer = new LayerState();
|
||||||
this.hero = new HeroState();
|
this.hero = new HeroState();
|
||||||
this.roleFace = new RoleFaceBinder();
|
this.roleFace = new RoleFaceBinder();
|
||||||
this.idNumberMap = new Map();
|
this.idNumberMap = new Map();
|
||||||
this.numberIdMap = new Map();
|
this.numberIdMap = new Map();
|
||||||
this.data = new GameDataState();
|
|
||||||
|
//#region 怪物初始化
|
||||||
|
|
||||||
|
// 怪物管理器初始化
|
||||||
|
const enemyManager = new EnemyManager(new EnemyLegacyBridge());
|
||||||
|
enemyManager.setAttributeDefaults('hp', 0);
|
||||||
|
enemyManager.setAttributeDefaults('atk', 0);
|
||||||
|
enemyManager.setAttributeDefaults('def', 0);
|
||||||
|
enemyManager.setAttributeDefaults('exp', 0);
|
||||||
|
enemyManager.setAttributeDefaults('money', 0);
|
||||||
|
enemyManager.setAttributeDefaults('point', 0);
|
||||||
|
registerSpecials(enemyManager);
|
||||||
|
this.enemyManager = enemyManager;
|
||||||
|
// 怪物上下文初始化
|
||||||
|
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.registerFinalEffect(new MainEnemyFinalEffect());
|
||||||
|
enemyContext.resize(TILE_WIDTH, TILE_HEIGHT);
|
||||||
|
this.enemyContext = enemyContext;
|
||||||
|
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
saveState(): IStateSaveData {
|
saveState(): IStateSaveData {
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
import { EnemyManager, IEnemyManager } from '@user/data-base';
|
|
||||||
import { IEnemyAttributes } from './enemy/types';
|
|
||||||
import { IGameDataState } from './types';
|
|
||||||
import { registerSpecials } from './enemy';
|
|
||||||
|
|
||||||
export class GameDataState implements IGameDataState {
|
|
||||||
readonly enemyManager: IEnemyManager<IEnemyAttributes>;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.enemyManager = new EnemyManager<IEnemyAttributes>();
|
|
||||||
registerSpecials(this.enemyManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,6 +3,7 @@ import {
|
|||||||
IManhattanRangeParam,
|
IManhattanRangeParam,
|
||||||
IRange,
|
IRange,
|
||||||
IRectRangeParam,
|
IRectRangeParam,
|
||||||
|
ITileLocator,
|
||||||
ManhattanRange,
|
ManhattanRange,
|
||||||
RectRange
|
RectRange
|
||||||
} from '@motajs/common';
|
} from '@motajs/common';
|
||||||
@ -17,7 +18,6 @@ import {
|
|||||||
IEnemy
|
IEnemy
|
||||||
} from '@user/data-base';
|
} from '@user/data-base';
|
||||||
import { IHaloValue } from './special';
|
import { IHaloValue } from './special';
|
||||||
import { ITileLocator } from '@user/types';
|
|
||||||
import { IEnemyAttributes } from './types';
|
import { IEnemyAttributes } from './types';
|
||||||
|
|
||||||
const FULL_RANGE = new FullRange();
|
const FULL_RANGE = new FullRange();
|
||||||
@ -95,27 +95,18 @@ export class CommonAura implements IEnemyAuraView<
|
|||||||
const { hpBuff, atkBuff, defBuff } = this.special.value;
|
const { hpBuff, atkBuff, defBuff } = this.special.value;
|
||||||
|
|
||||||
if (hpBuff !== 0) {
|
if (hpBuff !== 0) {
|
||||||
enemy.setAttribute(
|
const hpValue = (baseEnemy.getAttribute('hp') * hpBuff) / 100;
|
||||||
'hp',
|
enemy.addAttribute('hp', Math.floor(hpValue));
|
||||||
enemy.getAttribute('hp') +
|
|
||||||
Math.floor((baseEnemy.getAttribute('hp') * hpBuff) / 100)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atkBuff !== 0) {
|
if (atkBuff !== 0) {
|
||||||
enemy.setAttribute(
|
const atkValue = (baseEnemy.getAttribute('atk') * atkBuff) / 100;
|
||||||
'atk',
|
enemy.addAttribute('atk', Math.floor(atkValue));
|
||||||
enemy.getAttribute('atk') +
|
|
||||||
Math.floor((baseEnemy.getAttribute('atk') * atkBuff) / 100)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defBuff !== 0) {
|
if (defBuff !== 0) {
|
||||||
enemy.setAttribute(
|
const defValue = (baseEnemy.getAttribute('def') * defBuff) / 100;
|
||||||
'def',
|
enemy.addAttribute('def', Math.floor(defValue));
|
||||||
enemy.getAttribute('def') +
|
|
||||||
Math.floor((baseEnemy.getAttribute('def') * defBuff) / 100)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
packages-user/data-state/src/enemy/final.ts
Normal file
29
packages-user/data-state/src/enemy/final.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { IEnemy, IEnemyFinalEffect } from '@user/data-base';
|
||||||
|
import { IEnemyAttributes } from './types';
|
||||||
|
import { ITileLocator } from '@motajs/common';
|
||||||
|
|
||||||
|
const HERO_STATUS_PLACEHOLDER = {
|
||||||
|
atk: 0,
|
||||||
|
def: 0
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export class MainEnemyFinalEffect implements IEnemyFinalEffect<IEnemyAttributes> {
|
||||||
|
readonly priority: number = 0;
|
||||||
|
|
||||||
|
apply(enemy: IEnemy<IEnemyAttributes>, _locator: ITileLocator): void {
|
||||||
|
if (enemy.hasSpecial(3)) {
|
||||||
|
enemy.setAttribute(
|
||||||
|
'def',
|
||||||
|
Math.max(
|
||||||
|
enemy.getAttribute('def'),
|
||||||
|
HERO_STATUS_PLACEHOLDER.atk - 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy.hasSpecial(10)) {
|
||||||
|
enemy.setAttribute('atk', HERO_STATUS_PLACEHOLDER.atk);
|
||||||
|
enemy.setAttribute('def', HERO_STATUS_PLACEHOLDER.def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
export * from './aura';
|
export * from './aura';
|
||||||
export * from './damage';
|
export * from './damage';
|
||||||
|
export * from './final';
|
||||||
|
export * from './legacy';
|
||||||
export * from './mapDamage';
|
export * from './mapDamage';
|
||||||
export * from './special';
|
export * from './special';
|
||||||
|
|||||||
19
packages-user/data-state/src/enemy/legacy.ts
Normal file
19
packages-user/data-state/src/enemy/legacy.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { IEnemyLegacyBridge } from '@user/data-base';
|
||||||
|
import { IEnemyAttributes } from './types';
|
||||||
|
|
||||||
|
export class EnemyLegacyBridge implements IEnemyLegacyBridge<IEnemyAttributes> {
|
||||||
|
fromLegacyEnemy(
|
||||||
|
enemy: Enemy,
|
||||||
|
defaultAttr: Partial<IEnemyAttributes>
|
||||||
|
): IEnemyAttributes {
|
||||||
|
return {
|
||||||
|
hp: enemy.hp ?? defaultAttr.hp ?? 0,
|
||||||
|
atk: enemy.atk ?? defaultAttr.atk ?? 0,
|
||||||
|
def: enemy.def ?? defaultAttr.def ?? 0,
|
||||||
|
money: enemy.money ?? defaultAttr.money ?? 0,
|
||||||
|
exp: enemy.exp ?? defaultAttr.exp ?? 0,
|
||||||
|
point: enemy.point ?? defaultAttr.point ?? 0,
|
||||||
|
guard: defaultAttr.guard ?? new Set()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,9 +8,9 @@ import {
|
|||||||
IRectRangeParam,
|
IRectRangeParam,
|
||||||
ManhattanRange,
|
ManhattanRange,
|
||||||
RayRange,
|
RayRange,
|
||||||
RectRange
|
RectRange,
|
||||||
|
ITileLocator
|
||||||
} from '@motajs/common';
|
} from '@motajs/common';
|
||||||
import { ITileLocator } from '@user/types';
|
|
||||||
import { IReadonlyEnemy, ISpecial } from '@user/data-base';
|
import { IReadonlyEnemy, ISpecial } from '@user/data-base';
|
||||||
import {
|
import {
|
||||||
IEnemyContext,
|
IEnemyContext,
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export interface IHaloValue {
|
|||||||
export function registerSpecials(
|
export function registerSpecials(
|
||||||
manager: IEnemyManager<IEnemyAttributes>
|
manager: IEnemyManager<IEnemyAttributes>
|
||||||
): void {
|
): void {
|
||||||
manager.registerAttribute('guard', new Set());
|
manager.setAttributeDefaults('guard', new Set());
|
||||||
|
|
||||||
// 0 - 空
|
// 0 - 空
|
||||||
manager.registerSpecial(
|
manager.registerSpecial(
|
||||||
|
|||||||
@ -1,2 +1,7 @@
|
|||||||
|
/** 每个地图的默认宽度 */
|
||||||
|
export const TILE_WIDTH = 13;
|
||||||
|
/** 每个地图的默认高度 */
|
||||||
|
export const TILE_HEIGHT = 13;
|
||||||
|
|
||||||
/** 默认的勇士图片 */
|
/** 默认的勇士图片 */
|
||||||
export const DEFAULT_HERO_IMAGE: ImageIds = 'hero.png';
|
export const DEFAULT_HERO_IMAGE: ImageIds = 'hero.png';
|
||||||
|
|||||||
@ -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 {
|
||||||
@ -21,13 +21,16 @@ export interface ICoreState {
|
|||||||
readonly hero: IHeroState;
|
readonly hero: IHeroState;
|
||||||
/** 朝向绑定 */
|
/** 朝向绑定 */
|
||||||
readonly roleFace: IRoleFaceBinder;
|
readonly roleFace: IRoleFaceBinder;
|
||||||
/** 游戏数据状态 */
|
|
||||||
readonly data: IGameDataState;
|
|
||||||
/** id 到图块数字的映射 */
|
/** id 到图块数字的映射 */
|
||||||
readonly idNumberMap: Map<string, number>;
|
readonly idNumberMap: Map<string, number>;
|
||||||
/** 图块数字到 id 的映射 */
|
/** 图块数字到 id 的映射 */
|
||||||
readonly numberIdMap: Map<number, string>;
|
readonly numberIdMap: Map<number, string>;
|
||||||
|
|
||||||
|
/** 怪物管理器 */
|
||||||
|
readonly enemyManager: IEnemyManager<IEnemyAttributes>;
|
||||||
|
/** 怪物上下文 */
|
||||||
|
readonly enemyContext: IEnemyContext<IEnemyAttributes>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存状态
|
* 保存状态
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@user/types"
|
|
||||||
}
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
// todo: 2.C
|
|
||||||
|
|
||||||
export interface IEnemyInfo {}
|
|
||||||
|
|
||||||
export interface IDamageInfo {}
|
|
||||||
|
|
||||||
export interface IDamageEnemy {
|
|
||||||
/** 原始怪物信息 */
|
|
||||||
readonly enemy: Enemy;
|
|
||||||
/** 该怪物所属的怪物列表 */
|
|
||||||
readonly collection: IEnemyCollection | null;
|
|
||||||
/** 怪物横坐标 */
|
|
||||||
readonly x: number | undefined;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取怪物属性信息
|
|
||||||
*/
|
|
||||||
getEnemyInfo(): IEnemyInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取这个怪物的伤害信息
|
|
||||||
*/
|
|
||||||
getDamageInfo(): IDamageInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMapDamage {
|
|
||||||
/** 伤害类型 */
|
|
||||||
readonly type: string;
|
|
||||||
/** 伤害值 */
|
|
||||||
readonly damage: number;
|
|
||||||
/** 伤害优先级 */
|
|
||||||
readonly priority: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMapDamageSummary {
|
|
||||||
/** 该点的总伤害 */
|
|
||||||
readonly totalDamage: number;
|
|
||||||
/** 该点的伤害信息 */
|
|
||||||
readonly damages: IMapDamage[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IEnemyCollection {
|
|
||||||
/** 怪物列表,索引为 x + width * y,值表示该点对应的怪物 */
|
|
||||||
readonly list: Map<number, IDamageEnemy>;
|
|
||||||
|
|
||||||
/** 楼层 id */
|
|
||||||
readonly floorId: FloorIds;
|
|
||||||
/** 楼层宽度 */
|
|
||||||
readonly width: number;
|
|
||||||
/** 楼层高度 */
|
|
||||||
readonly height: number;
|
|
||||||
|
|
||||||
/** 地图伤害 */
|
|
||||||
readonly mapDamage: Map<number, IMapDamageSummary>;
|
|
||||||
|
|
||||||
/** 用于计算本怪物列表中怪物信息的勇士属性 */
|
|
||||||
readonly hero: HeroStatus;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取一点的怪物信息,不存在时返回 null
|
|
||||||
* @param x 怪物横坐标
|
|
||||||
* @param y 怪物纵坐标
|
|
||||||
*/
|
|
||||||
getEnemy(x: number, y: number): IDamageEnemy | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取一点的地图伤害信息,每一点都包含地图伤害对象,传入地图外坐标时返回 null
|
|
||||||
* @param x 横坐标
|
|
||||||
* @param y 纵坐标
|
|
||||||
*/
|
|
||||||
getMapDamage(x: number, y: number): IMapDamageSummary | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重置此地图的怪物信息,并重新计算
|
|
||||||
*/
|
|
||||||
refresh(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 复制这个怪物列表,同时将复制后的列表中勇士属性设为指定值
|
|
||||||
* @param status 新的勇士属性
|
|
||||||
*/
|
|
||||||
with(status: HeroStatus): IEnemyCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IDamageSystem {
|
|
||||||
readonly collections: Map<FloorIds, IEnemyCollection>;
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export * from './enemy';
|
|
||||||
export * from './spatial';
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
export interface ITileLocator {
|
|
||||||
/** 图块所在横坐标 */
|
|
||||||
x: number;
|
|
||||||
/** 图块所在纵坐标 */
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
@ -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."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -135,6 +135,13 @@ export interface IRayRangeParam {
|
|||||||
|
|
||||||
//#region 实用接口
|
//#region 实用接口
|
||||||
|
|
||||||
|
export interface ITileLocator {
|
||||||
|
/** 图块所在横坐标 */
|
||||||
|
x: number;
|
||||||
|
/** 图块所在纵坐标 */
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
export const enum InternalDirectionGroup {
|
export const enum InternalDirectionGroup {
|
||||||
/** 上下左右四方向 */
|
/** 上下左右四方向 */
|
||||||
Dir4,
|
Dir4,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user