From 053de036ec1207cb12539bdfb3fedb0c21e4d0c6 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Mon, 26 Aug 2024 22:47:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=80=E5=85=B3=E9=97=A8=E5=8A=A8?= =?UTF-8?q?=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/index.ts | 4 +- src/core/render/preset/floor.ts | 106 +++++++++++++++++++++++-- src/plugin/game/fallback.ts | 135 ++++++++++++++++++++++++++++++++ src/types/core.d.ts | 2 +- src/types/map.d.ts | 2 + src/types/status.d.ts | 2 +- 6 files changed, 241 insertions(+), 10 deletions(-) diff --git a/src/core/render/index.ts b/src/core/render/index.ts index caef4d0..4749343 100644 --- a/src/core/render/index.ts +++ b/src/core/render/index.ts @@ -1,6 +1,6 @@ import { FloorItemDetail } from '@/plugin/fx/itemDetail'; import { FloorDamageExtends } from './preset/damage'; -import { LayerGroupFloorBinder } from './preset/floor'; +import { LayerDoorAnimate, LayerGroupFloorBinder } from './preset/floor'; import { HeroRenderer } from './preset/hero'; import { LayerGroup, FloorLayer } from './preset/layer'; import { MotaRenderer } from './render'; @@ -26,9 +26,11 @@ Mota.require('var', 'loading').once('loaded', () => { const damage = new FloorDamageExtends(); const hero = new HeroRenderer(); const detail = new FloorItemDetail(); + const door = new LayerDoorAnimate(); layer.extends(damage); layer.extends(detail); layer.getLayer('event')?.extends(hero); + layer.getLayer('event')?.extends(door); render.appendChild(layer); }); diff --git a/src/core/render/preset/floor.ts b/src/core/render/preset/floor.ts index 044127f..396f70d 100644 --- a/src/core/render/preset/floor.ts +++ b/src/core/render/preset/floor.ts @@ -4,9 +4,12 @@ import { ILayerGroupRenderExtends, ILayerRenderExtends, Layer, - LayerGroup + LayerGroup, + LayerMovingRenderable } from './layer'; import { texture } from '../cache'; +import { sleep } from 'mutate-animate'; +import { RenderAdapter } from '../adapter'; const hook = Mota.require('var', 'hook'); @@ -281,16 +284,105 @@ export class LayerFloorBinder implements ILayerRenderExtends { } } -export class LayerOpenDoorAnimate implements ILayerRenderExtends { - id: string = 'open-door-animate'; +interface DoorAnimateRenderable { + renderable: LayerMovingRenderable; + count: number; + perTime: number; +} + +export class LayerDoorAnimate implements ILayerRenderExtends { + id: string = 'door-animate'; layer!: Layer; - awake(layer: Layer) { - this.layer = layer; + private moving: Set = new Set(); + + private getRenderable(block: Block): DoorAnimateRenderable | null { + const { x, y, id } = block; + const renderable = texture.getRenderable(id); + if (!renderable) return null; + const image = renderable.autotile + ? renderable.image[0] + : renderable.image; + const time = block.event.doorInfo?.time ?? 160; + const frame = renderable.render.length; + const perTime = time / frame; + + const data: LayerMovingRenderable = { + x, + y, + zIndex: y, + image, + autotile: false, + animate: 0, + frame, + bigImage: false, + render: renderable.render + }; + return { renderable: data, count: frame, perTime }; } - openDoor(x: number, y: number) {} + /** + * 开门 + * @param block 图块信息 + */ + async openDoor(block: Block) { + const renderable = this.getRenderable(block); + if (!renderable) return Promise.reject(); + const { renderable: data, count: frame, perTime } = renderable; + data.animate = 0; + this.moving.add(data); - closeDoor(x: number, y: number) {} + let now = 0; + while (now < frame) { + await sleep(perTime); + data.animate = ++now; + this.layer.update(this.layer); + } + + this.moving.delete(data); + return Promise.resolve(); + } + + /** + * 关门 + * @param block 图块信息 + */ + async closeDoor(block: Block) { + const renderable = this.getRenderable(block); + if (!renderable) return Promise.reject(); + const { renderable: data, count: frame, perTime } = renderable; + data.animate = frame - 1; + this.moving.add(data); + + let now = 0; + while (now >= 0) { + await sleep(perTime); + data.animate = --now; + this.layer.update(this.layer); + } + this.moving.delete(data); + return Promise.resolve(); + } + + awake(layer: Layer) { + this.layer = layer; + doorAdapter.add(this); + } + + onMovingUpdate(layer: Layer, renderable: LayerMovingRenderable[]): void { + renderable.push(...this.moving); + } + + onDestroy(layer: Layer): void { + doorAdapter.remove(this); + } } + +const doorAdapter = new RenderAdapter('door-animate'); +doorAdapter.recieve('openDoor', (item, block: Block) => { + return item.openDoor(block); +}); +doorAdapter.recieve('closeDoor', (item, block: Block) => { + return item.closeDoor(block); +}); diff --git a/src/plugin/game/fallback.ts b/src/plugin/game/fallback.ts index 50a637a..f187180 100644 --- a/src/plugin/game/fallback.ts +++ b/src/plugin/game/fallback.ts @@ -1,19 +1,26 @@ import type { RenderAdapter } from '@/core/render/adapter'; +import type { LayerDoorAnimate } from '@/core/render/preset/floor'; import type { HeroRenderer } from '@/core/render/preset/hero'; import { hook } from '@/game/game'; interface Adapters { 'hero-adapter'?: RenderAdapter; + 'door-animate'?: RenderAdapter; } const adapters: Adapters = {}; export function init() { + const hook = Mota.require('var', 'hook'); + let fallbackIds: number = 1e8; + if (!main.replayChecking && main.mode === 'play') { const Adapter = Mota.require('module', 'Render').RenderAdapter; const hero = Adapter.get('hero-adapter'); + const doorAnimate = Adapter.get('door-animate'); adapters['hero-adapter'] = hero; + adapters['door-animate'] = doorAnimate; } let moving: boolean = false; @@ -280,6 +287,134 @@ export function init() { moveDir = core.status.hero.loc.direction; stepDir = moveDir; }); + + // ----- 开关门 + events.prototype.openDoor = function ( + x: number, + y: number, + needKey: boolean, + callback?: () => void + ) { + var block = core.getBlock(x, y); + core.saveAndStopAutomaticRoute(); + if (!this._openDoor_check(block, x, y, needKey)) { + var 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; + Mota.require('var', 'hook').emit( + 'afterOpenDoor', + block.event.id, + x, + y + ); + if (callback) callback(); + }, 1); // +1是为了录像检测系统 + } else { + const locked = core.status.lockControl; + core.lockControl(); + core.status.replay.animate = true; + core.removeBlock(x, y); + + const cb = () => { + core.maps._removeBlockFromMap(core.status.floorId, block); + if (!locked) core.unlockControl(); + core.status.replay.animate = false; + hook.emit('afterOpenDoor', block.event.id, x, y); + callback?.(); + }; + + adapters['door-animate']?.all('openDoor', block).then(cb); + + const animate = fallbackIds++; + core.animateFrame.lastAsyncId = animate; + core.animateFrame.asyncId[animate] = cb; + this._openDoor_animate(block, x, y, callback); + } + }; + + events.prototype.closeDoor = function ( + x: number, + y: number, + id: AllIds, + callback?: () => void + ) { + id = id || ''; + if ( + // @ts-ignore + (core.material.icons.animates[id] == null && + // @ts-ignore + core.material.icons.npc48[id] == null) || + core.getBlock(x, y) != null + ) { + if (callback) callback(); + return; + } + var block = core.getBlockById(id); + var 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 { + adapters['door-animate']?.all('closeDoor', block).then(() => { + cb(); + }); + + const animate = fallbackIds++; + core.animateFrame.lastAsyncId = animate; + core.animateFrame.asyncId[animate] = cb; + this._openDoor_animate(block, x, y, callback); + } + + // var blockInfo = core.getBlockInfo(block); + // var speed = (doorInfo.time || 160) / 4; + // blockInfo.posX = 3; + // core.maps._drawBlockInfo(blockInfo, x, y); + + // var animate = window.setInterval( + // function () { + // blockInfo.posX--; + // if (blockInfo.posX < 0) { + // clearInterval(animate); + // delete core.animateFrame.asyncId[animate]; + // cb(); + // return; + // } + // core.maps._drawBlockInfo(blockInfo, x, y); + // }, + // core.status.replay.speed == 24 + // ? 1 + // : speed / Math.max(core.status.replay.speed, 1) + // ); + + // core.animateFrame.lastAsyncId = animate; + // core.animateFrame.asyncId[animate] = cb; + }; }); return { readyMove, endMove, move }; diff --git a/src/types/core.d.ts b/src/types/core.d.ts index f296127..8b595a4 100644 --- a/src/types/core.d.ts +++ b/src/types/core.d.ts @@ -275,7 +275,7 @@ interface AnimateFrame { /** * 上一个异步事件的id */ - readonly lastAsyncId: number; + lastAsyncId: number; } interface Weather { diff --git a/src/types/map.d.ts b/src/types/map.d.ts index 126605f..5f58f0d 100644 --- a/src/types/map.d.ts +++ b/src/types/map.d.ts @@ -1403,6 +1403,8 @@ interface Maps { floorId: FloorIds, noCache?: boolean ): number[][]; + + _removeBlockFromMap(floorId: FloorIds, block: Block): void; } declare const maps: new () => Maps; diff --git a/src/types/status.d.ts b/src/types/status.d.ts index 64951a6..4f9cb66 100644 --- a/src/types/status.d.ts +++ b/src/types/status.d.ts @@ -661,7 +661,7 @@ interface InitGameStatus { /** * 当前的回放状态 */ - replay: DeepReadonly; + replay: ReplayStatus; /** * 当前的所有全局商店