mirror of
https://github.com/motajs/template.git
synced 2026-10-16 18:40:17 +08:00
refactor: 删除 legacy-plugin-data
This commit is contained in:
parent
7e4418362b
commit
10755475a4
@ -1,9 +1,24 @@
|
||||
import { ISaveSystem } from '@user/data-common';
|
||||
import { IBGMPlayer, IMotaAudioContext, ISoundPlayer } from '@motajs/audio';
|
||||
import { ISaveSystem } from './save';
|
||||
import { ICoreState } from '@user/data-state';
|
||||
import { IAutotileProcessor, IMaterialManager } from './material';
|
||||
import { IRenderTreeRoot } from '@motajs/render';
|
||||
|
||||
export interface IClientBase extends ICoreState {
|
||||
/** 存档系统 */
|
||||
readonly save: ISaveSystem;
|
||||
/** 音频上下文 */
|
||||
readonly audioContext: IMotaAudioContext;
|
||||
/** 音效播放器 */
|
||||
readonly soundPlayer: ISoundPlayer<SoundIds>;
|
||||
/** BGM 播放器 */
|
||||
readonly bgmPlayer: IBGMPlayer<BgmIds>;
|
||||
/** 素材管理器 */
|
||||
readonly materials: IMaterialManager;
|
||||
/** 自动元件处理器 */
|
||||
readonly autotile: IAutotileProcessor;
|
||||
/** 渲染画面的根元素 */
|
||||
readonly renderer: IRenderTreeRoot;
|
||||
}
|
||||
|
||||
export interface IClientBaseExtended {
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
"@motajs/types": "workspace:*",
|
||||
"@motajs/system": "workspace:*",
|
||||
"@user/data-base": "workspace:*",
|
||||
"@user/data-state": "workspace:*",
|
||||
"@user/legacy-plugin-data": "workspace:*"
|
||||
"@user/data-state": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,7 +163,7 @@ export const ReplaySettings = defineComponent<MainSettingsProps>(props => {
|
||||
props.controller.closeAll();
|
||||
core.ui.closePanel();
|
||||
const route = core.status.route.slice();
|
||||
const flags = client.data.flags;
|
||||
const flags = client.flags;
|
||||
const seed = flags.getFieldValue<number>('__seed__');
|
||||
core.startGame(core.status.hard, seed, route);
|
||||
break;
|
||||
@ -218,7 +218,7 @@ export const ReplaySettings = defineComponent<MainSettingsProps>(props => {
|
||||
break;
|
||||
}
|
||||
case ReplayChoice.Download: {
|
||||
const flags = client.data.flags;
|
||||
const flags = client.flags;
|
||||
const seed = flags.getFieldValue<number>('__seed__');
|
||||
core.download(
|
||||
core.firstData.name + '_' + core.formatDate2() + '.h5route',
|
||||
|
||||
@ -1,40 +1,20 @@
|
||||
import { IRenderTreeRoot } from '@motajs/render';
|
||||
import { IMapExtensionManager, IMapRenderer } from './render/map';
|
||||
import { IBGMPlayer, IMotaAudioContext, ISoundPlayer } from '@motajs/audio';
|
||||
import {
|
||||
IAutotileProcessor,
|
||||
IMaterialManager,
|
||||
IMotaAssetsLoader,
|
||||
IClientBase
|
||||
} from '@user/client-base';
|
||||
import { IMotaAssetsLoader, IClientBase } from '@user/client-base';
|
||||
import { IExcitation, IExcitationDivider } from '@motajs/animate';
|
||||
|
||||
export interface IClientCore extends IClientBase {
|
||||
/** 渲染端加载对象 */
|
||||
readonly loader: IMotaAssetsLoader;
|
||||
|
||||
/** 素材管理器 */
|
||||
readonly materials: IMaterialManager;
|
||||
/** 自动元件处理器 */
|
||||
readonly autotile: IAutotileProcessor;
|
||||
|
||||
/** 用于渲染系统的 Raf 激励源 */
|
||||
readonly rafExcitation: IExcitation<number>;
|
||||
/** 用于渲染系统的激励源分频器 */
|
||||
readonly excitationDivider: IExcitationDivider<number>;
|
||||
/** 渲染画面的根元素 */
|
||||
readonly renderer: IRenderTreeRoot;
|
||||
|
||||
/** 主地图渲染器,主要用于渲染游戏画面中的地图 */
|
||||
readonly mainMapRenderer: IMapRenderer;
|
||||
/** 副地图渲染器,主要用于渲染缩略图、浏览地图等内容 */
|
||||
// readonly expandMapRenderer: IMapRenderer;
|
||||
/** 主地图渲染器的拓展管理对象 */
|
||||
readonly mainMapExtension: IMapExtensionManager;
|
||||
|
||||
/** 音频上下文 */
|
||||
readonly audioContext: IMotaAudioContext;
|
||||
/** 音效播放器 */
|
||||
readonly soundPlayer: ISoundPlayer<SoundIds>;
|
||||
/** BGM 播放器 */
|
||||
readonly bgmPlayer: IBGMPlayer<BgmIds>;
|
||||
}
|
||||
|
||||
@ -34,9 +34,11 @@ export interface IHaloValue {
|
||||
|
||||
//#endregion
|
||||
|
||||
// TODO: 注释需要更新
|
||||
/**
|
||||
* 注册所有怪物特殊属性到 enemyManager
|
||||
*
|
||||
*
|
||||
* 属性实现位置一览('./'表示当前文件夹 '../'表示上一级文件夹):
|
||||
* 1. 调参类属性 | 仅影响战斗过程的属性:./damage.ts calDamageWithTurn 函数
|
||||
* 2. 地图伤害:./damage.ts DamageEnemy.calMapDamage 方法
|
||||
@ -46,7 +48,6 @@ export interface IHaloValue {
|
||||
* 6. 中毒的瞬移效果:还在脚本编辑的 moveDirectly
|
||||
* 7. 衰弱效果:../state/hero.ts getHeroStatusOf 方法
|
||||
* 8. 重生属性:还在脚本编辑的 changingFloor
|
||||
* 9. 阻击 | 捕捉 的每步效果:packages-user/legacy-plugin-data/src/enemy/checkblock.ts
|
||||
*/
|
||||
export function registerSpecials(manager: IEnemyManager<IEnemyAttr>): void {
|
||||
manager.setAttributeDefaults('guard', new Set());
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
"@user/data-base": "workspace:*",
|
||||
"@user/data-system": "workspace:*",
|
||||
"@user/data-fallback": "workspace:*",
|
||||
"@user/data-state": "workspace:*",
|
||||
"@user/legacy-plugin-data": "workspace:*"
|
||||
"@user/data-state": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,11 +6,8 @@ import * as DataBase from '@user/data-base';
|
||||
import * as DataSystem from '@user/data-system';
|
||||
import * as DataFallback from '@user/data-fallback';
|
||||
import * as DataState from '@user/data-state';
|
||||
import * as LegacyPluginData from '@user/legacy-plugin-data';
|
||||
|
||||
export function create() {
|
||||
DataBase.loading.once('registered', createModule);
|
||||
|
||||
Mota.register('@motajs/common', Common);
|
||||
Mota.register('@motajs/legacy-common', LegacyCommon);
|
||||
Mota.register('@user/data-common', DataCommon);
|
||||
@ -18,11 +15,6 @@ export function create() {
|
||||
Mota.register('@user/data-system', DataSystem);
|
||||
Mota.register('@user/data-fallback', DataFallback);
|
||||
Mota.register('@user/data-state', DataState);
|
||||
Mota.register('@user/legacy-plugin-data', LegacyPluginData);
|
||||
|
||||
DataBase.loading.emit('dataRegistered');
|
||||
}
|
||||
|
||||
function createModule() {
|
||||
LegacyPluginData.createLegacy();
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ import type * as DataSystem from '@user/data-system';
|
||||
import type * as DataState from '@user/data-state';
|
||||
import type * as DataFallback from '@user/data-fallback';
|
||||
import type * as LegacyPluginClient from '@user/legacy-plugin-client';
|
||||
import type * as LegacyPluginData from '@user/legacy-plugin-data';
|
||||
// ---------- 必要的第三方库
|
||||
import type * as MutateAnimate from 'mutate-animate';
|
||||
import type * as Vue from 'vue';
|
||||
@ -41,7 +40,6 @@ interface ModuleInterface {
|
||||
'@user/data-fallback': typeof DataFallback;
|
||||
'@user/data-state': typeof DataState;
|
||||
'@user/legacy-plugin-client': typeof LegacyPluginClient;
|
||||
'@user/legacy-plugin-data': typeof LegacyPluginData;
|
||||
// ---------- 必要的第三方库
|
||||
MutateAnimate: typeof MutateAnimate;
|
||||
Vue: typeof Vue;
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "@user/legacy-plugin-data",
|
||||
"dependencies": {
|
||||
"@user/data-state": "workspace:*",
|
||||
"@user/data-base": "workspace:*"
|
||||
}
|
||||
}
|
||||
@ -1,630 +0,0 @@
|
||||
import type { TimingFn } from 'mutate-animate';
|
||||
import { heroMoveCollection, MoveStep, state } from '@user/data-state';
|
||||
import { hook, loading } from '@user/data-base';
|
||||
import { Patch, PatchClass } from '@motajs/legacy-common';
|
||||
import { isNil } from 'lodash-es';
|
||||
import { fromDirectionString } from '@user/data-common';
|
||||
|
||||
// 向后兼容用,会充当两个版本间过渡的作用
|
||||
|
||||
export function initFallback() {
|
||||
let fallbackIds: number = 1e8;
|
||||
|
||||
const { mover: heroMover } = heroMoveCollection;
|
||||
|
||||
// ----- 工具函数
|
||||
|
||||
/**
|
||||
* 根据事件中给出的移动数组解析出全部的移动步骤
|
||||
*/
|
||||
function getMoveSteps(steps: string[]) {
|
||||
const moveSteps: string[] = [];
|
||||
steps.forEach(v => {
|
||||
const [type, number] = v.split(':');
|
||||
if (!number) moveSteps.push(type);
|
||||
else {
|
||||
if (type === 'speed') moveSteps.push(v);
|
||||
else {
|
||||
moveSteps.push(...Array(Number(number)).fill(type));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return moveSteps;
|
||||
}
|
||||
|
||||
function setHeroDirection(dir: Dir) {
|
||||
heroMover.setFaceDir(dir);
|
||||
heroMover.setMoveDir(dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成跳跃函数
|
||||
*/
|
||||
function generateJumpFn(dx: number, dy: number): TimingFn<2> {
|
||||
const distance = Math.hypot(dx, dy);
|
||||
const peak = 3 + distance;
|
||||
|
||||
return (progress: number) => {
|
||||
const x = dx * progress;
|
||||
const y = progress * dy + (progress ** 2 - progress) * peak;
|
||||
|
||||
return [x, y];
|
||||
};
|
||||
}
|
||||
|
||||
Mota.r(() => {
|
||||
// ----- 引入
|
||||
|
||||
const patch = new Patch(PatchClass.Control);
|
||||
const patch2 = new Patch(PatchClass.Events);
|
||||
const patch3 = new Patch(PatchClass.Maps);
|
||||
|
||||
//#region 勇士移动相关
|
||||
patch.add('moveAction', async function (callback?: () => void) {
|
||||
heroMover.clearMoveQueue();
|
||||
heroMover.oneStep('forward');
|
||||
const lock = core.status.lockControl;
|
||||
const controller = heroMover.startMove(false, true, lock);
|
||||
controller?.onEnd.then(() => {
|
||||
callback?.();
|
||||
});
|
||||
heroMover.once('stepEnd', () => {
|
||||
controller?.stop();
|
||||
});
|
||||
});
|
||||
|
||||
patch.add('_moveAction_moving', () => {});
|
||||
|
||||
patch2.add('_action_moveAction', function () {
|
||||
if (core.canMoveHero()) {
|
||||
const nx = core.nextX(),
|
||||
ny = core.nextY();
|
||||
// 检查noPass决定是撞击还是移动
|
||||
if (core.noPass(nx, ny)) {
|
||||
core.insertAction([{ type: 'trigger', loc: [nx, ny] }]);
|
||||
} else {
|
||||
// 先移动一格,然后尝试触发事件
|
||||
core.insertAction([
|
||||
{
|
||||
type: 'function',
|
||||
function:
|
||||
'function() { core.moveAction(core.doAction); }',
|
||||
async: true
|
||||
},
|
||||
{ type: '_label' }
|
||||
]);
|
||||
}
|
||||
}
|
||||
core.doAction();
|
||||
});
|
||||
|
||||
patch2.add(
|
||||
'eventMoveHero',
|
||||
async function (
|
||||
steps: string[],
|
||||
time: number = 500,
|
||||
callback?: () => void
|
||||
) {
|
||||
if (heroMover.moving) return;
|
||||
const moveSteps = getMoveSteps(steps);
|
||||
|
||||
const resolved = moveSteps.map<MoveStep>(v => {
|
||||
if (v.startsWith('speed')) {
|
||||
return { type: 'speed', value: Number(v.slice(6)) };
|
||||
} else {
|
||||
return { type: 'dir', value: v as Move2 };
|
||||
}
|
||||
});
|
||||
const start: MoveStep = { type: 'speed', value: time };
|
||||
|
||||
heroMover.insertMove(...[start, ...resolved]);
|
||||
const controller = heroMover.startMove(true, true, true, false);
|
||||
if (!controller) {
|
||||
callback?.();
|
||||
return;
|
||||
}
|
||||
controller.onEnd.then(() => {
|
||||
callback?.();
|
||||
});
|
||||
|
||||
const animate = fallbackIds++;
|
||||
|
||||
core.animateFrame.lastAsyncId = animate;
|
||||
core.animateFrame.asyncId[animate] = controller.stop;
|
||||
}
|
||||
);
|
||||
|
||||
patch.add(
|
||||
'setHeroLoc',
|
||||
function (
|
||||
name: 'x' | 'y' | 'direction',
|
||||
value: number | Dir,
|
||||
noGather?: boolean
|
||||
) {
|
||||
if (!core.status.hero) return;
|
||||
// @ts-expect-error todo
|
||||
core.status.hero.loc[name] = value;
|
||||
if (name === 'direction') {
|
||||
const dir = fromDirectionString(value as Dir);
|
||||
state.hero.mover.turn(dir);
|
||||
setHeroDirection(value as Dir);
|
||||
} else if (name === 'x') {
|
||||
// 为了防止逆天样板出问题
|
||||
core.bigmap.posX = value as number;
|
||||
if (!noGather) {
|
||||
state.hero.mover.setPosition(
|
||||
value as number,
|
||||
core.status.hero.loc.y
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 为了防止逆天样板出问题
|
||||
core.bigmap.posY = value as number;
|
||||
if (!noGather) {
|
||||
state.hero.mover.setPosition(
|
||||
core.status.hero.loc.x,
|
||||
value as number
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
patch.add('waitHeroToStop', function (callback?: () => void) {
|
||||
core.stopAutomaticRoute();
|
||||
core.clearContinueAutomaticRoute();
|
||||
heroMover.controller?.stop();
|
||||
if (callback) {
|
||||
core.status.replay.animate = true;
|
||||
core.lockControl();
|
||||
core.status.automaticRoute.moveDirectly = false;
|
||||
setTimeout(
|
||||
function () {
|
||||
core.status.replay.animate = false;
|
||||
callback();
|
||||
},
|
||||
core.status.replay.speed === 24 ? 1 : 30
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
patch.add(
|
||||
'moveHero',
|
||||
async function (
|
||||
direction?: Dir,
|
||||
callback?: () => void,
|
||||
noRoute: boolean = false
|
||||
) {
|
||||
if (heroMover.moving) return;
|
||||
heroMover.clearMoveQueue();
|
||||
heroMover.oneStep(direction ?? 'forward');
|
||||
const lock = core.status.lockControl;
|
||||
const controller = heroMover.startMove(false, noRoute, lock);
|
||||
controller?.onEnd.then(() => {
|
||||
callback?.();
|
||||
});
|
||||
heroMover.once('stepEnd', () => {
|
||||
controller?.stop();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
patch2.add('setHeroIcon', function (name: ImageIds) {
|
||||
core.status.hero.image = name;
|
||||
state.hero.mover.setImage(name);
|
||||
});
|
||||
|
||||
patch.add('isMoving', function () {
|
||||
return heroMover.moving;
|
||||
});
|
||||
|
||||
patch.add(
|
||||
'setAutomaticRoute',
|
||||
function (destX: number, destY: number, stepPostfix: DiredLoc[]) {
|
||||
if (heroMover.moving) return;
|
||||
if (!core.status.played || core.status.lockControl) return;
|
||||
if (core.control._setAutomaticRoute_isMoving(destX, destY))
|
||||
return;
|
||||
if (
|
||||
core.control._setAutomaticRoute_isTurning(
|
||||
destX,
|
||||
destY,
|
||||
stepPostfix
|
||||
)
|
||||
)
|
||||
return;
|
||||
if (
|
||||
core.control._setAutomaticRoute_clickMoveDirectly(
|
||||
destX,
|
||||
destY,
|
||||
stepPostfix
|
||||
)
|
||||
)
|
||||
return;
|
||||
// 找寻自动寻路路线
|
||||
const moveStep = core.automaticRoute(destX, destY);
|
||||
if (
|
||||
moveStep.length === 0 &&
|
||||
(destX !== core.status.hero.loc.x ||
|
||||
destY !== core.status.hero.loc.y ||
|
||||
stepPostfix.length === 0)
|
||||
)
|
||||
return;
|
||||
moveStep.push(...stepPostfix);
|
||||
core.status.automaticRoute.destX = destX;
|
||||
core.status.automaticRoute.destY = destY;
|
||||
core.control._setAutomaticRoute_drawRoute(moveStep);
|
||||
core.control._setAutomaticRoute_setAutoSteps(moveStep);
|
||||
|
||||
// ???
|
||||
core.setAutoHeroMove();
|
||||
|
||||
// 执行移动
|
||||
const steps: MoveStep[] = moveStep.map(v => {
|
||||
return { type: 'dir', value: v.direction };
|
||||
});
|
||||
heroMover.clearMoveQueue();
|
||||
heroMover.insertMove(...steps);
|
||||
heroMover.startMove();
|
||||
}
|
||||
);
|
||||
|
||||
//#region 开关门
|
||||
|
||||
patch2.add(
|
||||
'openDoor',
|
||||
function (
|
||||
x: number,
|
||||
y: number,
|
||||
needKey: boolean,
|
||||
callback?: () => void
|
||||
) {
|
||||
const block = core.getBlock(x, y);
|
||||
core.saveAndStopAutomaticRoute();
|
||||
if (!core.events._openDoor_check(block, x, y, needKey)) {
|
||||
const locked = core.status.lockControl;
|
||||
core.waitHeroToStop(function () {
|
||||
if (!locked) core.unlockControl();
|
||||
if (callback) callback();
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (core.status.replay.speed === 24) {
|
||||
core.status.replay.animate = true;
|
||||
core.removeBlock(x, y);
|
||||
setTimeout(function () {
|
||||
core.status.replay.animate = false;
|
||||
hook.emit(
|
||||
'afterOpenDoor',
|
||||
block.event.id as AllIdsOf<'animates'>,
|
||||
x,
|
||||
y
|
||||
);
|
||||
if (callback) callback();
|
||||
}, 1); // +1是为了录像检测系统
|
||||
} else {
|
||||
const locked = core.status.lockControl;
|
||||
core.lockControl();
|
||||
core.status.replay.animate = true;
|
||||
|
||||
const cb = () => {
|
||||
core.removeBlock(x, y);
|
||||
core.maps._removeBlockFromMap(
|
||||
core.status.floorId,
|
||||
block
|
||||
);
|
||||
if (!locked) core.unlockControl();
|
||||
core.status.replay.animate = false;
|
||||
hook.emit(
|
||||
'afterOpenDoor',
|
||||
block.event.id as AllIdsOf<'animates'>,
|
||||
x,
|
||||
y
|
||||
);
|
||||
callback?.();
|
||||
};
|
||||
|
||||
// const layer = state.maps.getLayerByAlias('event')!;
|
||||
// layer.openDoor(x, y).then(cb);
|
||||
|
||||
const animate = fallbackIds++;
|
||||
core.animateFrame.lastAsyncId = animate;
|
||||
core.animateFrame.asyncId[animate] = cb;
|
||||
// this._openDoor_animate(block, x, y, callback);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
patch2.add(
|
||||
'closeDoor',
|
||||
function (x: number, y: number, id: AllIds, callback?: () => void) {
|
||||
id = id || '';
|
||||
if (
|
||||
// @ts-expect-error todo
|
||||
(isNil(core.material.icons.animates[id]) &&
|
||||
// @ts-expect-error todo
|
||||
isNil(core.material.icons.npc48[id])) ||
|
||||
!isNil(core.getBlock(x, y))
|
||||
) {
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
const block = core.getBlockById(id);
|
||||
const doorInfo = (block.event || {}).doorInfo;
|
||||
if (!doorInfo) {
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
|
||||
core.playSound(doorInfo.closeSound);
|
||||
|
||||
const locked = core.status.lockControl;
|
||||
core.lockControl();
|
||||
core.status.replay.animate = true;
|
||||
const cb = function () {
|
||||
if (!locked) core.unlockControl();
|
||||
core.status.replay.animate = false;
|
||||
core.setBlock(id, x, y);
|
||||
core.showBlock(x, y);
|
||||
callback?.();
|
||||
};
|
||||
|
||||
if (core.status.replay.speed === 24) {
|
||||
cb();
|
||||
} else {
|
||||
// const num = state.tileStore.idToNumber(id)!;
|
||||
// const layer = state.maps.getLayerByAlias('event')!;
|
||||
// layer.closeDoor(num, x, y).then(cb);
|
||||
|
||||
const animate = fallbackIds++;
|
||||
core.animateFrame.lastAsyncId = animate;
|
||||
core.animateFrame.asyncId[animate] = cb;
|
||||
core.events._openDoor_animate(block, x, y, callback);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
//#region 动画
|
||||
|
||||
patch3.add(
|
||||
'drawAnimate',
|
||||
function (
|
||||
name: AnimationIds,
|
||||
x: number,
|
||||
y: number,
|
||||
_alignWindow?: boolean,
|
||||
callback?: () => void
|
||||
) {
|
||||
// @ts-expect-error todo
|
||||
name = core.getMappedName(name);
|
||||
|
||||
// 正在播放录像:不显示动画
|
||||
if (
|
||||
core.isReplaying() ||
|
||||
!core.material.animates[name] ||
|
||||
isNil(x) ||
|
||||
isNil(y)
|
||||
) {
|
||||
callback?.();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// adapters.animate
|
||||
// ?.all(
|
||||
// 'drawAnimate',
|
||||
// name,
|
||||
// x * 32 + 16,
|
||||
// y * 32 + 16,
|
||||
// alignWindow ?? false
|
||||
// )
|
||||
// .then(() => {
|
||||
// callback?.();
|
||||
// });
|
||||
}
|
||||
);
|
||||
|
||||
patch3.add(
|
||||
'drawHeroAnimate',
|
||||
function (name: AnimationIds, callback?: () => void) {
|
||||
// @ts-expect-error todo
|
||||
name = core.getMappedName(name);
|
||||
|
||||
// 正在播放录像或动画不存在:不显示动画
|
||||
if (core.isReplaying() || !core.material.animates[name]) {
|
||||
if (callback) callback();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// adapters.animate?.global('drawHeroAnimate', name).then(() => {
|
||||
// callback?.();
|
||||
// });
|
||||
}
|
||||
);
|
||||
|
||||
patch3.add(
|
||||
'moveBlock',
|
||||
async function (
|
||||
x: number,
|
||||
y: number,
|
||||
steps: string[],
|
||||
time: number = 500,
|
||||
keep: boolean = false,
|
||||
callback?: () => void
|
||||
) {
|
||||
if (!steps || steps.length === 0) {
|
||||
callback?.();
|
||||
return;
|
||||
}
|
||||
const block = core.getBlock(x, y);
|
||||
if (!block) {
|
||||
callback?.();
|
||||
return;
|
||||
}
|
||||
// const mover = new BlockMover(
|
||||
// x,
|
||||
// y,
|
||||
// core.status.floorId,
|
||||
// 'event'
|
||||
// );
|
||||
// const moveSteps = getMoveSteps(steps);
|
||||
// const resolved = moveSteps.map<MoveStep>(v => {
|
||||
// if (v.startsWith('speed')) {
|
||||
// return { type: 'speed', value: Number(v.slice(6)) };
|
||||
// } else {
|
||||
// return { type: 'dir', value: v as Move2 };
|
||||
// }
|
||||
// });
|
||||
// const start: MoveStep = { type: 'speed', value: time };
|
||||
// mover.insertMove(...[start, ...resolved]);
|
||||
// const controller = mover.startMove();
|
||||
|
||||
// if (controller) {
|
||||
// await controller.onEnd;
|
||||
// }
|
||||
|
||||
// if (!keep) {
|
||||
// core.removeBlock(mover.x, mover.y);
|
||||
// }
|
||||
callback?.();
|
||||
}
|
||||
);
|
||||
|
||||
patch3.add(
|
||||
'jumpBlock',
|
||||
async function (
|
||||
sx: number,
|
||||
sy: number,
|
||||
ex: number,
|
||||
ey: number,
|
||||
time: number = 500,
|
||||
keep: boolean = false,
|
||||
callback?: () => void
|
||||
) {
|
||||
const block = core.getBlock(sx, sy);
|
||||
if (!block) {
|
||||
callback?.();
|
||||
return;
|
||||
}
|
||||
time /= core.status.replay.speed;
|
||||
if (core.status.replay.speed === 24) time = 1;
|
||||
const dx = ex - sx;
|
||||
const dy = ey - sy;
|
||||
|
||||
const fn = generateJumpFn(dx, dy);
|
||||
// 先使用 mainMapRenderer 妥协
|
||||
const { client } = Mota.require('@user/client-modules');
|
||||
const renderer = client.mainMapRenderer;
|
||||
// if (renderer.layerState !== state.maps) {
|
||||
// callback?.();
|
||||
// return;
|
||||
// }
|
||||
// const layer = state.maps.getLayerByAlias('event');
|
||||
// if (!layer) {
|
||||
// callback?.();
|
||||
// return;
|
||||
// }
|
||||
core.removeBlock(sx, sy);
|
||||
// const moving = renderer.addMovingBlock(layer, block.id, sx, sy);
|
||||
core.updateStatusBar();
|
||||
// await moving.moveRelative(fn, time);
|
||||
// moving.destroy();
|
||||
|
||||
if (keep) {
|
||||
core.setBlock(block.id, ex, ey);
|
||||
}
|
||||
core.updateStatusBar();
|
||||
|
||||
callback?.();
|
||||
}
|
||||
);
|
||||
|
||||
patch2.add(
|
||||
'jumpHero',
|
||||
async function (
|
||||
ex: number,
|
||||
ey: number,
|
||||
time: number = 500,
|
||||
callback?: () => void
|
||||
) {
|
||||
if (heroMover.moving) return;
|
||||
|
||||
// adapters.viewport?.all('mutateTo', ex, ey, time);
|
||||
|
||||
const locked = core.status.lockControl;
|
||||
core.lockControl();
|
||||
|
||||
time /= core.status.replay.speed;
|
||||
if (core.status.replay.speed === 24) time = 1;
|
||||
|
||||
await state.hero.mover.jumpHero(ex, ey, time);
|
||||
|
||||
if (!locked) core.unlockControl();
|
||||
core.setHeroLoc('x', ex);
|
||||
core.setHeroLoc('y', ey);
|
||||
callback?.();
|
||||
}
|
||||
);
|
||||
|
||||
//#region 视角处理
|
||||
|
||||
patch.add(
|
||||
'moveDirectly',
|
||||
function (destX: number, destY: number, ignoreSteps: number) {
|
||||
const data = core.control.controldata;
|
||||
const success = data.moveDirectly(destX, destY, ignoreSteps);
|
||||
// if (success) adapters.viewport?.all('mutateTo', destX, destY);
|
||||
return success;
|
||||
}
|
||||
);
|
||||
|
||||
patch.add(
|
||||
'moveViewport',
|
||||
function (
|
||||
x: number,
|
||||
y: number,
|
||||
_moveMode: EaseMode,
|
||||
time: number = 1,
|
||||
callback?: () => void
|
||||
) {
|
||||
// todo
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
loading.once('loaded', () => {
|
||||
for (const animate of Object.values(core.material.animates)) {
|
||||
animate.se ??= {};
|
||||
if (typeof animate.se === 'string') {
|
||||
animate.se = { 1: animate.se };
|
||||
}
|
||||
animate.pitch ??= {};
|
||||
}
|
||||
});
|
||||
loading.once('coreInit', () => {
|
||||
const moveAction = new Set<string>(['up', 'down', 'left', 'right']);
|
||||
// 复写录像的移动
|
||||
core.registerReplayAction('move', action => {
|
||||
if (moveAction.has(action)) {
|
||||
if (!heroMover.moving) {
|
||||
heroMover.startMove();
|
||||
}
|
||||
if (!heroMover.controller) {
|
||||
return false;
|
||||
}
|
||||
heroMover.controller.push({
|
||||
type: 'dir',
|
||||
value: action as Dir
|
||||
});
|
||||
|
||||
heroMover.controller.onEnd.then(() => {
|
||||
core.replay();
|
||||
});
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -1,220 +0,0 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// 创建新图层
|
||||
function createCanvas(name, zIndex) {
|
||||
if (!name) return;
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.id = name;
|
||||
canvas.className = 'gameCanvas no-anti-aliasing';
|
||||
// 编辑器模式下设置zIndex会导致加入的图层覆盖优先级过高
|
||||
if (main.mode != 'editor') canvas.style.zIndex = zIndex || 0;
|
||||
// 将图层插入进游戏内容
|
||||
document.getElementById('gameDraw').appendChild(canvas);
|
||||
var ctx = canvas.getContext('2d');
|
||||
core.canvas[name] = ctx;
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
export function initFiveLayer() {
|
||||
// 大地图适配
|
||||
|
||||
core.initStatus.bg2maps = {};
|
||||
core.initStatus.fg2maps = {};
|
||||
|
||||
if (main.mode == 'editor') {
|
||||
var bg2Canvas = createCanvas('bg2', 20);
|
||||
var fg2Canvas = createCanvas('fg2', 63);
|
||||
core.bigmap.canvas = [
|
||||
'bg2',
|
||||
'fg2',
|
||||
'bg',
|
||||
'event',
|
||||
'event2',
|
||||
'fg',
|
||||
'damage'
|
||||
];
|
||||
/*插入编辑器的图层 不做此步新增图层无法在编辑器显示*/
|
||||
// 编辑器图层覆盖优先级 eui > efg > fg(前景层) > event2(48*32图块的事件层) > event(事件层) > bg(背景层)
|
||||
// 背景层2(bg2) 插入事件层(event)之前(即bg与event之间)
|
||||
document
|
||||
.getElementById('mapEdit')
|
||||
.insertBefore(bg2Canvas, document.getElementById('event'));
|
||||
// 前景层2(fg2) 插入编辑器前景(efg)之前(即fg之后)
|
||||
document
|
||||
.getElementById('mapEdit')
|
||||
.insertBefore(fg2Canvas, document.getElementById('ebm'));
|
||||
// 原本有三个图层 从4开始添加
|
||||
var num = 4;
|
||||
// 新增图层存入editor.dom中
|
||||
editor.dom.bg2c = core.canvas.bg2.canvas;
|
||||
editor.dom.bg2Ctx = core.canvas.bg2;
|
||||
editor.dom.fg2c = core.canvas.fg2.canvas;
|
||||
editor.dom.fg2Ctx = core.canvas.fg2;
|
||||
editor.dom.maps.push('bg2map', 'fg2map');
|
||||
editor.dom.canvas.push('bg2', 'fg2');
|
||||
|
||||
// 创建编辑器上的按钮
|
||||
var createCanvasBtn = name => {
|
||||
// 电脑端创建按钮
|
||||
var input = document.createElement('input');
|
||||
// layerMod4/layerMod5
|
||||
var id = 'layerMod' + num++;
|
||||
// bg2map/fg2map
|
||||
var value = name + 'map';
|
||||
input.type = 'radio';
|
||||
input.name = 'layerMod';
|
||||
input.id = id;
|
||||
input.value = value;
|
||||
editor.dom[id] = input;
|
||||
input.onchange = () => {
|
||||
editor.uifunctions.setLayerMod(value);
|
||||
};
|
||||
return input;
|
||||
};
|
||||
|
||||
var createCanvasBtn_mobile = name => {
|
||||
// 手机端往选择列表中添加子选项
|
||||
var input = document.createElement('option');
|
||||
var id = 'layerMod' + num++;
|
||||
var value = name + 'map';
|
||||
input.name = 'layerMod';
|
||||
input.value = value;
|
||||
editor.dom[id] = input;
|
||||
return input;
|
||||
};
|
||||
if (!editor.isMobile) {
|
||||
var input = createCanvasBtn('bg2');
|
||||
var input2 = createCanvasBtn('fg2');
|
||||
// 获取事件层及其父节点
|
||||
var child = document.getElementById('layerMod'),
|
||||
parent = child.parentNode;
|
||||
// 背景层2插入事件层前
|
||||
parent.insertBefore(input, child);
|
||||
// 不能直接更改背景层2的innerText 所以创建文本节点
|
||||
var txt = document.createTextNode('背2');
|
||||
// 插入事件层前(即新插入的背景层2前)
|
||||
parent.insertBefore(txt, child);
|
||||
// 向最后插入前景层2(即插入前景层后)
|
||||
parent.appendChild(input2);
|
||||
var txt2 = document.createTextNode('前2');
|
||||
parent.appendChild(txt2);
|
||||
} else {
|
||||
var input = createCanvasBtn_mobile('bg2');
|
||||
var input2 = createCanvasBtn_mobile('fg2');
|
||||
// 手机端因为是选项 所以可以直接改innerText
|
||||
input.innerText = '背景2';
|
||||
input2.innerText = '前景2';
|
||||
var parent = document.getElementById('layerMod');
|
||||
parent.insertBefore(input, parent.children[1]);
|
||||
parent.appendChild(input2);
|
||||
}
|
||||
}
|
||||
|
||||
maps.prototype._loadFloor_doNotCopy = function () {
|
||||
return [
|
||||
'firstArrive',
|
||||
'eachArrive',
|
||||
'blocks',
|
||||
'parallelDo',
|
||||
'map',
|
||||
'bgmap',
|
||||
'fgmap',
|
||||
'bg2map',
|
||||
'fg2map',
|
||||
'events',
|
||||
'changeFloor',
|
||||
'afterBattle',
|
||||
'afterGetItem',
|
||||
'afterOpenDoor',
|
||||
'cannotMove',
|
||||
'enemy'
|
||||
];
|
||||
};
|
||||
////// 绘制背景和前景层 //////
|
||||
maps.prototype._drawBg_draw = function (
|
||||
floorId,
|
||||
toDrawCtx,
|
||||
cacheCtx,
|
||||
config
|
||||
) {
|
||||
config.ctx = cacheCtx;
|
||||
core.maps._drawBg_drawBackground(floorId, config);
|
||||
// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。
|
||||
core.maps._drawFloorImages(
|
||||
floorId,
|
||||
config.ctx,
|
||||
'bg',
|
||||
null,
|
||||
null,
|
||||
config.onMap
|
||||
);
|
||||
core.maps._drawBgFgMap(floorId, 'bg', config);
|
||||
if (config.onMap) {
|
||||
core.drawImage(
|
||||
toDrawCtx,
|
||||
cacheCtx.canvas,
|
||||
core.bigmap.v2 ? -32 : 0,
|
||||
core.bigmap.v2 ? -32 : 0
|
||||
);
|
||||
core.clearMap('bg2');
|
||||
core.clearMap(cacheCtx);
|
||||
}
|
||||
core.maps._drawBgFgMap(floorId, 'bg2', config);
|
||||
if (config.onMap)
|
||||
core.drawImage(
|
||||
'bg2',
|
||||
cacheCtx.canvas,
|
||||
core.bigmap.v2 ? -32 : 0,
|
||||
core.bigmap.v2 ? -32 : 0
|
||||
);
|
||||
config.ctx = toDrawCtx;
|
||||
};
|
||||
maps.prototype._drawFg_draw = function (
|
||||
floorId,
|
||||
toDrawCtx,
|
||||
cacheCtx,
|
||||
config
|
||||
) {
|
||||
config.ctx = cacheCtx;
|
||||
// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块;后绘制的覆盖先绘制的。
|
||||
core.maps._drawFloorImages(
|
||||
floorId,
|
||||
config.ctx,
|
||||
'fg',
|
||||
null,
|
||||
null,
|
||||
config.onMap
|
||||
);
|
||||
core.maps._drawBgFgMap(floorId, 'fg', config);
|
||||
if (config.onMap) {
|
||||
core.drawImage(
|
||||
toDrawCtx,
|
||||
cacheCtx.canvas,
|
||||
core.bigmap.v2 ? -32 : 0,
|
||||
core.bigmap.v2 ? -32 : 0
|
||||
);
|
||||
core.clearMap('fg2');
|
||||
core.clearMap(cacheCtx);
|
||||
}
|
||||
core.maps._drawBgFgMap(floorId, 'fg2', config);
|
||||
if (config.onMap)
|
||||
core.drawImage(
|
||||
'fg2',
|
||||
cacheCtx.canvas,
|
||||
core.bigmap.v2 ? -32 : 0,
|
||||
core.bigmap.v2 ? -32 : 0
|
||||
);
|
||||
config.ctx = toDrawCtx;
|
||||
};
|
||||
////// 移动判定 //////
|
||||
maps.prototype._generateMovableArray_arrays = function (floorId) {
|
||||
return {
|
||||
bgArray: this.getBgMapArray(floorId),
|
||||
fgArray: this.getFgMapArray(floorId),
|
||||
eventArray: this.getMapArray(floorId),
|
||||
bg2Array: this._getBgFgMapArray('bg2', floorId),
|
||||
fg2Array: this._getBgFgMapArray('fg2', floorId)
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
import { hook } from '@user/data-base';
|
||||
import { isNil } from 'lodash-es';
|
||||
|
||||
const potionItems: AllIdsOf<'items'>[] = [
|
||||
'redPotion',
|
||||
'bluePotion',
|
||||
'yellowPotion',
|
||||
'greenPotion'
|
||||
];
|
||||
|
||||
export function createHook() {
|
||||
hook.on('afterGetItem', (itemId, x, y, isGentleClick) => {
|
||||
// 获得一个道具后触发的事件
|
||||
// itemId:获得的道具ID;x和y是该道具所在的坐标
|
||||
// isGentleClick:是否是轻按触发的
|
||||
if (potionItems.includes(itemId)) core.playSound('回血');
|
||||
else core.playSound('获得道具');
|
||||
|
||||
const todo: any[] = [];
|
||||
// 检查该点的获得道具后事件。
|
||||
if (isNil(core.status.floorId)) return;
|
||||
const event =
|
||||
core.floors[core.status.floorId].afterGetItem[`${x},${y}`];
|
||||
if (
|
||||
event &&
|
||||
(event instanceof Array ||
|
||||
!isGentleClick ||
|
||||
!event.disableOnGentleClick)
|
||||
) {
|
||||
core.unshift(todo, event as any[]);
|
||||
}
|
||||
|
||||
if (todo.length > 0) core.insertAction(todo, x, y);
|
||||
});
|
||||
|
||||
hook.on('afterOpenDoor', (_doorId, x, y) => {
|
||||
// 开一个门后触发的事件s
|
||||
|
||||
const todo: any[] = [];
|
||||
// 检查该点的获得开门后事件。
|
||||
if (isNil(core.status.floorId)) return;
|
||||
const event =
|
||||
core.floors[core.status.floorId].afterOpenDoor[`${x},${y}`];
|
||||
if (event) core.unshift(todo, event as any[]);
|
||||
|
||||
if (todo.length > 0) core.insertAction(todo, x, y);
|
||||
|
||||
if (isNil(core.status.event.id)) core.continueAutomaticRoute();
|
||||
else core.clearContinueAutomaticRoute();
|
||||
});
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
import { loading } from '@user/data-base';
|
||||
import { initFallback } from './fallback';
|
||||
import { initFiveLayer } from './fiveLayer';
|
||||
import { createHook } from './hook';
|
||||
import { initReplay } from './replay';
|
||||
|
||||
export function createLegacy() {
|
||||
initFallback();
|
||||
loading.once('coreInit', () => {
|
||||
initFiveLayer();
|
||||
createHook();
|
||||
initReplay();
|
||||
});
|
||||
}
|
||||
|
||||
export * from './fallback';
|
||||
export * from './fiveLayer';
|
||||
export * from './replay';
|
||||
export * from './shop';
|
||||
@ -1,112 +0,0 @@
|
||||
import { canOpenShop } from './shop';
|
||||
import { hook } from '@user/data-base';
|
||||
|
||||
let cliping = false;
|
||||
let startIndex = 0;
|
||||
|
||||
export function readyClip() {
|
||||
cliping = true;
|
||||
return (startIndex = core.status.route.length - 1);
|
||||
}
|
||||
|
||||
export function clip(...replace: string[]) {
|
||||
if (!cliping) return;
|
||||
cliping = false;
|
||||
|
||||
core.status.route.splice(startIndex);
|
||||
core.status.route.push(...replace);
|
||||
}
|
||||
|
||||
export function initReplay() {
|
||||
function tipAndWait(content: string, time: number) {
|
||||
const speed = core.status.replay.speed;
|
||||
if (main.replayChecking || speed === 24) return Promise.resolve();
|
||||
const { tip } = Mota.require('@motajs/legacy-ui');
|
||||
tip('info', '录像播放操作:' + content);
|
||||
return new Promise<void>(res => {
|
||||
setTimeout(res, time / speed);
|
||||
});
|
||||
}
|
||||
|
||||
// 商店
|
||||
let shopOpened = false;
|
||||
let openedShopId = '';
|
||||
|
||||
hook.on('reset', () => {
|
||||
shopOpened = false;
|
||||
openedShopId = '';
|
||||
});
|
||||
|
||||
core.registerReplayAction('openShop', name => {
|
||||
if (!name.startsWith('openShop:')) return false;
|
||||
const id = name.slice(9);
|
||||
if (!canOpenShop(id)) return false;
|
||||
if (shopOpened && openedShopId === id) return true;
|
||||
openedShopId = name.slice(9);
|
||||
shopOpened = true;
|
||||
core.status.route.push(name);
|
||||
core.replay();
|
||||
return true;
|
||||
});
|
||||
|
||||
core.registerReplayAction('buy', name => {
|
||||
if (!name.startsWith('buy:') && !name.startsWith('sell:')) return false;
|
||||
if (!shopOpened) return false;
|
||||
if (!openedShopId) return false;
|
||||
const [type, id, n] = name.split(':');
|
||||
const num = parseInt(n);
|
||||
const shop = core.status.shops[openedShopId] as ItemShopEvent;
|
||||
const item = shop.choices.find(v => v.id === id);
|
||||
if (!item) return false;
|
||||
flags.itemShop ??= {};
|
||||
flags.itemShop[openedShopId] ??= {};
|
||||
flags.itemShop[openedShopId][id] ??= 0;
|
||||
if ((num as number) > item.number - flags.itemShop[openedShopId][id]) {
|
||||
return false;
|
||||
}
|
||||
let cost = 0;
|
||||
if (type === 'buy') {
|
||||
cost = parseInt(item.money) * (num as number);
|
||||
} else {
|
||||
cost = -item.sell * (num as number);
|
||||
}
|
||||
if (cost > core.status.hero.money) return false;
|
||||
core.status.hero.money -= cost;
|
||||
flags.itemShop[openedShopId][id] += type === 'buy' ? num : -num;
|
||||
core.addItem(
|
||||
id as AllIdsOf<'items'>,
|
||||
(type === 'buy' ? num : -num) as number
|
||||
);
|
||||
const { name: itemName } = core.material.items[id as AllIdsOf<'items'>];
|
||||
core.status.route.push(name);
|
||||
tipAndWait(`购买物品:${itemName}`, 1000).then(() => {
|
||||
core.replay();
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
core.registerReplayAction('closeShop', name => {
|
||||
if (name !== 'closeShop') return false;
|
||||
shopOpened = false;
|
||||
openedShopId = '';
|
||||
core.status.route.push(name);
|
||||
core.replay();
|
||||
return true;
|
||||
});
|
||||
|
||||
core.registerReplayAction('fly', action => {
|
||||
if (!action.startsWith('fly:')) return false;
|
||||
const floorId = action.slice(4) as FloorIds;
|
||||
if (
|
||||
!core.canUseItem('fly') ||
|
||||
(core.flags.flyNearStair && !core.nearStair())
|
||||
)
|
||||
return false;
|
||||
tipAndWait(`飞往:${floorId}`, 1000).then(() => {
|
||||
if (!core.flyTo(floorId, core.replay)) {
|
||||
core.control._replay_error(action);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -1,199 +0,0 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { state } from '@user/data-state';
|
||||
|
||||
type Shop = CommonShopEvent | CommonEventShopEvent | ItemShopEvent;
|
||||
|
||||
export function openShop(shopId: string, noRoute: boolean) {
|
||||
const shop = core.status.shops[shopId] as Shop;
|
||||
// Step 1: 检查能否打开此商店
|
||||
if (!canOpenShop(shopId)) {
|
||||
core.drawTip('该商店尚未开启');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!noRoute) {
|
||||
core.status.route.push(`openShop:${shopId}`);
|
||||
}
|
||||
|
||||
// Step2: 检查公共事件商店
|
||||
if (shop.commonEvent) {
|
||||
core.insertCommonEvent(shop.commonEvent, shop.args);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 3: 检查道具商店
|
||||
if (shop.item) {
|
||||
Mota.r(() => {
|
||||
if (!core.isReplaying()) {
|
||||
Mota.require('@motajs/legacy-ui').mainUi.open('shop', {
|
||||
shopId: shopId
|
||||
});
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Step4 普通商店
|
||||
core.insertAction(convertShop(shop));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 是否访问过某个快捷商店
|
||||
export function isShopVisited(id: string) {
|
||||
flags.__shops__ ??= {};
|
||||
const shops = state.flags.getFieldValue('__shops__');
|
||||
if (!shops[id]) shops[id] = {};
|
||||
return shops[id].visited;
|
||||
}
|
||||
|
||||
/// 当前应当显示的快捷商店列表
|
||||
export function listShopIds() {
|
||||
return Object.keys(core.status.shops).filter(id => {
|
||||
// @ts-expect-error 无法推导
|
||||
return isShopVisited(id) || !core.status.shops[id].mustEnable;
|
||||
});
|
||||
}
|
||||
|
||||
/// 是否能够打开某个商店
|
||||
export function canOpenShop(id: string) {
|
||||
if (isShopVisited(id)) return true;
|
||||
const shop = core.status.shops[id];
|
||||
// @ts-expect-error 无法推导
|
||||
if (shop.item || shop.commonEvent || shop.mustEnable) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 启用或禁用某个快捷商店
|
||||
export function setShopVisited(id: string, visited: boolean) {
|
||||
if (!core.hasFlag('__shops__')) core.setFlag('__shops__', {});
|
||||
const shops = state.flags.getFieldValue('__shops__');
|
||||
if (!shops[id]) shops[id] = {};
|
||||
if (visited) shops[id].visited = true;
|
||||
else delete shops[id].visited;
|
||||
}
|
||||
|
||||
/// 能否使用快捷商店
|
||||
export function canUseQuickShop() {
|
||||
// 如果返回一个字符串,表示不能,字符串为不能使用的提示
|
||||
// 返回null代表可以使用
|
||||
|
||||
// 检查当前楼层的canUseQuickShop选项是否为false
|
||||
if (core.status.thisMap.canUseQuickShop === false)
|
||||
return '当前楼层不能使用快捷商店。';
|
||||
return null;
|
||||
}
|
||||
|
||||
////// 将一个全局商店转变成可预览的公共事件 //////
|
||||
function convertShop(shop): MotaEvent {
|
||||
return [
|
||||
{
|
||||
type: 'function',
|
||||
function: "function() {core.addFlag('@temp@shop', 1);}"
|
||||
},
|
||||
{
|
||||
type: 'while',
|
||||
condition: 'true',
|
||||
data: [
|
||||
// 检测能否访问该商店
|
||||
{
|
||||
type: 'if',
|
||||
condition:
|
||||
"Mota.require('@user/legacy-plugin-data').isShopVisited('" +
|
||||
shop.id +
|
||||
"')",
|
||||
true: [
|
||||
// 可以访问,直接插入执行效果
|
||||
{
|
||||
type: 'function',
|
||||
function:
|
||||
"function() { Mota.require('@user/legacy-plugin-data').convertShop_replaceChoices('" +
|
||||
shop.id +
|
||||
"', false) }"
|
||||
}
|
||||
],
|
||||
false: [
|
||||
// 不能访问的情况下:检测能否预览
|
||||
{
|
||||
type: 'if',
|
||||
condition: shop.disablePreview,
|
||||
true: [
|
||||
// 不可预览,提示并退出
|
||||
{ type: 'playSound', name: '操作失败' },
|
||||
'当前无法访问该商店!',
|
||||
{ type: 'break' }
|
||||
],
|
||||
false: [
|
||||
// 可以预览:将商店全部内容进行替换
|
||||
{
|
||||
type: 'tip',
|
||||
text: '当前处于预览模式,不可购买'
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function:
|
||||
"function() { Mota.require('@user/legacy-plugin-data').convertShop_replaceChoices('" +
|
||||
shop.id +
|
||||
"', true) }"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: "function() {core.addFlag('@temp@shop', -1);}"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
export function convertShop_replaceChoices(shopId, previewMode) {
|
||||
const shop = core.status.shops[shopId];
|
||||
const choices = (shop.choices || [])
|
||||
.filter(function (choice) {
|
||||
if (choice.condition == null || choice.condition == '') return true;
|
||||
try {
|
||||
return core.calValue(choice.condition);
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.map(function (choice) {
|
||||
const ableToBuy = core.calValue(choice.need);
|
||||
return {
|
||||
text: choice.text,
|
||||
icon: choice.icon,
|
||||
color:
|
||||
ableToBuy && !previewMode
|
||||
? choice.color
|
||||
: [153, 153, 153, 1],
|
||||
action:
|
||||
ableToBuy && !previewMode
|
||||
? [{ type: 'playSound', name: '商店' }].concat(
|
||||
choice.action
|
||||
)
|
||||
: [
|
||||
{ type: 'playSound', name: '操作失败' },
|
||||
{
|
||||
type: 'tip',
|
||||
text: previewMode
|
||||
? '预览模式下不可购买'
|
||||
: '购买条件不足'
|
||||
}
|
||||
]
|
||||
};
|
||||
})
|
||||
.concat({
|
||||
text: '离开',
|
||||
action: [{ type: 'playSound', name: '取消' }, { type: 'break' }]
|
||||
});
|
||||
|
||||
let text = shop.text.trim();
|
||||
if (text.startsWith('[')) {
|
||||
const end = text.indexOf(']');
|
||||
text = text.slice(end + 1);
|
||||
}
|
||||
core.insertAction({ type: 'choices', text: text, choices: choices });
|
||||
}
|
||||
@ -276,9 +276,6 @@ importers:
|
||||
'@user/data-state':
|
||||
specifier: workspace:*
|
||||
version: link:../data-state
|
||||
'@user/legacy-plugin-data':
|
||||
specifier: workspace:*
|
||||
version: link:../legacy-plugin-data
|
||||
|
||||
packages-user/data-base:
|
||||
dependencies:
|
||||
@ -411,9 +408,6 @@ importers:
|
||||
'@user/data-system':
|
||||
specifier: workspace:*
|
||||
version: link:../data-system
|
||||
'@user/legacy-plugin-data':
|
||||
specifier: workspace:*
|
||||
version: link:../legacy-plugin-data
|
||||
|
||||
packages-user/legacy-plugin-client:
|
||||
dependencies:
|
||||
@ -424,15 +418,6 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../data-state
|
||||
|
||||
packages-user/legacy-plugin-data:
|
||||
dependencies:
|
||||
'@user/data-base':
|
||||
specifier: workspace:*
|
||||
version: link:../data-base
|
||||
'@user/data-state':
|
||||
specifier: workspace:*
|
||||
version: link:../data-state
|
||||
|
||||
packages/animate: {}
|
||||
|
||||
packages/anon-tokyo: {}
|
||||
|
||||
@ -3559,7 +3559,7 @@ isShopVisited_e
|
||||
/* isShopVisited_e
|
||||
default : ['shop1']
|
||||
allShops : ['IdString_0']
|
||||
var code = 'Mota.require("@user/legacy-plugin-data").isShopVisited(\'' + IdString_0 + '\')';
|
||||
var code = 'false';
|
||||
return [code, Blockly.JavaScript.ORDER_ATOMIC];
|
||||
*/;
|
||||
|
||||
|
||||
@ -1294,34 +1294,7 @@ actions.prototype._keyUpViewMaps = function (keycode) {
|
||||
|
||||
////// 快捷商店界面时的点击操作 //////
|
||||
actions.prototype._clickQuickShop = function (x, y) {
|
||||
const shop = Mota.require('@user/legacy-plugin-data');
|
||||
var shopIds = shop.listShopIds();
|
||||
if (this._out(x)) return;
|
||||
var topIndex =
|
||||
this._HY_ -
|
||||
Math.floor(shopIds.length / 2) +
|
||||
(core.status.event.ui.offset || 0);
|
||||
if (y >= topIndex && y < topIndex + shopIds.length) {
|
||||
var shopId = shopIds[y - topIndex];
|
||||
if (!shop.canOpenShop(shopId)) {
|
||||
core.playSound('操作失败');
|
||||
core.drawTip('当前项尚未开启');
|
||||
return;
|
||||
}
|
||||
var message = shop.canUseQuickShop(shopId);
|
||||
if (message == null) {
|
||||
// core.ui.closePanel();
|
||||
shop.openShop(shopIds[y - topIndex], false);
|
||||
} else {
|
||||
core.playSound('操作失败');
|
||||
core.drawTip(message);
|
||||
}
|
||||
}
|
||||
// 离开
|
||||
else if (y == topIndex + shopIds.length) {
|
||||
core.playSound('取消');
|
||||
core.ui.closePanel();
|
||||
}
|
||||
// Deprecated.
|
||||
};
|
||||
|
||||
////// 快捷商店界面时,放开某个键的操作 //////
|
||||
|
||||
@ -2304,14 +2304,12 @@ events.prototype._action_unloadEquip = function (data, x, y, prefix) {
|
||||
};
|
||||
|
||||
events.prototype._action_openShop = function (data, x, y, prefix) {
|
||||
Mota.require('@user/legacy-plugin-data').setShopVisited(data.id, true);
|
||||
if (data.open)
|
||||
Mota.require('@user/legacy-plugin-data').openShop(data.id, true);
|
||||
// Deprecated.
|
||||
core.doAction();
|
||||
};
|
||||
|
||||
events.prototype._action_disableShop = function (data, x, y, prefix) {
|
||||
Mota.require('@user/legacy-plugin-data').setShopVisited(data.id, false);
|
||||
// Deprecated.
|
||||
core.doAction();
|
||||
};
|
||||
|
||||
@ -3392,36 +3390,7 @@ events.prototype.openToolbox = function (fromUserAction) {
|
||||
|
||||
////// 点击快捷商店按钮时的打开操作 //////
|
||||
events.prototype.openQuickShop = function (fromUserAction) {
|
||||
if (core.isReplaying()) return;
|
||||
const shop = Mota.require('@user/legacy-plugin-data');
|
||||
|
||||
if (Object.keys(core.status.shops).length == 0) {
|
||||
core.playSound('操作失败');
|
||||
core.drawTip('本游戏没有快捷商店!');
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 如果只有一个商店,则直接打开之
|
||||
if (Object.keys(core.status.shops).length == 1) {
|
||||
var shopId = Object.keys(core.status.shops)[0];
|
||||
if (core.status.event.id != null) return;
|
||||
if (!shop.canOpenShop(shopId)) {
|
||||
core.playSound('操作失败');
|
||||
core.drawTip('当前无法打开快捷商店!');
|
||||
return;
|
||||
}
|
||||
var message = shop.canUseQuickShop(shopId);
|
||||
if (message != null) {
|
||||
core.playSound('操作失败');
|
||||
core.drawTip(message);
|
||||
return;
|
||||
}
|
||||
shop.openShop(shopId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._checkStatus('selectShop', fromUserAction)) return;
|
||||
core.ui._drawQuickShop();
|
||||
// Deprecated.
|
||||
};
|
||||
|
||||
events.prototype.openKeyBoard = function (fromUserAction) {
|
||||
|
||||
@ -2367,18 +2367,7 @@ ui.prototype._drawNotes = function () {
|
||||
|
||||
////// 绘制快捷商店选择栏 //////
|
||||
ui.prototype._drawQuickShop = function () {
|
||||
const shop = Mota.require('@user/legacy-plugin-data');
|
||||
core.status.event.id = 'selectShop';
|
||||
var shopList = core.status.shops,
|
||||
keys = shop.listShopIds();
|
||||
var choices = keys.map(function (shopId) {
|
||||
return {
|
||||
text: shopList[shopId].textInList,
|
||||
color: shop.isShopVisited(shopId) ? null : '#999999'
|
||||
};
|
||||
});
|
||||
choices.push('返回游戏');
|
||||
this.drawChoices2(null, choices, void 0, true);
|
||||
// Deprecated.
|
||||
};
|
||||
|
||||
ui.prototype._drawSyncSave = function () {
|
||||
|
||||
@ -131,9 +131,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
||||
);
|
||||
}
|
||||
|
||||
// 根据分区信息自动砍层与恢复
|
||||
Mota.require('@user/legacy-plugin-data')?.autoRemoveMaps?.(floorId);
|
||||
|
||||
// ---------- 重绘新地图;这一步将会设置core.status.floorId ---------- //
|
||||
core.drawMap(floorId);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user