mirror of
https://github.com/motajs/template.git
synced 2026-08-15 05:22:28 +08:00
Compare commits
1 Commits
77bf564022
...
c1b721774e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1b721774e |
@ -1,22 +1,9 @@
|
|||||||
import {
|
import { IFacedTileLocator } from '@motajs/common';
|
||||||
Hookable,
|
|
||||||
HookController,
|
|
||||||
IFacedTileLocator,
|
|
||||||
IHookController
|
|
||||||
} from '@motajs/common';
|
|
||||||
import { FaceDirection, IDataCommon, IFaceHandler } from '@user/data-common';
|
import { FaceDirection, IDataCommon, IFaceHandler } from '@user/data-common';
|
||||||
import { HeroMover } from './mover';
|
import { HeroMover } from './mover';
|
||||||
import {
|
import { IHeroLocation, IHeroLocationSave, IHeroMover } from './types';
|
||||||
IHeroLocation,
|
|
||||||
IHeroLocationHook,
|
|
||||||
IHeroLocationSave,
|
|
||||||
IHeroMover
|
|
||||||
} from './types';
|
|
||||||
|
|
||||||
export class HeroLocation
|
export class HeroLocation implements IHeroLocation {
|
||||||
extends Hookable<IHeroLocationHook>
|
|
||||||
implements IHeroLocation
|
|
||||||
{
|
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
floorId: string | undefined = undefined;
|
floorId: string | undefined = undefined;
|
||||||
@ -29,7 +16,6 @@ export class HeroLocation
|
|||||||
loc: IFacedTileLocator,
|
loc: IFacedTileLocator,
|
||||||
faceHandler: IFaceHandler<FaceDirection>
|
faceHandler: IFaceHandler<FaceDirection>
|
||||||
) {
|
) {
|
||||||
super();
|
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.x = loc.x;
|
this.x = loc.x;
|
||||||
this.y = loc.y;
|
this.y = loc.y;
|
||||||
@ -38,21 +24,9 @@ export class HeroLocation
|
|||||||
this.mover = mover;
|
this.mover = mover;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createController(
|
|
||||||
hook: Partial<IHeroLocationHook>
|
|
||||||
): IHookController<IHeroLocationHook> {
|
|
||||||
return new HookController(this, hook);
|
|
||||||
}
|
|
||||||
|
|
||||||
setFloor(floorId: string | undefined): void {
|
|
||||||
this.floorId = floorId;
|
|
||||||
this.forEachHook(hook => hook.onSetFloor?.(floorId));
|
|
||||||
}
|
|
||||||
|
|
||||||
setPos(x: number, y: number): void {
|
setPos(x: number, y: number): void {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.forEachHook(hook => hook.onSetPos?.(x, y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentFaceDirection(): FaceDirection {
|
getCurrentFaceDirection(): FaceDirection {
|
||||||
|
|||||||
@ -40,7 +40,7 @@ export class HeroMover<T extends IHeroLocation>
|
|||||||
readonly tile: T,
|
readonly tile: T,
|
||||||
faceHandler: IFaceHandler<FaceDirection>
|
faceHandler: IFaceHandler<FaceDirection>
|
||||||
) {
|
) {
|
||||||
super(faceHandler, tile.getCurrentFaceDirection());
|
super(faceHandler);
|
||||||
this.state = tile.state;
|
this.state = tile.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,9 +15,7 @@ import {
|
|||||||
IHeroState,
|
IHeroState,
|
||||||
IHeroStateSave,
|
IHeroStateSave,
|
||||||
IModifierStateSave,
|
IModifierStateSave,
|
||||||
IReadonlyHeroAttribute,
|
IReadonlyHeroAttribute
|
||||||
IHeroChangeFloorInfo,
|
|
||||||
IHeroStateHook
|
|
||||||
} from './types';
|
} from './types';
|
||||||
import {
|
import {
|
||||||
FaceDirection,
|
FaceDirection,
|
||||||
@ -25,18 +23,9 @@ import {
|
|||||||
IFaceHandler,
|
IFaceHandler,
|
||||||
SaveCompression
|
SaveCompression
|
||||||
} from '@user/data-common';
|
} from '@user/data-common';
|
||||||
import {
|
import { IFacedTileLocator, logger } from '@motajs/common';
|
||||||
Hookable,
|
|
||||||
HookController,
|
|
||||||
IFacedTileLocator,
|
|
||||||
IHookController,
|
|
||||||
logger
|
|
||||||
} from '@motajs/common';
|
|
||||||
|
|
||||||
export class HeroState<THero>
|
export class HeroState<THero> implements IHeroState<THero> {
|
||||||
extends Hookable<IHeroStateHook>
|
|
||||||
implements IHeroState<THero>
|
|
||||||
{
|
|
||||||
/** 修饰器工厂函数注册表 */
|
/** 修饰器工厂函数注册表 */
|
||||||
private readonly registry: Map<
|
private readonly registry: Map<
|
||||||
string,
|
string,
|
||||||
@ -54,7 +43,6 @@ export class HeroState<THero>
|
|||||||
faceHandler: IFaceHandler<FaceDirection>,
|
faceHandler: IFaceHandler<FaceDirection>,
|
||||||
public attribute: IHeroAttribute<THero>
|
public attribute: IHeroAttribute<THero>
|
||||||
) {
|
) {
|
||||||
super();
|
|
||||||
this.rendering = new HeroRendering(state);
|
this.rendering = new HeroRendering(state);
|
||||||
const defaultLoc: IFacedTileLocator = {
|
const defaultLoc: IFacedTileLocator = {
|
||||||
x: 0,
|
x: 0,
|
||||||
@ -71,10 +59,8 @@ export class HeroState<THero>
|
|||||||
this.equip = new HeroEquipment(this.items.equipment, this.attribute);
|
this.equip = new HeroEquipment(this.items.equipment, this.attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createController(
|
attachAttribute(attribute: IHeroAttribute<THero>): void {
|
||||||
hook: Partial<IHeroStateHook>
|
this.attribute = attribute;
|
||||||
): IHookController<IHeroStateHook> {
|
|
||||||
return new HookController(this, hook);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getLocation(): IFacedTileLocator {
|
getLocation(): IFacedTileLocator {
|
||||||
@ -85,12 +71,6 @@ export class HeroState<THero>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region 属性相关
|
|
||||||
|
|
||||||
attachAttribute(attribute: IHeroAttribute<THero>): void {
|
|
||||||
this.attribute = attribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
getModifiableAttribute(): IHeroAttribute<THero> {
|
getModifiableAttribute(): IHeroAttribute<THero> {
|
||||||
return this.attribute;
|
return this.attribute;
|
||||||
}
|
}
|
||||||
@ -129,22 +109,6 @@ export class HeroState<THero>
|
|||||||
return modifier;
|
return modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
async changeFloor(info: IHeroChangeFloorInfo): Promise<void> {
|
|
||||||
await Promise.all(
|
|
||||||
this.forEachHook(hook => hook.onBeforeChangeFloor?.(info))
|
|
||||||
);
|
|
||||||
const mover = this.location.mover;
|
|
||||||
mover.setFaceDir(info.face);
|
|
||||||
mover.setMoveDir(info.face);
|
|
||||||
mover.setPos(info.x, info.y);
|
|
||||||
this.location.setFloor(info.target);
|
|
||||||
await Promise.all(
|
|
||||||
this.forEachHook(hook => hook.onAfterChangeFloor?.(info))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
saveState(compression: SaveCompression): IHeroStateSave<THero> {
|
saveState(compression: SaveCompression): IHeroStateSave<THero> {
|
||||||
const modifiers: IModifierStateSave<THero>[] = [];
|
const modifiers: IModifierStateSave<THero>[] = [];
|
||||||
for (const [name, modifier] of this.attribute.iterateModifiers()) {
|
for (const [name, modifier] of this.attribute.iterateModifiers()) {
|
||||||
|
|||||||
@ -227,21 +227,6 @@ export interface IHeroAttribute<THero> extends IReadonlyHeroAttribute<THero> {
|
|||||||
|
|
||||||
//#region 勇士位置
|
//#region 勇士位置
|
||||||
|
|
||||||
export interface IHeroLocationHook extends IHookBase {
|
|
||||||
/**
|
|
||||||
* 当设置勇士位置时触发
|
|
||||||
* @param x 设置为的横坐标
|
|
||||||
* @param y 设置为的纵坐标
|
|
||||||
*/
|
|
||||||
onSetPos?(x: number, y: number): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当设置勇士所处楼层时触发
|
|
||||||
* @param floorId 设置为的楼层 id,undefined 表示尚不处于任何楼层
|
|
||||||
*/
|
|
||||||
onSetFloor?(floorId: string | undefined): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IHeroLocationSave {
|
export interface IHeroLocationSave {
|
||||||
/** 当前横坐标 */
|
/** 当前横坐标 */
|
||||||
readonly x: number;
|
readonly x: number;
|
||||||
@ -257,18 +242,11 @@ export interface IHeroLocation
|
|||||||
extends
|
extends
|
||||||
ISaveableContent<IHeroLocationSave>,
|
ISaveableContent<IHeroLocationSave>,
|
||||||
IObjectMovable,
|
IObjectMovable,
|
||||||
IHookable<IHeroLocationHook>,
|
|
||||||
IDataCommonExtended {
|
IDataCommonExtended {
|
||||||
/** 当前所在楼层 id,undefined 表示尚不处于任何楼层 */
|
/** 当前所在楼层 id,undefined 表示尚不处于任何楼层 */
|
||||||
readonly floorId: string | undefined;
|
readonly floorId: string | undefined;
|
||||||
/** 勇士的移动对象 */
|
/** 勇士的移动对象 */
|
||||||
readonly mover: IHeroMover<this>;
|
readonly mover: IHeroMover<this>;
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置勇士所在的楼层 id,注意此方法会引起数据变化,但是不会产生楼层切换动画
|
|
||||||
* @param floorId 目标楼层 id
|
|
||||||
*/
|
|
||||||
setFloor(floorId: string | undefined): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@ -750,33 +728,6 @@ export interface IHeroEquipment<THero>
|
|||||||
|
|
||||||
//#region 勇士状态
|
//#region 勇士状态
|
||||||
|
|
||||||
export interface IHeroChangeFloorInfo {
|
|
||||||
/** 要切换至的目标楼层 */
|
|
||||||
readonly target: string;
|
|
||||||
/** 要切换至的目标位置横坐标 */
|
|
||||||
readonly x: number;
|
|
||||||
/** 要切换至的目标位置纵坐标 */
|
|
||||||
readonly y: number;
|
|
||||||
/** 要切换至的目标朝向 */
|
|
||||||
readonly face: FaceDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IHeroStateHook extends IHookBase {
|
|
||||||
/**
|
|
||||||
* 当勇士切换楼层前触发,此钩子执行完毕后会立刻触发 `IHeroLocation` 的 `onSetFloor` 钩子。
|
|
||||||
* 此钩子应该用于切换楼层前的过渡及必要的数据准备,不应该修改勇士位置相关的数据。
|
|
||||||
* @param info 勇士切换楼层信息对象
|
|
||||||
*/
|
|
||||||
onBeforeChangeFloor?(info: IHeroChangeFloorInfo): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当勇士切换楼层后触发,此钩子会在 `IHeroLocation` 的 `onSetFloor` 钩子执行完毕后立刻触发。
|
|
||||||
* 此钩子应该用于切换楼层后的过渡及必要的数据处理,不应该修改勇士位置相关的数据。
|
|
||||||
* @param info 勇士切换楼层信息对象
|
|
||||||
*/
|
|
||||||
onAfterChangeFloor?(info: IHeroChangeFloorInfo): Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IHeroStateSave<THero> {
|
export interface IHeroStateSave<THero> {
|
||||||
/** 勇士属性状态 */
|
/** 勇士属性状态 */
|
||||||
readonly attribute: THero;
|
readonly attribute: THero;
|
||||||
@ -794,8 +745,9 @@ export interface IHeroStateSave<THero> {
|
|||||||
readonly equip: IHeroEquipmentSave;
|
readonly equip: IHeroEquipmentSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IHeroState<THero>
|
export interface IHeroState<THero> extends ISaveableContent<
|
||||||
extends ISaveableContent<IHeroStateSave<THero>>, IHookable<IHeroStateHook> {
|
IHeroStateSave<THero>
|
||||||
|
> {
|
||||||
/** 勇士移动对象 */
|
/** 勇士移动对象 */
|
||||||
readonly location: IHeroLocation;
|
readonly location: IHeroLocation;
|
||||||
/** 勇士属性对象 */
|
/** 勇士属性对象 */
|
||||||
@ -857,12 +809,6 @@ export interface IHeroState<THero>
|
|||||||
type: string,
|
type: string,
|
||||||
name: K
|
name: K
|
||||||
): IHeroModifier<THero[K], V> | null;
|
): IHeroModifier<THero[K], V> | null;
|
||||||
|
|
||||||
/**
|
|
||||||
* 切换勇士所在楼层
|
|
||||||
* @param info 楼层切换信息对象
|
|
||||||
*/
|
|
||||||
changeFloor(info: IHeroChangeFloorInfo): Promise<void>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export * from './layerState';
|
export * from './layerState';
|
||||||
export * from './mapLayer';
|
export * from './mapLayer';
|
||||||
export * from './mapState';
|
export * from './mapStore';
|
||||||
export * from './mover';
|
export * from './mover';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { IDataCommon, IMapRawData, SaveCompression } from '@user/data-common';
|
import { IDataCommon, SaveCompression } from '@user/data-common';
|
||||||
import { ITileStore } from '@user/data-common';
|
import { ITileStore } from '@user/data-common';
|
||||||
import {
|
import {
|
||||||
ILayerState,
|
ILayerState,
|
||||||
@ -11,7 +11,7 @@ import {
|
|||||||
MapArea
|
MapArea
|
||||||
} from './types';
|
} from './types';
|
||||||
import { LayerState } from './layerState';
|
import { LayerState } from './layerState';
|
||||||
import { isNil, uniq } from 'lodash-es';
|
import { uniq } from 'lodash-es';
|
||||||
|
|
||||||
export class MapState implements IMapState {
|
export class MapState implements IMapState {
|
||||||
/** 楼层 id 到状态对象的映射 */
|
/** 楼层 id 到状态对象的映射 */
|
||||||
@ -39,56 +39,6 @@ export class MapState implements IMapState {
|
|||||||
|
|
||||||
//#region 楼层管理
|
//#region 楼层管理
|
||||||
|
|
||||||
fromRaw(raw: IMapRawData): ILayerState | null {
|
|
||||||
let length = 0;
|
|
||||||
const entries = Object.entries(raw.map);
|
|
||||||
for (const [_, map] of Object.entries(raw.map)) {
|
|
||||||
if (length > 0 && map.length !== length) {
|
|
||||||
logger.error(60, map.length.toString(), length.toString());
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
length = map.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (length % raw.width !== 0) {
|
|
||||||
logger.error(61, length.toString(), raw.width.toString());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置楼层图块数据
|
|
||||||
const height = length / raw.width;
|
|
||||||
const state = this.createLayerState(raw.floorId, raw.width, height);
|
|
||||||
for (const [zIndex, map] of entries) {
|
|
||||||
const z = Number(zIndex);
|
|
||||||
if (isNaN(z)) {
|
|
||||||
logger.error(62, 'IMapRawData.map', String(zIndex));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const layer = state.addLayer();
|
|
||||||
const alias = raw.layerAlias[z];
|
|
||||||
layer.setMapRef(new Uint32Array(map));
|
|
||||||
layer.setZIndex(z);
|
|
||||||
state.setLayerAlias(layer, alias);
|
|
||||||
|
|
||||||
// 设置图块静态触发器
|
|
||||||
const extra = raw.blockData[z];
|
|
||||||
for (const [index, data] of Object.entries(extra)) {
|
|
||||||
const indexNum = Number(index);
|
|
||||||
if (isNaN(indexNum)) {
|
|
||||||
logger.error(62, 'IMapRawData.blockData', String(index));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!isNil(data.trigger)) {
|
|
||||||
const x = indexNum % raw.width;
|
|
||||||
const y = Math.floor(indexNum / raw.width);
|
|
||||||
layer.setTriggerType(data.trigger, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
createLayerState(id: string, width: number, height: number): ILayerState {
|
createLayerState(id: string, width: number, height: number): ILayerState {
|
||||||
if (this.mapData.has(id)) {
|
if (this.mapData.has(id)) {
|
||||||
logger.warn(121, id);
|
logger.warn(121, id);
|
||||||
@ -18,7 +18,7 @@ const enum DynamicMoveCode {
|
|||||||
export class DynamicTileMover extends ObjectMover<IDynamicTile> {
|
export class DynamicTileMover extends ObjectMover<IDynamicTile> {
|
||||||
constructor(public readonly tile: IDynamicTile) {
|
constructor(public readonly tile: IDynamicTile) {
|
||||||
const face = tile.state.faceManager;
|
const face = tile.state.faceManager;
|
||||||
super(face.get(DYNAMIC_MOVER_FACE)!, tile.getCurrentFaceDirection());
|
super(face.get(DYNAMIC_MOVER_FACE)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onMoveStart(): Promise<void> {
|
protected onMoveStart(): Promise<void> {
|
||||||
|
|||||||
@ -1,14 +1,7 @@
|
|||||||
import {
|
import { IHookable, IHookBase, IHookController } from '@motajs/common';
|
||||||
IHookable,
|
|
||||||
IHookBase,
|
|
||||||
IHookController,
|
|
||||||
ITileLocator
|
|
||||||
} from '@motajs/common';
|
|
||||||
import {
|
import {
|
||||||
FaceDirection,
|
FaceDirection,
|
||||||
IDataCommonExtended,
|
IDataCommonExtended,
|
||||||
IMapBlockRawData,
|
|
||||||
IMapRawData,
|
|
||||||
IMoverController,
|
IMoverController,
|
||||||
IObjectMovable,
|
IObjectMovable,
|
||||||
IObjectMover,
|
IObjectMover,
|
||||||
@ -28,8 +21,6 @@ export interface IMapLayerData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ILayerLocation {
|
export interface ILayerLocation {
|
||||||
/** 该点的位置 */
|
|
||||||
readonly locator: ITileLocator;
|
|
||||||
/** 该点的静态图块数字 */
|
/** 该点的静态图块数字 */
|
||||||
readonly tile: number;
|
readonly tile: number;
|
||||||
/** 该点的静态图块信息 */
|
/** 该点的静态图块信息 */
|
||||||
@ -38,8 +29,6 @@ export interface ILayerLocation {
|
|||||||
readonly trigger: number;
|
readonly trigger: number;
|
||||||
/** 该点包含的所有动态图块 */
|
/** 该点包含的所有动态图块 */
|
||||||
readonly dynamics: Iterable<IDynamicTile>;
|
readonly dynamics: Iterable<IDynamicTile>;
|
||||||
/** 该点的静态图块原始数据 */
|
|
||||||
readonly block: IMapBlockRawData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapLayerHooks extends IHookBase {
|
export interface IMapLayerHooks extends IHookBase {
|
||||||
@ -453,12 +442,6 @@ export interface IMapState
|
|||||||
*/
|
*/
|
||||||
getActiveMap(id: string): ILayerState | null;
|
getActiveMap(id: string): ILayerState | null;
|
||||||
|
|
||||||
/**
|
|
||||||
* 从楼层原始数据生成楼层状态
|
|
||||||
* @param raw 楼层原始数据
|
|
||||||
*/
|
|
||||||
fromRaw(raw: IMapRawData): ILayerState | null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建并注册一个空白楼层,若 id 已存在则警告并覆盖,返回楼层状态对象
|
* 创建并注册一个空白楼层,若 id 已存在则警告并覆盖,返回楼层状态对象
|
||||||
* @param id 楼层 id
|
* @param id 楼层 id
|
||||||
|
|||||||
@ -371,13 +371,9 @@ export abstract class ObjectMover<T extends IObjectMovable>
|
|||||||
|
|
||||||
readonly faceHandler: IFaceHandler<FaceDirection>;
|
readonly faceHandler: IFaceHandler<FaceDirection>;
|
||||||
|
|
||||||
constructor(
|
constructor(faceHandler: IFaceHandler<FaceDirection>) {
|
||||||
faceHandler: IFaceHandler<FaceDirection>,
|
|
||||||
direction: FaceDirection
|
|
||||||
) {
|
|
||||||
super();
|
super();
|
||||||
this.faceHandler = faceHandler;
|
this.faceHandler = faceHandler;
|
||||||
this.faceDirection = direction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createController(
|
protected createController(
|
||||||
@ -655,6 +651,7 @@ export abstract class ObjectMover<T extends IObjectMovable>
|
|||||||
this.clear();
|
this.clear();
|
||||||
this.shouldStop = false;
|
this.shouldStop = false;
|
||||||
|
|
||||||
|
this.faceDirection = this.tile.getCurrentFaceDirection();
|
||||||
this.moveDirection = FaceDirection.Unknown;
|
this.moveDirection = FaceDirection.Unknown;
|
||||||
|
|
||||||
const { promise, resolve } = Promise.withResolvers<void>();
|
const { promise, resolve } = Promise.withResolvers<void>();
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
//#region tile
|
//#region tile
|
||||||
|
|
||||||
import { IFacedTileLocator } from '@motajs/common';
|
|
||||||
|
|
||||||
export const enum TileType {
|
export const enum TileType {
|
||||||
/** 未知或尚未归类的图块 */
|
/** 未知或尚未归类的图块 */
|
||||||
Unknown,
|
Unknown,
|
||||||
@ -255,54 +253,6 @@ export interface IItemStore<THero, TLegacy> {
|
|||||||
|
|
||||||
//#region map
|
//#region map
|
||||||
|
|
||||||
export const enum ChangeFloorType {
|
|
||||||
/** 指定具体位置的楼层切换方式 */
|
|
||||||
Specified,
|
|
||||||
/** 仅指定相对关系的楼层切换方式 */
|
|
||||||
Related
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum ChangeFloorTarget {
|
|
||||||
/** 切换至前一层 */
|
|
||||||
Previous,
|
|
||||||
/** 切换至后一层 */
|
|
||||||
Next
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum ChangeFloorPos {
|
|
||||||
/** 原地不动 */
|
|
||||||
Stand,
|
|
||||||
/** 左右对称位置 */
|
|
||||||
SymmetryX,
|
|
||||||
/** 上下对称位置 */
|
|
||||||
SymmetryY,
|
|
||||||
/** 中心对称位置 */
|
|
||||||
CentralSymmetry
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IChangeFloorData {
|
|
||||||
/** 切换至的楼层 id 的切换方式 */
|
|
||||||
readonly floorType: ChangeFloorType;
|
|
||||||
/** 指定具体位置的切换楼层方式下,切换至的具体楼层 */
|
|
||||||
readonly targetFloor?: string;
|
|
||||||
/** 相对关系的楼层切换方式下,切换至的楼层代号 */
|
|
||||||
readonly relatedFloor?: ChangeFloorTarget;
|
|
||||||
|
|
||||||
/** 切换至的目标位置的切换方式 */
|
|
||||||
readonly posType: ChangeFloorType;
|
|
||||||
/** 指定具体位置的位置切换方式下,切换至的具体位置,朝向填写 `FaceDirection.Unknown` 视为维持 */
|
|
||||||
readonly targetPos?: IFacedTileLocator;
|
|
||||||
/** 相对关系的位置切换方式下,切换至的位置代号 */
|
|
||||||
readonly relatedPos?: ChangeFloorPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMapBlockRawData {
|
|
||||||
/** 此点的静态触发器类型(仅对该点生效,不会跟随任何图块移动) */
|
|
||||||
readonly trigger?: number;
|
|
||||||
/** 楼层切换信息 */
|
|
||||||
readonly changeFloor?: IChangeFloorData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMapRawData {
|
export interface IMapRawData {
|
||||||
/** 楼层 id */
|
/** 楼层 id */
|
||||||
readonly floorId: string;
|
readonly floorId: string;
|
||||||
@ -312,8 +262,6 @@ export interface IMapRawData {
|
|||||||
readonly map: Record<number, number[]>;
|
readonly map: Record<number, number[]>;
|
||||||
/** 每个地图图层的字符串别名 */
|
/** 每个地图图层的字符串别名 */
|
||||||
readonly layerAlias: Record<number, string>;
|
readonly layerAlias: Record<number, string>;
|
||||||
/** 每个地图图层中,指定位置图块的额外数据,外层 key 为图层 zIndex,内层 key 为图块位置索引 */
|
|
||||||
readonly blockData: Record<number, Record<number, IMapBlockRawData>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapStore {
|
export interface IMapStore {
|
||||||
|
|||||||
@ -1,162 +0,0 @@
|
|||||||
import { IFacedTileLocator, logger } from '@motajs/common';
|
|
||||||
import {
|
|
||||||
IHeroChangeFloorInfo,
|
|
||||||
IHeroState,
|
|
||||||
IMapLayer,
|
|
||||||
IMapState,
|
|
||||||
IStateBase
|
|
||||||
} from '@user/data-base';
|
|
||||||
import {
|
|
||||||
ChangeFloorPos,
|
|
||||||
ChangeFloorTarget,
|
|
||||||
ChangeFloorType,
|
|
||||||
FaceDirection,
|
|
||||||
IChangeFloorData,
|
|
||||||
IHeroAttr
|
|
||||||
} from '@user/data-common';
|
|
||||||
import {
|
|
||||||
BaseTrigger,
|
|
||||||
ITrigger,
|
|
||||||
ITriggerCollection,
|
|
||||||
ITriggerHandler,
|
|
||||||
TriggerCollection
|
|
||||||
} from '@user/data-system';
|
|
||||||
import { isNil } from 'lodash-es';
|
|
||||||
|
|
||||||
export const enum TriggerType {
|
|
||||||
/** 楼层切换触发器 */
|
|
||||||
ChangeFloor
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ChangeFloorTrigger extends BaseTrigger implements ITrigger {
|
|
||||||
readonly type: number = TriggerType.ChangeFloor;
|
|
||||||
readonly priority: number = 10;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
state: IStateBase,
|
|
||||||
readonly maps: IMapState,
|
|
||||||
readonly hero: IHeroState<IHeroAttr>
|
|
||||||
) {
|
|
||||||
super(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取楼层切换的目标楼层
|
|
||||||
* @param data 楼层切换数据
|
|
||||||
*/
|
|
||||||
private getFloorTarget(data: IChangeFloorData): string | undefined {
|
|
||||||
if (data.floorType === ChangeFloorType.Specified) {
|
|
||||||
if (isNil(data.targetFloor)) {
|
|
||||||
logger.warn(165);
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
return data.targetFloor;
|
|
||||||
} else {
|
|
||||||
if (isNil(data.relatedFloor)) {
|
|
||||||
logger.warn(166);
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
const curr = this.hero.location.floorId;
|
|
||||||
if (isNil(curr)) {
|
|
||||||
logger.warn(167);
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
const index = this.maps.maps.indexOf(curr);
|
|
||||||
if (index === -1) {
|
|
||||||
logger.warn(168);
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
if (data.relatedFloor === ChangeFloorTarget.Next) {
|
|
||||||
const next = this.maps.maps[index + 1];
|
|
||||||
if (isNil(next)) {
|
|
||||||
logger.warn(169);
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
} else {
|
|
||||||
const next = this.maps.maps[index - 1];
|
|
||||||
if (isNil(next)) {
|
|
||||||
logger.warn(169);
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getPosTarget(
|
|
||||||
data: IChangeFloorData,
|
|
||||||
layer: IMapLayer
|
|
||||||
): IFacedTileLocator | undefined {
|
|
||||||
if (data.posType === ChangeFloorType.Specified) {
|
|
||||||
if (!data.targetPos) {
|
|
||||||
logger.warn(165);
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
return data.targetPos;
|
|
||||||
} else {
|
|
||||||
if (isNil(data.relatedPos)) {
|
|
||||||
logger.warn(166);
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
const { x, y, floorId } = this.hero.location;
|
|
||||||
if (isNil(floorId)) {
|
|
||||||
logger.warn(167);
|
|
||||||
return void 0;
|
|
||||||
}
|
|
||||||
const { width, height } = layer;
|
|
||||||
switch (data.relatedPos) {
|
|
||||||
case ChangeFloorPos.Stand:
|
|
||||||
return {
|
|
||||||
direction: FaceDirection.Unknown,
|
|
||||||
x,
|
|
||||||
y
|
|
||||||
};
|
|
||||||
case ChangeFloorPos.SymmetryX:
|
|
||||||
return {
|
|
||||||
direction: FaceDirection.Unknown,
|
|
||||||
x: width - x - 1,
|
|
||||||
y
|
|
||||||
};
|
|
||||||
case ChangeFloorPos.SymmetryY:
|
|
||||||
return {
|
|
||||||
direction: FaceDirection.Unknown,
|
|
||||||
x,
|
|
||||||
y: height - y - 1
|
|
||||||
};
|
|
||||||
case ChangeFloorPos.CentralSymmetry:
|
|
||||||
return {
|
|
||||||
direction: FaceDirection.Unknown,
|
|
||||||
x: width - x - 1,
|
|
||||||
y: height - y - 1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async trigger(handler: ITriggerHandler): Promise<void> {
|
|
||||||
if (!handler.layer || !handler.locator || !handler.mapLayer) {
|
|
||||||
logger.warn(164);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { x, y } = handler.locator;
|
|
||||||
const data = handler.mapLayer.getLocationData(x, y);
|
|
||||||
if (!data || !data.block.changeFloor) return;
|
|
||||||
const floor = this.getFloorTarget(data.block.changeFloor);
|
|
||||||
const pos = this.getPosTarget(data.block.changeFloor, handler.mapLayer);
|
|
||||||
if (isNil(floor) || isNil(pos)) return;
|
|
||||||
const hero = handler.state.hero;
|
|
||||||
const isUnknown = pos.direction === FaceDirection.Unknown;
|
|
||||||
const defaults = hero.location.mover.faceDirection;
|
|
||||||
const info: IHeroChangeFloorInfo = {
|
|
||||||
target: floor,
|
|
||||||
x: pos.x,
|
|
||||||
y: pos.y,
|
|
||||||
face: isUnknown ? defaults : pos.direction
|
|
||||||
};
|
|
||||||
return handler.state.hero.changeFloor(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
collection(): ITriggerCollection {
|
|
||||||
return new TriggerCollection([this]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -225,7 +225,7 @@ export class CoreState implements ICoreState {
|
|||||||
this.initTileStore(core.maps.blocksInfo);
|
this.initTileStore(core.maps.blocksInfo);
|
||||||
this.initItemStore(core.items.items);
|
this.initItemStore(core.items.items);
|
||||||
this.initEnemyManager(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
|
this.initEnemyManager(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
|
||||||
this.initMapState(
|
this.initMapStore(
|
||||||
core.floorIds,
|
core.floorIds,
|
||||||
core.floors as Record<FloorIds, ResolvedFloor>
|
core.floors as Record<FloorIds, ResolvedFloor>
|
||||||
);
|
);
|
||||||
@ -323,7 +323,7 @@ export class CoreState implements ICoreState {
|
|||||||
manager.compareWith(reference);
|
manager.compareWith(reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initMapState(
|
private initMapStore(
|
||||||
floors: FloorIds[],
|
floors: FloorIds[],
|
||||||
data: Record<FloorIds, ResolvedFloor>
|
data: Record<FloorIds, ResolvedFloor>
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
export * from './collection';
|
export * from './collection';
|
||||||
export * from './collector';
|
export * from './collector';
|
||||||
export * from './registry';
|
export * from './registry';
|
||||||
export * from './trigger';
|
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
import { IStateBase } from '@user/data-base';
|
|
||||||
import { ITrigger, ITriggerCollection, ITriggerHandler } from './types';
|
|
||||||
import { TriggerCollection } from './collection';
|
|
||||||
|
|
||||||
export abstract class BaseTrigger implements ITrigger {
|
|
||||||
abstract type: number;
|
|
||||||
abstract priority: number;
|
|
||||||
|
|
||||||
constructor(readonly state: IStateBase) {}
|
|
||||||
|
|
||||||
abstract trigger(handler: ITriggerHandler): Promise<void>;
|
|
||||||
|
|
||||||
collection(): ITriggerCollection {
|
|
||||||
return new TriggerCollection([this]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -58,10 +58,7 @@
|
|||||||
"56": "Cannot convert legacy tile data since no tile legacy converter is attached to TileStore.",
|
"56": "Cannot convert legacy tile data since no tile legacy converter is attached to TileStore.",
|
||||||
"57": "Cannot convert legacy item data since no item legacy converter is attached to ItemStore.",
|
"57": "Cannot convert legacy item data since no item legacy converter is attached to ItemStore.",
|
||||||
"58": "Cannot find max equipment uid while loading equipment store.",
|
"58": "Cannot find max equipment uid while loading equipment store.",
|
||||||
"59": "Cannot find item raw data for tile num $1.",
|
"59": "Cannot find item raw data for tile num $1."
|
||||||
"60": "Cannot create layer state from raw data since the area of every layer of the map does not equal: $1 vs $2.",
|
|
||||||
"61": "Cannot create layer state from raw data since map area cannot be divided by width evenly: area = $1 while divider = $2.",
|
|
||||||
"62": "Expected a number for the key of $1, but got $2."
|
|
||||||
},
|
},
|
||||||
"warn": {
|
"warn": {
|
||||||
"1": "Resource with type of 'none' is loaded.",
|
"1": "Resource with type of 'none' is loaded.",
|
||||||
@ -226,12 +223,6 @@
|
|||||||
"160": "Replay safety collection ending function is called outside replay safety collection unexpectedly.",
|
"160": "Replay safety collection ending function is called outside replay safety collection unexpectedly.",
|
||||||
"161": "Replay safety detected. Followings are simplified detect info. To get detailed info, run: '$1'.\n$2",
|
"161": "Replay safety detected. Followings are simplified detect info. To get detailed info, run: '$1'.\n$2",
|
||||||
"162": "Cannot find replay safety detail info of code $1. The detail info may expired, or it just has not been existed.",
|
"162": "Cannot find replay safety detail info of code $1. The detail info may expired, or it just has not been existed.",
|
||||||
"163": "Replay command code $1 has already been registered. This will not replace the old registry.",
|
"163": "Replay command code $1 has already been registered. This will not replace the old registry."
|
||||||
"164": "Change floor trigger needs specified locator.",
|
|
||||||
"165": "Target floor id or target position needs to be specified while change floor type is 'ChangeFloorType.Specified'.",
|
|
||||||
"166": "Related floor id or related position needs to be specified while change floor type is 'ChangeFloorType.Related'.",
|
|
||||||
"167": "Hero must at a specified floor before using related change floor method.",
|
|
||||||
"168": "The current floor of hero does not in the specified map list.",
|
|
||||||
"169": "The current floor is the last or the first floor in the map list, so related floor change method will not work."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user