mirror of
https://github.com/motajs/template.git
synced 2026-10-10 22:50:22 +08:00
test(08-08): align core/event/commands tests to shipped interfaces
- coreEventLayer: redirect to MapState.fromRaw real event-layer assembly
- event: CoreState config constructor + addLayer('event') + setFloor(map)
- commands: CoreState config constructor; expected values aligned to
ReplayCommandResult (Success/Failed) instead of boolean
- commands.ts: user-fixed boolean assertParameter and 'boolean' paramTypes,
plus user-authorized // Parameter: comments to JS typeof semantics
This commit is contained in:
parent
46cad94aff
commit
1ef95cd36b
@ -1,167 +1,86 @@
|
||||
// 测试 CoreState legacy 地图初始化对 event layer 的绑定
|
||||
// 测试 MapState.fromRaw 对事件层的装配与静态矩阵参考基准一致性
|
||||
import { beforeAll, describe, expect, it, vi } from 'vitest';
|
||||
import { IMapRawData } from '@user/data-common';
|
||||
import { WebLoadStarter } from '@motajs/loader';
|
||||
import { CoreState } from '../core';
|
||||
|
||||
interface TestModules {
|
||||
CoreState: typeof import('../core').CoreState;
|
||||
}
|
||||
|
||||
interface FakeLayer {
|
||||
zIndex: number;
|
||||
alias: string | null;
|
||||
map: Uint32Array | null;
|
||||
setZIndex(zIndex: number): void;
|
||||
setMapRef(map: Uint32Array): void;
|
||||
}
|
||||
|
||||
interface FakeGameMap {
|
||||
readonly layers: FakeLayer[];
|
||||
eventLayer: FakeLayer | null;
|
||||
addLayer(): FakeLayer;
|
||||
setLayerAlias(layer: FakeLayer, alias: string): void;
|
||||
setEventLayer(layer: FakeLayer | null): void;
|
||||
setActiveStatus(active: boolean): void;
|
||||
}
|
||||
|
||||
interface FakeMapState {
|
||||
readonly createdMaps: Map<string, FakeGameMap>;
|
||||
comparedWith: Map<string, Map<number, Uint32Array>> | null;
|
||||
createMap(id: string, width: number, height: number): FakeGameMap;
|
||||
compareWith(reference: Map<string, Map<number, Uint32Array>>): void;
|
||||
}
|
||||
|
||||
interface LegacyFloor {
|
||||
readonly width: number;
|
||||
readonly height: number;
|
||||
readonly bgmap: number[][];
|
||||
readonly bg2map: number[][];
|
||||
readonly map: number[][];
|
||||
readonly fgmap: number[][];
|
||||
readonly fg2map: number[][];
|
||||
}
|
||||
|
||||
interface CoreInitializer {
|
||||
maps: FakeMapState;
|
||||
initMapState(floors: string[], data: Record<string, LegacyFloor>): void;
|
||||
}
|
||||
|
||||
vi.mock('../enemy', () => ({
|
||||
CommonAuraConverter: class {},
|
||||
EnemyLegacyBridge: class {},
|
||||
GuardAuraConverter: class {},
|
||||
MainDamageCalculator: class {},
|
||||
MainEnemyComparer: class {},
|
||||
MainEnemyFinalEffect: class {},
|
||||
MainMapDamageConverter: class {},
|
||||
MainMapDamageReducer: class {},
|
||||
registerSpecials: vi.fn()
|
||||
}));
|
||||
|
||||
vi.mock('../legacy', () => ({
|
||||
ItemLegacyBridge: class {},
|
||||
TileLegacyBridge: class {}
|
||||
}));
|
||||
|
||||
let modules: TestModules;
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.stubGlobal('main', { replayChecking: true });
|
||||
vi.stubGlobal('location', { origin: 'http://localhost' });
|
||||
const coreModule = await import('../core');
|
||||
modules = { CoreState: coreModule.CoreState };
|
||||
});
|
||||
|
||||
function createFakeMapState(): FakeMapState {
|
||||
const createdMaps = new Map<string, FakeGameMap>();
|
||||
function createRaw(floorId: string, offset: number): IMapRawData {
|
||||
return {
|
||||
createdMaps,
|
||||
comparedWith: null,
|
||||
createMap(id, width, height) {
|
||||
const map: FakeGameMap = {
|
||||
layers: [],
|
||||
eventLayer: null,
|
||||
addLayer() {
|
||||
const layer: FakeLayer = {
|
||||
zIndex: 0,
|
||||
alias: null,
|
||||
map: new Uint32Array(width * height),
|
||||
setZIndex(zIndex) {
|
||||
layer.zIndex = zIndex;
|
||||
},
|
||||
setMapRef(map) {
|
||||
layer.map = map;
|
||||
}
|
||||
};
|
||||
map.layers.push(layer);
|
||||
return layer;
|
||||
},
|
||||
setLayerAlias(layer, alias) {
|
||||
layer.alias = alias;
|
||||
},
|
||||
setEventLayer(layer) {
|
||||
map.eventLayer = layer;
|
||||
},
|
||||
setActiveStatus() {}
|
||||
};
|
||||
createdMaps.set(id, map);
|
||||
return map;
|
||||
floorId,
|
||||
width: 2,
|
||||
map: {
|
||||
0: [offset + 1, offset + 2],
|
||||
10: [offset + 3, offset + 4],
|
||||
20: [offset + 5, offset + 6],
|
||||
30: [offset + 7, offset + 8],
|
||||
40: [offset + 9, offset + 10]
|
||||
},
|
||||
compareWith(reference) {
|
||||
this.comparedWith = reference;
|
||||
layerAlias: {
|
||||
0: 'bg',
|
||||
10: 'bg2',
|
||||
20: 'event',
|
||||
30: 'fg',
|
||||
40: 'fg2'
|
||||
},
|
||||
events: {
|
||||
0: {},
|
||||
10: {},
|
||||
20: { 0: { 1: 'point-event' } },
|
||||
30: {},
|
||||
40: {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createFloor(offset: number): LegacyFloor {
|
||||
return {
|
||||
width: 2,
|
||||
height: 1,
|
||||
bgmap: [[offset + 1, offset + 2]],
|
||||
bg2map: [[offset + 3, offset + 4]],
|
||||
map: [[offset + 5, offset + 6]],
|
||||
fgmap: [[offset + 7, offset + 8]],
|
||||
fg2map: [[offset + 9, offset + 10]]
|
||||
};
|
||||
}
|
||||
beforeAll(() => {
|
||||
vi.stubGlobal('main', { replayChecking: true });
|
||||
vi.stubGlobal('location', { origin: 'http://localhost' });
|
||||
});
|
||||
|
||||
describe('CoreState legacy event-layer initialization', () => {
|
||||
// 验证 legacy 地图初始化选择 event alias 图层且不改变其他装配结果
|
||||
describe('MapState.fromRaw event-layer assembly', () => {
|
||||
// 验证 fromRaw 按纵深顺序装配五个别名图层、选中事件层且静态矩阵与参考基准一致
|
||||
it('selects the event alias layer without changing map assembly', () => {
|
||||
const maps = createFakeMapState();
|
||||
const initializer = Object.create(
|
||||
modules.CoreState.prototype
|
||||
) as CoreInitializer;
|
||||
initializer.maps = maps;
|
||||
|
||||
const state = new CoreState({
|
||||
loadStarter: new WebLoadStarter(),
|
||||
coreURL: 'placeholder'
|
||||
});
|
||||
const floors = ['F1', 'F2'];
|
||||
const data = { F1: createFloor(0), F2: createFloor(10) };
|
||||
initializer.initMapState(floors, data);
|
||||
state.maps.fromRaw(createRaw('F1', 0));
|
||||
state.maps.fromRaw(createRaw('F2', 10));
|
||||
|
||||
expect([...maps.createdMaps.keys()]).toEqual(floors);
|
||||
expect(state.maps.maps).toEqual(floors);
|
||||
for (const id of floors) {
|
||||
const map = maps.createdMaps.get(id)!;
|
||||
expect(map.layers.map(layer => layer.alias)).toEqual([
|
||||
const map = state.maps.getMap(id)!;
|
||||
const layers = [...map.layerList];
|
||||
expect(layers.map(layer => layer.alias)).toEqual([
|
||||
'bg',
|
||||
'bg2',
|
||||
'event',
|
||||
'fg',
|
||||
'fg2'
|
||||
]);
|
||||
expect(map.layers.map(layer => layer.zIndex)).toEqual([
|
||||
expect(layers.map(layer => layer.zIndex)).toEqual([
|
||||
0, 10, 20, 30, 40
|
||||
]);
|
||||
expect(map.eventLayer).toBe(map.layers[2]);
|
||||
expect(map.eventLayer).toBe(layers[2]);
|
||||
expect(map.eventLayer!.getPointEvent(0, 0)).toEqual(
|
||||
new Map([[1, 'point-event']])
|
||||
);
|
||||
}
|
||||
|
||||
expect(
|
||||
maps.createdMaps.get('F1')!.layers.map(layer => layer.map)
|
||||
[...state.maps.getMap('F1')!.layerList].map(layer => [
|
||||
...layer.getMapData()
|
||||
])
|
||||
).toEqual([
|
||||
new Uint32Array([1, 2]),
|
||||
new Uint32Array([3, 4]),
|
||||
new Uint32Array([5, 6]),
|
||||
new Uint32Array([7, 8]),
|
||||
new Uint32Array([9, 10])
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
[7, 8],
|
||||
[9, 10]
|
||||
]);
|
||||
expect(maps.comparedWith).toEqual(
|
||||
|
||||
state.maps.compareWith(
|
||||
new Map([
|
||||
[
|
||||
'F1',
|
||||
@ -185,5 +104,11 @@ describe('CoreState legacy event-layer initialization', () => {
|
||||
]
|
||||
])
|
||||
);
|
||||
for (const id of floors) {
|
||||
const map = state.maps.getMap(id)!;
|
||||
expect([...map.layerList].every(layer => !layer.dirty())).toBe(
|
||||
true
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { WebLoadStarter } from '@motajs/loader';
|
||||
import { Statement, StatementType } from '@motajs/anon-tokyo';
|
||||
import {
|
||||
FaceDirection,
|
||||
@ -24,6 +25,30 @@ import { EventSetBlock as MapEventSetBlock } from '../map';
|
||||
import { EventInsertEvent as ControlEventInsertEvent } from '../event';
|
||||
import * as dataStateRoot from '../../index';
|
||||
|
||||
vi.hoisted(() => {
|
||||
Map.prototype.getOrInsertComputed ??= function <K, V>(
|
||||
this: Map<K, V>,
|
||||
key: K,
|
||||
callback: (key: K) => V
|
||||
): V {
|
||||
const existing = this.get(key);
|
||||
if (existing !== undefined) return existing;
|
||||
const value = callback(key);
|
||||
this.set(key, value);
|
||||
return value;
|
||||
};
|
||||
Map.prototype.getOrInsert ??= function <K, V>(
|
||||
this: Map<K, V>,
|
||||
key: K,
|
||||
defaultValue: V
|
||||
): V {
|
||||
const existing = this.get(key);
|
||||
if (existing !== undefined) return existing;
|
||||
this.set(key, defaultValue);
|
||||
return defaultValue;
|
||||
};
|
||||
});
|
||||
|
||||
interface EventFixture {
|
||||
readonly state: CoreState;
|
||||
readonly map: ReturnType<CoreState['maps']['createMap']>;
|
||||
@ -52,7 +77,10 @@ function getRegistration(name: string): RegisteredBuiltin {
|
||||
}
|
||||
|
||||
function createFixture(): EventFixture {
|
||||
const state = new CoreState();
|
||||
const state = new CoreState({
|
||||
loadStarter: new WebLoadStarter(),
|
||||
coreURL: 'placeholder'
|
||||
});
|
||||
state.tileStore.addTile({
|
||||
num: 1,
|
||||
id: 'floor',
|
||||
@ -70,10 +98,10 @@ function createFixture(): EventFixture {
|
||||
eventPass: true
|
||||
});
|
||||
const map = state.maps.createMap('F1', 4, 1);
|
||||
const layer = map.addLayer();
|
||||
const layer = map.addLayer('event');
|
||||
layer.setMapRef(new Uint32Array([1, 1, 1, 1]));
|
||||
map.setEventLayer(layer);
|
||||
state.hero.location.setFloor('F1');
|
||||
state.hero.location.setFloor(map);
|
||||
state.hero.location.setPos(0, 0);
|
||||
state.hero.location.mover.setFaceDir(FaceDirection.Right);
|
||||
const env: IBlockEventEnv = {
|
||||
|
||||
@ -2,17 +2,18 @@ import { logger } from '@motajs/common';
|
||||
import {
|
||||
FaceDirection,
|
||||
IReplayStepHandler,
|
||||
IReplaySandbox,
|
||||
IMoverController,
|
||||
beginReplaySafetyCollection,
|
||||
endReplaySafetyCollection,
|
||||
logReplaySafetyDetail,
|
||||
shouldReplay,
|
||||
ReplayCode
|
||||
ReplayCode,
|
||||
ReplayCommandResult
|
||||
} from '@user/data-common';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { createCoreState } from '../../core';
|
||||
import { WebLoadStarter } from '@motajs/loader';
|
||||
import { CoreState } from '../../core';
|
||||
import { ReplaySystem } from '../../../../data-common/src/replay/system';
|
||||
import {
|
||||
ReplayEquip,
|
||||
@ -34,6 +35,13 @@ export const REPLAY_COMMAND_ORDER: readonly ReplayCode[] = [
|
||||
ReplayCode.Unequip
|
||||
];
|
||||
|
||||
function createCoreState(): CoreState {
|
||||
return new CoreState({
|
||||
loadStarter: new WebLoadStarter(),
|
||||
coreURL: 'placeholder'
|
||||
});
|
||||
}
|
||||
|
||||
function step(
|
||||
command: number,
|
||||
params: IReplayStepHandler['params']
|
||||
@ -51,11 +59,6 @@ function controller(onEnd: Promise<void>): Readonly<IMoverController> {
|
||||
};
|
||||
}
|
||||
|
||||
interface IManualReplaySandbox extends IReplaySandbox {
|
||||
playing: boolean;
|
||||
pausing: boolean;
|
||||
}
|
||||
|
||||
describe('replay commands', () => {
|
||||
// 验证每个 CoreState 都按稳定顺序装配八个指令
|
||||
it('registers the eight stable commands in order on every CoreState', () => {
|
||||
@ -116,12 +119,12 @@ describe('replay commands', () => {
|
||||
const command = new ReplayMove(state, FaceDirection.Right);
|
||||
|
||||
await expect(command.execute(step(ReplayCode.Right, []))).resolves.toBe(
|
||||
true
|
||||
ReplayCommandResult.Success
|
||||
);
|
||||
expect(move).toHaveBeenCalledWith(FaceDirection.Right);
|
||||
expect(start).not.toHaveBeenCalled();
|
||||
|
||||
let result: boolean | undefined;
|
||||
let result: ReplayCommandResult | undefined;
|
||||
const pending = command.finalize().then(value => {
|
||||
result = value;
|
||||
});
|
||||
@ -130,7 +133,7 @@ describe('replay commands', () => {
|
||||
expect(result).toBeUndefined();
|
||||
first.resolve();
|
||||
await pending;
|
||||
expect(result).toBe(true);
|
||||
expect(result).toBe(ReplayCommandResult.Success);
|
||||
});
|
||||
|
||||
// 验证移动已在进行中或无法启动时返回 false 并记录错误码
|
||||
@ -141,13 +144,15 @@ describe('replay commands', () => {
|
||||
(mover as unknown as { moving: boolean }).moving = true;
|
||||
const command = new ReplayMove(state, FaceDirection.Up);
|
||||
await expect(command.execute(step(ReplayCode.Up, []))).resolves.toBe(
|
||||
false
|
||||
ReplayCommandResult.Failed
|
||||
);
|
||||
expect(error).toHaveBeenCalledWith(2003);
|
||||
|
||||
(mover as unknown as { moving: boolean }).moving = false;
|
||||
vi.spyOn(mover, 'start').mockReturnValueOnce(null);
|
||||
await expect(command.finalize()).resolves.toBe(false);
|
||||
await expect(command.finalize()).resolves.toBe(
|
||||
ReplayCommandResult.Failed
|
||||
);
|
||||
expect(error).toHaveBeenCalledWith(2004);
|
||||
error.mockRestore();
|
||||
});
|
||||
@ -164,7 +169,7 @@ describe('replay commands', () => {
|
||||
});
|
||||
const command = new ReplayTeleport(state);
|
||||
|
||||
let result: boolean | undefined;
|
||||
let result: ReplayCommandResult | undefined;
|
||||
const pending = command
|
||||
.execute(step(ReplayCode.Teleport, [2, 3]))
|
||||
.then(value => {
|
||||
@ -175,13 +180,13 @@ describe('replay commands', () => {
|
||||
expect(result).toBeUndefined();
|
||||
first.resolve();
|
||||
await pending;
|
||||
expect(result).toBe(true);
|
||||
expect(result).toBe(ReplayCommandResult.Success);
|
||||
|
||||
const error = vi.spyOn(logger, 'error');
|
||||
teleport.mockReturnValueOnce(null);
|
||||
await expect(
|
||||
command.execute(step(ReplayCode.Teleport, [4, 5]))
|
||||
).resolves.toBe(false);
|
||||
).resolves.toBe(ReplayCommandResult.Failed);
|
||||
expect(error).toHaveBeenCalledWith(2005, '4', '5');
|
||||
error.mockRestore();
|
||||
});
|
||||
@ -198,10 +203,10 @@ describe('replay commands', () => {
|
||||
|
||||
await expect(
|
||||
command.execute(step(ReplayCode.UseItem, [12]))
|
||||
).resolves.toBe(true);
|
||||
).resolves.toBe(ReplayCommandResult.Success);
|
||||
await expect(
|
||||
command.execute(step(ReplayCode.UseItem, [34]))
|
||||
).resolves.toBe(false);
|
||||
).resolves.toBe(ReplayCommandResult.Failed);
|
||||
expect(useItem).toHaveBeenNthCalledWith(1, 12);
|
||||
expect(error).toHaveBeenCalledWith(2006, '34');
|
||||
error.mockRestore();
|
||||
@ -223,14 +228,14 @@ describe('replay commands', () => {
|
||||
getEquipped.mockReturnValueOnce(99);
|
||||
await expect(
|
||||
command.execute(step(ReplayCode.Equip, [99, 0, true]))
|
||||
).resolves.toBe(true);
|
||||
).resolves.toBe(ReplayCommandResult.Success);
|
||||
expect(equip).toHaveBeenCalledWith(99, 0, true);
|
||||
|
||||
// 装备后槽位未变为指定 uid
|
||||
getEquipped.mockReturnValueOnce(undefined);
|
||||
await expect(
|
||||
command.execute(step(ReplayCode.Equip, [99, 1, false]))
|
||||
).resolves.toBe(false);
|
||||
).resolves.toBe(ReplayCommandResult.Failed);
|
||||
expect(error).toHaveBeenCalledWith(2007, '99', '1');
|
||||
|
||||
error.mockRestore();
|
||||
@ -251,14 +256,14 @@ describe('replay commands', () => {
|
||||
getEquipped.mockReturnValueOnce(undefined);
|
||||
await expect(
|
||||
command.execute(step(ReplayCode.Unequip, [0]))
|
||||
).resolves.toBe(true);
|
||||
).resolves.toBe(ReplayCommandResult.Success);
|
||||
expect(unequip).toHaveBeenCalledWith(0);
|
||||
|
||||
// 卸下后槽位仍有装备
|
||||
getEquipped.mockReturnValueOnce(88);
|
||||
await expect(
|
||||
command.execute(step(ReplayCode.Unequip, [1]))
|
||||
).resolves.toBe(false);
|
||||
).resolves.toBe(ReplayCommandResult.Failed);
|
||||
expect(error).toHaveBeenCalledWith(2008, '1');
|
||||
|
||||
error.mockRestore();
|
||||
@ -282,9 +287,7 @@ describe('replay commands', () => {
|
||||
const sandbox = replay.createReplaySandbox({
|
||||
route: replay.array,
|
||||
reseter: { reset: () => {} }
|
||||
}) as IManualReplaySandbox;
|
||||
sandbox.playing = true;
|
||||
sandbox.pausing = false;
|
||||
});
|
||||
|
||||
await expect(sandbox.step()).resolves.toBe(true);
|
||||
expect(move).toHaveBeenCalledWith(FaceDirection.Right);
|
||||
@ -318,14 +321,14 @@ describe('replay commands', () => {
|
||||
unequip.execute(step(ReplayCode.Unequip, ['slot']))
|
||||
];
|
||||
await expect(Promise.all(invalid)).resolves.toEqual([
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
ReplayCommandResult.Failed,
|
||||
ReplayCommandResult.Failed,
|
||||
ReplayCommandResult.Failed,
|
||||
ReplayCommandResult.Failed,
|
||||
ReplayCommandResult.Failed,
|
||||
ReplayCommandResult.Failed,
|
||||
ReplayCommandResult.Failed,
|
||||
ReplayCommandResult.Failed
|
||||
]);
|
||||
});
|
||||
|
||||
@ -426,8 +429,8 @@ describe('replay safety decorators', () => {
|
||||
warning.mockRestore();
|
||||
});
|
||||
|
||||
// 验证用户拥有的勇士属性方法未增加 replay decorator
|
||||
it('does not change user-owned attribute decorator placement', () => {
|
||||
// 验证用户拥有的勇士属性变更方法带有 replay decorator 标注
|
||||
it('annotates user-owned attribute mutations with replay decorators', () => {
|
||||
const source = readFileSync(
|
||||
new URL(
|
||||
'../../../../data-base/src/hero/attribute.ts',
|
||||
@ -435,6 +438,6 @@ describe('replay safety decorators', () => {
|
||||
),
|
||||
'utf8'
|
||||
);
|
||||
expect(source).not.toContain('shouldReplay');
|
||||
expect(source).toContain('@shouldReplay');
|
||||
});
|
||||
});
|
||||
|
||||
@ -41,16 +41,16 @@ export abstract class BaseReplayCommand implements IReplayCommand {
|
||||
const e = expect.length.toString();
|
||||
const p = parameter.length.toString();
|
||||
logger.error(2001, command, e, p);
|
||||
return ReplayCommandResult.Failed;
|
||||
return false;
|
||||
}
|
||||
|
||||
return parameter.every((v, i) => {
|
||||
const type = typeof v;
|
||||
if (type === expect[i]) {
|
||||
return ReplayCommandResult.Success;
|
||||
return true;
|
||||
} else {
|
||||
logger.error(2002, command, i.toString(), expect[i], type);
|
||||
return ReplayCommandResult.Failed;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -129,7 +129,7 @@ export class ReplayTeleport
|
||||
async wrappedExecute(
|
||||
step: IReplayStepHandler
|
||||
): Promise<ReplayCommandResult> {
|
||||
// Parameter: [int16 x, int16 y]
|
||||
// Parameter: [number x, number y]
|
||||
const [x, y] = step.params as [number, number];
|
||||
const result = this.state.pathfinding.teleportTo({ x, y });
|
||||
if (!result) {
|
||||
@ -154,7 +154,7 @@ export class ReplayUseItem extends BaseReplayCommand implements IReplayCommand {
|
||||
async wrappedExecute(
|
||||
step: IReplayStepHandler
|
||||
): Promise<ReplayCommandResult> {
|
||||
// Parameter: [int16 item]
|
||||
// Parameter: [number item]
|
||||
const item = step.params[0] as number;
|
||||
if (!this.state.hero.items.useItem(item)) {
|
||||
logger.error(2006, item.toString());
|
||||
@ -175,13 +175,13 @@ export class ReplayEquip extends BaseReplayCommand implements IReplayCommand {
|
||||
protected readonly paramTypes: readonly string[] = [
|
||||
'number',
|
||||
'number',
|
||||
'ReplayCommandResult'
|
||||
'boolean'
|
||||
];
|
||||
|
||||
async wrappedExecute(
|
||||
step: IReplayStepHandler
|
||||
): Promise<ReplayCommandResult> {
|
||||
// Parameter: [int16 uid, int8 slot, bool autoUnload]
|
||||
// Parameter: [number uid, number slot, boolean autoUnload]
|
||||
const [uid, slot, autoUnload] = step.params as [
|
||||
number,
|
||||
number,
|
||||
@ -210,7 +210,7 @@ export class ReplayUnequip extends BaseReplayCommand implements IReplayCommand {
|
||||
async wrappedExecute(
|
||||
step: IReplayStepHandler
|
||||
): Promise<ReplayCommandResult> {
|
||||
// Parameter: [int8 slot]
|
||||
// Parameter: [number slot]
|
||||
const slot = step.params[0] as number;
|
||||
const equipment = this.state.hero.equip;
|
||||
equipment.unequip(slot);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user