refactor: 删除 legacy-plugin-data

This commit is contained in:
unanmed 2026-09-17 18:21:35 +08:00
parent 7e4418362b
commit 10755475a4
21 changed files with 30 additions and 1371 deletions

View File

@ -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 {

View File

@ -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:*"
}
}

View File

@ -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',

View File

@ -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>;
}

View File

@ -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());

View File

@ -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:*"
}
}

View File

@ -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();
}

View File

@ -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;

View File

@ -1,7 +0,0 @@
{
"name": "@user/legacy-plugin-data",
"dependencies": {
"@user/data-state": "workspace:*",
"@user/data-base": "workspace:*"
}
}

View File

@ -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;
}
});
});
}

View File

@ -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)
};
};
}

View File

@ -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();
});
}

View File

@ -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';

View File

@ -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;
});
}

View File

@ -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 });
}

View File

@ -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: {}

View File

@ -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];
*/;

View File

@ -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.
};
////// 快捷商店界面时,放开某个键的操作 //////

View File

@ -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) {

View File

@ -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 () {

View File

@ -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);