mirror of
https://github.com/motajs/template.git
synced 2026-07-27 06:42:29 +08:00
feat: 楼层切换
This commit is contained in:
parent
4bf39062a8
commit
f4c77d152f
@ -1,9 +1,22 @@
|
||||
import { IFacedTileLocator } from '@motajs/common';
|
||||
import {
|
||||
Hookable,
|
||||
HookController,
|
||||
IFacedTileLocator,
|
||||
IHookController
|
||||
} from '@motajs/common';
|
||||
import { FaceDirection, IDataCommon, IFaceHandler } from '@user/data-common';
|
||||
import { HeroMover } from './mover';
|
||||
import { IHeroLocation, IHeroLocationSave, IHeroMover } from './types';
|
||||
import {
|
||||
IHeroLocation,
|
||||
IHeroLocationHook,
|
||||
IHeroLocationSave,
|
||||
IHeroMover
|
||||
} from './types';
|
||||
|
||||
export class HeroLocation implements IHeroLocation {
|
||||
export class HeroLocation
|
||||
extends Hookable<IHeroLocationHook>
|
||||
implements IHeroLocation
|
||||
{
|
||||
x: number;
|
||||
y: number;
|
||||
floorId: string | undefined = undefined;
|
||||
@ -16,6 +29,7 @@ export class HeroLocation implements IHeroLocation {
|
||||
loc: IFacedTileLocator,
|
||||
faceHandler: IFaceHandler<FaceDirection>
|
||||
) {
|
||||
super();
|
||||
this.state = state;
|
||||
this.x = loc.x;
|
||||
this.y = loc.y;
|
||||
@ -24,9 +38,21 @@ export class HeroLocation implements IHeroLocation {
|
||||
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 {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.forEachHook(hook => hook.onSetPos?.(x, y));
|
||||
}
|
||||
|
||||
getCurrentFaceDirection(): FaceDirection {
|
||||
|
||||
@ -40,7 +40,7 @@ export class HeroMover<T extends IHeroLocation>
|
||||
readonly tile: T,
|
||||
faceHandler: IFaceHandler<FaceDirection>
|
||||
) {
|
||||
super(faceHandler);
|
||||
super(faceHandler, tile.getCurrentFaceDirection());
|
||||
this.state = tile.state;
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,9 @@ import {
|
||||
IHeroState,
|
||||
IHeroStateSave,
|
||||
IModifierStateSave,
|
||||
IReadonlyHeroAttribute
|
||||
IReadonlyHeroAttribute,
|
||||
IHeroChangeFloorInfo,
|
||||
IHeroStateHook
|
||||
} from './types';
|
||||
import {
|
||||
FaceDirection,
|
||||
@ -23,9 +25,18 @@ import {
|
||||
IFaceHandler,
|
||||
SaveCompression
|
||||
} from '@user/data-common';
|
||||
import { IFacedTileLocator, logger } from '@motajs/common';
|
||||
import {
|
||||
Hookable,
|
||||
HookController,
|
||||
IFacedTileLocator,
|
||||
IHookController,
|
||||
logger
|
||||
} from '@motajs/common';
|
||||
|
||||
export class HeroState<THero> implements IHeroState<THero> {
|
||||
export class HeroState<THero>
|
||||
extends Hookable<IHeroStateHook>
|
||||
implements IHeroState<THero>
|
||||
{
|
||||
/** 修饰器工厂函数注册表 */
|
||||
private readonly registry: Map<
|
||||
string,
|
||||
@ -43,6 +54,7 @@ export class HeroState<THero> implements IHeroState<THero> {
|
||||
faceHandler: IFaceHandler<FaceDirection>,
|
||||
public attribute: IHeroAttribute<THero>
|
||||
) {
|
||||
super();
|
||||
this.rendering = new HeroRendering(state);
|
||||
const defaultLoc: IFacedTileLocator = {
|
||||
x: 0,
|
||||
@ -59,8 +71,10 @@ export class HeroState<THero> implements IHeroState<THero> {
|
||||
this.equip = new HeroEquipment(this.items.equipment, this.attribute);
|
||||
}
|
||||
|
||||
attachAttribute(attribute: IHeroAttribute<THero>): void {
|
||||
this.attribute = attribute;
|
||||
protected createController(
|
||||
hook: Partial<IHeroStateHook>
|
||||
): IHookController<IHeroStateHook> {
|
||||
return new HookController(this, hook);
|
||||
}
|
||||
|
||||
getLocation(): IFacedTileLocator {
|
||||
@ -71,6 +85,12 @@ export class HeroState<THero> implements IHeroState<THero> {
|
||||
};
|
||||
}
|
||||
|
||||
//#region 属性相关
|
||||
|
||||
attachAttribute(attribute: IHeroAttribute<THero>): void {
|
||||
this.attribute = attribute;
|
||||
}
|
||||
|
||||
getModifiableAttribute(): IHeroAttribute<THero> {
|
||||
return this.attribute;
|
||||
}
|
||||
@ -109,6 +129,22 @@ export class HeroState<THero> implements IHeroState<THero> {
|
||||
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> {
|
||||
const modifiers: IModifierStateSave<THero>[] = [];
|
||||
for (const [name, modifier] of this.attribute.iterateModifiers()) {
|
||||
|
||||
@ -227,6 +227,21 @@ export interface IHeroAttribute<THero> extends IReadonlyHeroAttribute<THero> {
|
||||
|
||||
//#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 {
|
||||
/** 当前横坐标 */
|
||||
readonly x: number;
|
||||
@ -242,11 +257,18 @@ export interface IHeroLocation
|
||||
extends
|
||||
ISaveableContent<IHeroLocationSave>,
|
||||
IObjectMovable,
|
||||
IHookable<IHeroLocationHook>,
|
||||
IDataCommonExtended {
|
||||
/** 当前所在楼层 id,undefined 表示尚不处于任何楼层 */
|
||||
readonly floorId: string | undefined;
|
||||
/** 勇士的移动对象 */
|
||||
readonly mover: IHeroMover<this>;
|
||||
|
||||
/**
|
||||
* 设置勇士所在的楼层 id,注意此方法会引起数据变化,但是不会产生楼层切换动画
|
||||
* @param floorId 目标楼层 id
|
||||
*/
|
||||
setFloor(floorId: string | undefined): void;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@ -728,6 +750,33 @@ export interface IHeroEquipment<THero>
|
||||
|
||||
//#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> {
|
||||
/** 勇士属性状态 */
|
||||
readonly attribute: THero;
|
||||
@ -745,9 +794,8 @@ export interface IHeroStateSave<THero> {
|
||||
readonly equip: IHeroEquipmentSave;
|
||||
}
|
||||
|
||||
export interface IHeroState<THero> extends ISaveableContent<
|
||||
IHeroStateSave<THero>
|
||||
> {
|
||||
export interface IHeroState<THero>
|
||||
extends ISaveableContent<IHeroStateSave<THero>>, IHookable<IHeroStateHook> {
|
||||
/** 勇士移动对象 */
|
||||
readonly location: IHeroLocation;
|
||||
/** 勇士属性对象 */
|
||||
@ -809,6 +857,12 @@ export interface IHeroState<THero> extends ISaveableContent<
|
||||
type: string,
|
||||
name: K
|
||||
): IHeroModifier<THero[K], V> | null;
|
||||
|
||||
/**
|
||||
* 切换勇士所在楼层
|
||||
* @param info 楼层切换信息对象
|
||||
*/
|
||||
changeFloor(info: IHeroChangeFloorInfo): Promise<void>;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export * from './layerState';
|
||||
export * from './mapLayer';
|
||||
export * from './mapStore';
|
||||
export * from './mapState';
|
||||
export * from './mover';
|
||||
export * from './types';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { logger } from '@motajs/common';
|
||||
import { IDataCommon, SaveCompression } from '@user/data-common';
|
||||
import { IDataCommon, IMapRawData, SaveCompression } from '@user/data-common';
|
||||
import { ITileStore } from '@user/data-common';
|
||||
import {
|
||||
ILayerState,
|
||||
@ -11,7 +11,7 @@ import {
|
||||
MapArea
|
||||
} from './types';
|
||||
import { LayerState } from './layerState';
|
||||
import { uniq } from 'lodash-es';
|
||||
import { isNil, uniq } from 'lodash-es';
|
||||
|
||||
export class MapState implements IMapState {
|
||||
/** 楼层 id 到状态对象的映射 */
|
||||
@ -39,6 +39,56 @@ export class MapState implements IMapState {
|
||||
|
||||
//#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 {
|
||||
if (this.mapData.has(id)) {
|
||||
logger.warn(121, id);
|
||||
@ -18,7 +18,7 @@ const enum DynamicMoveCode {
|
||||
export class DynamicTileMover extends ObjectMover<IDynamicTile> {
|
||||
constructor(public readonly tile: IDynamicTile) {
|
||||
const face = tile.state.faceManager;
|
||||
super(face.get(DYNAMIC_MOVER_FACE)!);
|
||||
super(face.get(DYNAMIC_MOVER_FACE)!, tile.getCurrentFaceDirection());
|
||||
}
|
||||
|
||||
protected onMoveStart(): Promise<void> {
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
import { IHookable, IHookBase, IHookController } from '@motajs/common';
|
||||
import {
|
||||
IHookable,
|
||||
IHookBase,
|
||||
IHookController,
|
||||
ITileLocator
|
||||
} from '@motajs/common';
|
||||
import {
|
||||
FaceDirection,
|
||||
IDataCommonExtended,
|
||||
IMapBlockRawData,
|
||||
IMapRawData,
|
||||
IMoverController,
|
||||
IObjectMovable,
|
||||
IObjectMover,
|
||||
@ -21,6 +28,8 @@ export interface IMapLayerData {
|
||||
}
|
||||
|
||||
export interface ILayerLocation {
|
||||
/** 该点的位置 */
|
||||
readonly locator: ITileLocator;
|
||||
/** 该点的静态图块数字 */
|
||||
readonly tile: number;
|
||||
/** 该点的静态图块信息 */
|
||||
@ -29,6 +38,8 @@ export interface ILayerLocation {
|
||||
readonly trigger: number;
|
||||
/** 该点包含的所有动态图块 */
|
||||
readonly dynamics: Iterable<IDynamicTile>;
|
||||
/** 该点的静态图块原始数据 */
|
||||
readonly block: IMapBlockRawData;
|
||||
}
|
||||
|
||||
export interface IMapLayerHooks extends IHookBase {
|
||||
@ -442,6 +453,12 @@ export interface IMapState
|
||||
*/
|
||||
getActiveMap(id: string): ILayerState | null;
|
||||
|
||||
/**
|
||||
* 从楼层原始数据生成楼层状态
|
||||
* @param raw 楼层原始数据
|
||||
*/
|
||||
fromRaw(raw: IMapRawData): ILayerState | null;
|
||||
|
||||
/**
|
||||
* 创建并注册一个空白楼层,若 id 已存在则警告并覆盖,返回楼层状态对象
|
||||
* @param id 楼层 id
|
||||
|
||||
@ -371,9 +371,13 @@ export abstract class ObjectMover<T extends IObjectMovable>
|
||||
|
||||
readonly faceHandler: IFaceHandler<FaceDirection>;
|
||||
|
||||
constructor(faceHandler: IFaceHandler<FaceDirection>) {
|
||||
constructor(
|
||||
faceHandler: IFaceHandler<FaceDirection>,
|
||||
direction: FaceDirection
|
||||
) {
|
||||
super();
|
||||
this.faceHandler = faceHandler;
|
||||
this.faceDirection = direction;
|
||||
}
|
||||
|
||||
protected createController(
|
||||
@ -651,7 +655,6 @@ export abstract class ObjectMover<T extends IObjectMovable>
|
||||
this.clear();
|
||||
this.shouldStop = false;
|
||||
|
||||
this.faceDirection = this.tile.getCurrentFaceDirection();
|
||||
this.moveDirection = FaceDirection.Unknown;
|
||||
|
||||
const { promise, resolve } = Promise.withResolvers<void>();
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
//#region tile
|
||||
|
||||
import { IFacedTileLocator } from '@motajs/common';
|
||||
|
||||
export const enum TileType {
|
||||
/** 未知或尚未归类的图块 */
|
||||
Unknown,
|
||||
@ -253,6 +255,54 @@ export interface IItemStore<THero, TLegacy> {
|
||||
|
||||
//#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 {
|
||||
/** 楼层 id */
|
||||
readonly floorId: string;
|
||||
@ -262,6 +312,8 @@ export interface IMapRawData {
|
||||
readonly map: Record<number, number[]>;
|
||||
/** 每个地图图层的字符串别名 */
|
||||
readonly layerAlias: Record<number, string>;
|
||||
/** 每个地图图层中,指定位置图块的额外数据,外层 key 为图层 zIndex,内层 key 为图块位置索引 */
|
||||
readonly blockData: Record<number, Record<number, IMapBlockRawData>>;
|
||||
}
|
||||
|
||||
export interface IMapStore {
|
||||
|
||||
162
packages-user/data-state/src/content/triggers.ts
Normal file
162
packages-user/data-state/src/content/triggers.ts
Normal file
@ -0,0 +1,162 @@
|
||||
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.initItemStore(core.items.items);
|
||||
this.initEnemyManager(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
|
||||
this.initMapStore(
|
||||
this.initMapState(
|
||||
core.floorIds,
|
||||
core.floors as Record<FloorIds, ResolvedFloor>
|
||||
);
|
||||
@ -323,7 +323,7 @@ export class CoreState implements ICoreState {
|
||||
manager.compareWith(reference);
|
||||
}
|
||||
|
||||
private initMapStore(
|
||||
private initMapState(
|
||||
floors: FloorIds[],
|
||||
data: Record<FloorIds, ResolvedFloor>
|
||||
) {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export * from './collection';
|
||||
export * from './collector';
|
||||
export * from './registry';
|
||||
export * from './trigger';
|
||||
export * from './types';
|
||||
|
||||
16
packages-user/data-system/src/trigger/trigger.ts
Normal file
16
packages-user/data-system/src/trigger/trigger.ts
Normal file
@ -0,0 +1,16 @@
|
||||
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,7 +58,10 @@
|
||||
"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.",
|
||||
"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": {
|
||||
"1": "Resource with type of 'none' is loaded.",
|
||||
@ -223,6 +226,12 @@
|
||||
"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",
|
||||
"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