mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-04-25 00:23:25 +08:00
Compare commits
6 Commits
cca10a429c
...
05e254fee0
Author | SHA1 | Date | |
---|---|---|---|
05e254fee0 | |||
5c520e3d52 | |||
74f0386fd9 | |||
23a8c0bf3a | |||
4fda246a9a | |||
0679bbb1a5 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -49,4 +49,5 @@ script/people.ts
|
|||||||
user.ts
|
user.ts
|
||||||
.antlr
|
.antlr
|
||||||
graph.svg
|
graph.svg
|
||||||
docs/.vitepress
|
docs/.vitepress/cache
|
||||||
|
docs/.vitepress/dist
|
||||||
|
59
docs/.vitepress/config.ts
Normal file
59
docs/.vitepress/config.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { defineConfig } from 'vitepress';
|
||||||
|
|
||||||
|
// https://vitepress.dev/reference/site-config
|
||||||
|
export default defineConfig({
|
||||||
|
title: 'HTML5 魔塔样板 V2.B',
|
||||||
|
description: 'HTML5 魔塔样板 V2.B 帮助文档',
|
||||||
|
base: '/_docs/',
|
||||||
|
themeConfig: {
|
||||||
|
// https://vitepress.dev/reference/default-theme-config
|
||||||
|
nav: [
|
||||||
|
{ text: '主页', link: '/' },
|
||||||
|
{ text: '指南', link: '/guide/diff' },
|
||||||
|
{ text: 'API', link: '/api/' }
|
||||||
|
],
|
||||||
|
sidebar: {
|
||||||
|
'/guide/': [
|
||||||
|
{
|
||||||
|
text: '深度指南',
|
||||||
|
items: [
|
||||||
|
{ text: '差异说明', link: '/guide/diff' },
|
||||||
|
{ text: '系统说明', link: '/guide/system' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
socialLinks: [
|
||||||
|
{ icon: 'github', link: 'https://github.com/unanmed/HumanBreak' }
|
||||||
|
],
|
||||||
|
search: {
|
||||||
|
provider: 'local',
|
||||||
|
options: {
|
||||||
|
locales: {
|
||||||
|
zh: {
|
||||||
|
translations: {
|
||||||
|
button: {
|
||||||
|
buttonText: '搜索文档',
|
||||||
|
buttonAriaLabel: '搜索文档'
|
||||||
|
},
|
||||||
|
modal: {
|
||||||
|
noResultsText: '无法找到相关结果',
|
||||||
|
resetButtonTitle: '清除查询条件',
|
||||||
|
footer: {
|
||||||
|
selectText: '选择',
|
||||||
|
navigateText: '切换'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locales: {
|
||||||
|
root: {
|
||||||
|
lang: 'zh',
|
||||||
|
label: '中文'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
5
docs/api/index.md
Normal file
5
docs/api/index.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
lang: zh-CN
|
||||||
|
---
|
||||||
|
|
||||||
|
# API 列表
|
34
docs/guide/diff.md
Normal file
34
docs/guide/diff.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
lang: zh-CN
|
||||||
|
---
|
||||||
|
|
||||||
|
# 差异说明
|
||||||
|
|
||||||
|
本文档暂时只会对新样板新增内容进行说明,其余请查看[旧样板文档](https://h5mota.com/games/template/_docs/#/)。
|
||||||
|
|
||||||
|
本指南建立在你已经大致了解 js 的基础语法的基础上。如果还不了解可以尝试对指南内容进行模仿,或者查看[人类塔解析](https://h5mota.com/bbs/thread/?tid=1018&p=1)
|
||||||
|
|
||||||
|
如果你有能力直接使用源码版样板进行创作,也可以直接 fork 或 clone 2.B 样板[存储库](https://github.com/unanmed/HumanBreak/tree/template-v2.B)。2.B 样板使用了 vite 作为了构建工具,同时使用了 ts 等作为了开发语言。
|
||||||
|
|
||||||
|
本文将描述 2.B 样板与 2.10.3 及 2.A 样板的差异。
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
对于新样板,由于拥有了近乎完整的类型标注,因此更推荐使用 `VS Code` 进行代码编写,这样你可以获取到完整的类型标注,而由于类型标注的复杂性,样板编辑器完全无法部署,因此样板编辑器不会有任何新版的类型标注。在之后的更新中,样板 API 会进行大幅度的改动,因此每次更新都可能会弃用一部分 API,同时这些 API 会在若干个版本后被彻底删除。因此如果你的代码中使用到了弃用的 API,请尽快更换写法以保证可以向后接档。
|
||||||
|
|
||||||
|
## 主要差异
|
||||||
|
|
||||||
|
- 开发语言换为 TypeScript,可以享受到完整的类型支持
|
||||||
|
- 使用全新的 UI 编写方式,速度快,效率高
|
||||||
|
- 模块化,可以使用 ES6 模块化语法
|
||||||
|
- 移除插件系统,可以自定义代码目录结构,更加自由
|
||||||
|
- 优化渲染端(client 端)与数据端(data 端)的通讯,渲染段现在可以直接引用数据端,不过数据端还不能直接引用渲染端
|
||||||
|
|
||||||
|
## 差异内容
|
||||||
|
|
||||||
|
相比于 2.10.3 及 2.A,有如下改动:
|
||||||
|
|
||||||
|
- [系统说明](./system)
|
||||||
|
- [UI 编写](./ui)
|
||||||
|
- [UI 系统](./ui-system)
|
||||||
|
- [音频系统](./audio)
|
157
docs/guide/system.md
Normal file
157
docs/guide/system.md
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
---
|
||||||
|
lang: zh-CN
|
||||||
|
---
|
||||||
|
|
||||||
|
# 系统说明
|
||||||
|
|
||||||
|
本文将介绍 2.B 的系统都做了哪些更改
|
||||||
|
|
||||||
|
## 模块化
|
||||||
|
|
||||||
|
2.B 样板现在已经迁移至了 monorepo,将代码模块化,共分为 20 余个模块,每个模块的具体内容可以参考 API 文档,模块列表如下:
|
||||||
|
|
||||||
|
- [@motajs/client](../api/motajs-client)
|
||||||
|
- [@motajs/client-base](../api/motajs-client-base)
|
||||||
|
- [@motajs/common](../api/motajs-common)
|
||||||
|
- [@motajs/legacy-client](../api/motajs-legacy-client)
|
||||||
|
- [@motajs/legacy-common](../api/motajs-legacy-common)
|
||||||
|
- [@motajs/legacy-data](../api/motajs-legacy-data)
|
||||||
|
- [@motajs/legacy-system](../api/motajs-legacy-system)
|
||||||
|
- [@motajs/legacy-ui](../api/motajs-legacy-ui)
|
||||||
|
- [@motajs/render](../api/motajs-render)
|
||||||
|
- [@motajs/render-core](../api/motajs-render-core)
|
||||||
|
- [@motajs/render-elements](../api/motajs-render-elements)
|
||||||
|
- [@motajs/render-style](../api/motajs-render-style)
|
||||||
|
- [@motajs/render-vue](../api/motajs-render-vue)
|
||||||
|
- [@motajs/system](../api/motajs-system)
|
||||||
|
- [@motajs/system-action](../api/motajs-system-action)
|
||||||
|
- [@motajs/system-ui](../api/motajs-system-ui)
|
||||||
|
- [@motajs/types](../api/types)
|
||||||
|
- [@user/client-modules](../api/user-client-modules)
|
||||||
|
- [@user/data-base](../api/user-data-base)
|
||||||
|
- [@user/data-fallback](../api/user-data-fallback)
|
||||||
|
- [@user/data-state](../api/user-data-state)
|
||||||
|
- [@user/data-utils](../api/user-data-utils)
|
||||||
|
- [@user/entry-client](../api/user-entry-client)
|
||||||
|
- [@user/entry-data](../api/user-entry-data)
|
||||||
|
- [@user/legacy-plugin-client](../api/user-legacy-plugin-client)
|
||||||
|
- [@user/legacy-plugin-data](../api/user-legacy-plugin-data)
|
||||||
|
|
||||||
|
## Mota 全局变量
|
||||||
|
|
||||||
|
与 2.A 不同,2.B 对 `Mota` 全局变量做了简化,不再拥有 `Mota.Plugin` `Mota.Package` `Mota.requireAll` 属性与方法,它们全部整合至了 `Mota.require` 方法中,同时该方法的用法与 2.A 也不同,在 2.A 中,我们往往使用 `Mota.require('var', 'xxx')` 的方式调用,繁琐且不直观。在 2.B 中,我们可以直接填入模块名称,就可以获取到其内容了,例如:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const { hook, loading } = Mota.require('@user/data-base'); // 获取 hook 与 loading
|
||||||
|
const { Font } = Mota.require('@motajs/render'); // 获取 Font 字体类
|
||||||
|
```
|
||||||
|
|
||||||
|
我们只需要填写一个参数,而不需要填写两个参数了,更加直观,而且与 ES6 模块语法类似,便于转换。
|
||||||
|
|
||||||
|
多数情况下,我们是不需要使用 `Mota` 全局变量的。不过,还是有一些特殊情况需要使用该全局变量才可以,这些情况包括:
|
||||||
|
|
||||||
|
- 在数据端调用渲染端接口,数据端需要跑录像验证,因此不能直接引入渲染端接口,需要通过此全局变量才可以。
|
||||||
|
- 在 `libs` `functions.js` 中调用接口,这两个地方暂时还没有模块化,因此无法直接引入,需要通过此全局变量调用。
|
||||||
|
|
||||||
|
## 渲染端与数据端通信
|
||||||
|
|
||||||
|
一般情况下,渲染端**可以**直接引入数据端的内容,例如你可以在 `@user/client-modules` 里面直接引入 `@user/data-state` 的接口,这是没有问题的。不过,由于数据端需要在服务器上跑录像验证,因此**不能**直接引入渲染端的内容,否则会导致验证报错。如果需要在数据端引用渲染端接口,我们需要这么做:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// @user/data-state 中的某文件
|
||||||
|
const num = 100;
|
||||||
|
Mota.r(() => {
|
||||||
|
// 使用 r 方法包裹,这样这个函数就会在渲染端运行,可以有返回值,但是在录像验证中只会是 undefined
|
||||||
|
const { Font } = Mota.require('@motajs/render');
|
||||||
|
const font = new Font('Verdana', 18);
|
||||||
|
// 函数内也可以调用外部变量,例如这里就调用了外部的 num 变量,但是极度不推荐在渲染端修改数据端的内容
|
||||||
|
// 否则很可能导致录像不能运行,这里这个例子就会导致录像运行出错,因为录像验证时并不会执行这段代码,
|
||||||
|
// 勇士的血量也就不会变大,于是就出错了。
|
||||||
|
core.status.hero.hp += num;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
除此之外,我们还可以使用钩子来进行数据通信。示例如下:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// 渲染端和数据端都可以使用这个方式引入
|
||||||
|
import { hook } from '@user/data-base';
|
||||||
|
// 也可以通过 Mota.require 方法引入
|
||||||
|
const { hook } = Mota.require('@user/data-base');
|
||||||
|
|
||||||
|
// 监听战后函数,每次与怪物战斗后,都会执行这个函数
|
||||||
|
// 每个钩子的参数定义可以参考 package-user/data-base/src/game.ts GameEvent 接口
|
||||||
|
hook.on('afterBattle', enemy => {
|
||||||
|
console.log('与怪物战斗:', enemy.id);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 加载流程
|
||||||
|
|
||||||
|
与 2.A 相比,加载流程也不太一样,下面是 2.B 的加载流程:
|
||||||
|
|
||||||
|
1. 加载 `index.html`
|
||||||
|
2. 加载 2.x 样板的第三方库
|
||||||
|
|
||||||
|
3. 如果是游戏中,加载 `src/main.ts`
|
||||||
|
|
||||||
|
1. 加载渲染端入口
|
||||||
|
2. 加载数据端入口
|
||||||
|
3. 并行初始化数据端,写入 `Mota` 全局变量
|
||||||
|
4. 初始化完毕后执行 `loading.emit('dataRegistered')` 钩子
|
||||||
|
5. 并行初始化渲染端
|
||||||
|
6. 初始化完毕后执行 `loading.emit('clientRegistered')` 钩子
|
||||||
|
7. 二者都初始化完毕后执行 `loading.emit('registered')` 钩子
|
||||||
|
8. 执行数据端各个模块的初始化函数
|
||||||
|
9. 执行渲染段各个模块的初始化函数
|
||||||
|
|
||||||
|
4. 如果是录像验证中:
|
||||||
|
|
||||||
|
1. 加载数据端入口
|
||||||
|
2. 初始化数据端,写入 `Mota` 全局变量
|
||||||
|
3. 初始化完毕后执行 `loading.emit('dataRegistered')` 与 `loading.emit('registered')` 钩子
|
||||||
|
4. 执行数据端各个模块的初始化函数
|
||||||
|
|
||||||
|
5. 执行 `main.js` 初始化
|
||||||
|
6. 加载全塔属性
|
||||||
|
7. 加载 `core.js` 及其他 `libs` 中的脚本
|
||||||
|
8. 加载完毕后执行 `loading.emit('coreInit')` 钩子
|
||||||
|
9. 开始资源加载
|
||||||
|
10. 自动元件加载完毕后执行 `loading.emit('autotileLoaded')` 钩子
|
||||||
|
11. 资源加载完毕后执行 `loading.emit('loaded')` 钩子
|
||||||
|
12. 进入标题界面
|
||||||
|
|
||||||
|
## 函数重写
|
||||||
|
|
||||||
|
在 2.B 模式下,如果想改 `libs` 的内容,如果直接在里面改会很麻烦,而且两端通讯也不方便,因此我们建议在 `package-user` 中对函数重写,这样的话就可以使用模块化语法,更加方便。同时,2.B 也提供了函数重写接口,他在 `@motajs/legacy-common` 模块中,我们可以这么使用它:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// 新建一个 ts 文件,例如叫做 override.ts,放在 client-modules 文件夹下
|
||||||
|
import { Patch, PatchClass } from '@motajs/legacy-common';
|
||||||
|
|
||||||
|
// 新建函数,这个操作是必要的,我们不能直接在顶层使用这个接口
|
||||||
|
export function patchMyFunctions() {
|
||||||
|
// 创建 Patch 实例,参数表示这个 Patch 示例要重写哪个文件中的函数
|
||||||
|
// 如果需要复写两个文件,那么就需要创建两个实例
|
||||||
|
const patch = new Patch(PatchClass.Control);
|
||||||
|
|
||||||
|
// 使用 add 函数来重写,第一个参数会有自动补全
|
||||||
|
// 如果要重写的函数以下划线开头,可能会有报错
|
||||||
|
// 这时候需要去 types/declaration 中对应的文件中添加声明
|
||||||
|
patch.add('getFlag', (name, defaultValue) => {
|
||||||
|
// 重写 getFlag,如果变量是数字,那么 +100 后返回
|
||||||
|
const value = core.status.?hero.?flags[name] ?? defaultValue;
|
||||||
|
return typeof value === 'number' ? value + 100 : value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
然后,我们找到 `client-modules` 文件夹下的 `index.ts` 文件,然后在 `create` 函数中调用 `patchMyFunctions`,这样我们的函数重写就完成了。
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
**注意**,在渲染端重写的函数在录像验证中将无效,因为录像验证不会执行任何渲染端内容!
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
我们建议每个文件夹中都有一个 `index.ts` 文件,将本文件夹中的其他文件经由此文件导出,这样方便管理,同时结构清晰。可以参考 `packages-user/client-modules` 文件夹中是如何做的。
|
0
docs/guide/ui-system.md
Normal file
0
docs/guide/ui-system.md
Normal file
0
docs/guide/ui.md
Normal file
0
docs/guide/ui.md
Normal file
@ -4,7 +4,7 @@ layout: home
|
|||||||
|
|
||||||
hero:
|
hero:
|
||||||
name: 'mota-js'
|
name: 'mota-js'
|
||||||
text: 'HTML5魔塔样板V2.A'
|
text: 'HTML5魔塔样板V2.B'
|
||||||
tagline: HTML5魔塔样板从 2.x 到 3.0 的过渡版本
|
tagline: HTML5魔塔样板从 2.x 到 3.0 的过渡版本
|
||||||
actions:
|
actions:
|
||||||
- theme: brand
|
- theme: brand
|
||||||
|
8
packages-user/client-modules/package.json
Normal file
8
packages-user/client-modules/package.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "@user/client-modules",
|
||||||
|
"dependencies": {
|
||||||
|
"@motajs/render": "workspace:*",
|
||||||
|
"@motajs/legacy-ui": "workspace:*",
|
||||||
|
"@user/legacy-plugin-client": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
1
packages-user/client-modules/src/action/index.ts
Normal file
1
packages-user/client-modules/src/action/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './move';
|
@ -258,7 +258,7 @@ export class BgmController<
|
|||||||
export const bgmController = new BgmController<BgmIds>(audioPlayer);
|
export const bgmController = new BgmController<BgmIds>(audioPlayer);
|
||||||
|
|
||||||
export function loadAllBgm() {
|
export function loadAllBgm() {
|
||||||
const loading = Mota.require('var', 'loading');
|
const { loading } = Mota.require('@user/data-base');
|
||||||
loading.once('coreInit', () => {
|
loading.once('coreInit', () => {
|
||||||
const data = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d;
|
const data = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d;
|
||||||
for (const bgm of data.main.bgms) {
|
for (const bgm of data.main.bgms) {
|
@ -3,9 +3,11 @@ import { OpusDecoder, VorbisDecoder } from './decoder';
|
|||||||
import { AudioType } from './support';
|
import { AudioType } from './support';
|
||||||
import { AudioDecoder } from './decoder';
|
import { AudioDecoder } from './decoder';
|
||||||
|
|
||||||
loadAllBgm();
|
export function createAudio() {
|
||||||
AudioDecoder.registerDecoder(AudioType.Ogg, VorbisDecoder);
|
loadAllBgm();
|
||||||
AudioDecoder.registerDecoder(AudioType.Opus, OpusDecoder);
|
AudioDecoder.registerDecoder(AudioType.Ogg, VorbisDecoder);
|
||||||
|
AudioDecoder.registerDecoder(AudioType.Opus, OpusDecoder);
|
||||||
|
}
|
||||||
|
|
||||||
export * from './support';
|
export * from './support';
|
||||||
export * from './effect';
|
export * from './effect';
|
@ -51,5 +51,3 @@ isAudioSupport(AudioType.Wav);
|
|||||||
isAudioSupport(AudioType.Flac);
|
isAudioSupport(AudioType.Flac);
|
||||||
isAudioSupport(AudioType.Opus);
|
isAudioSupport(AudioType.Opus);
|
||||||
isAudioSupport(AudioType.Aac);
|
isAudioSupport(AudioType.Aac);
|
||||||
|
|
||||||
console.log(supportMap);
|
|
@ -1,4 +1,3 @@
|
|||||||
import { Patch } from '@motajs/legacy-common';
|
|
||||||
import { patchAudio } from './audio';
|
import { patchAudio } from './audio';
|
||||||
import { patchWeather } from './weather';
|
import { patchWeather } from './weather';
|
||||||
import { patchUI } from './ui';
|
import { patchUI } from './ui';
|
||||||
@ -7,8 +6,4 @@ export function patchAll() {
|
|||||||
patchAudio();
|
patchAudio();
|
||||||
patchWeather();
|
patchWeather();
|
||||||
patchUI();
|
patchUI();
|
||||||
const loading = Mota.require('var', 'loading');
|
|
||||||
loading.once('coreInit', () => {
|
|
||||||
Patch.patchAll();
|
|
||||||
});
|
|
||||||
}
|
}
|
20
packages-user/client-modules/src/index.ts
Normal file
20
packages-user/client-modules/src/index.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { loading } from '@user/data-base';
|
||||||
|
import { createAudio } from './audio';
|
||||||
|
import { patchAll } from './fallback';
|
||||||
|
import { createGameRenderer, createRender } from './render';
|
||||||
|
|
||||||
|
export function create() {
|
||||||
|
createAudio();
|
||||||
|
patchAll();
|
||||||
|
createRender();
|
||||||
|
loading.once('coreInit', () => {
|
||||||
|
createGameRenderer();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export * from './action';
|
||||||
|
export * from './weather';
|
||||||
|
export * from './audio';
|
||||||
|
export * from './loader';
|
||||||
|
export * from './fallback';
|
||||||
|
export * from './render';
|
@ -8,17 +8,19 @@ import {
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { LayerGroupFloorBinder } from './floor';
|
|
||||||
import {
|
import {
|
||||||
|
BlockCacher,
|
||||||
|
CanvasCacheItem,
|
||||||
|
ICanvasCacheItem,
|
||||||
calNeedRenderOf,
|
calNeedRenderOf,
|
||||||
ILayerGroupRenderExtends,
|
ILayerGroupRenderExtends,
|
||||||
Layer,
|
Layer,
|
||||||
LayerGroup
|
LayerGroup,
|
||||||
} from './layer';
|
LayerGroupFloorBinder,
|
||||||
import { BlockCacher, CanvasCacheItem, ICanvasCacheItem } from './block';
|
tagMap
|
||||||
|
} from '@motajs/render';
|
||||||
import { IDamageEnemy, IEnemyCollection, MapDamage } from '@motajs/types';
|
import { IDamageEnemy, IEnemyCollection, MapDamage } from '@motajs/types';
|
||||||
|
import { UserEnemyInfo } from '@user/data-state';
|
||||||
const ensureFloorDamage = Mota.require('fn', 'ensureFloorDamage');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据伤害大小获取颜色
|
* 根据伤害大小获取颜色
|
||||||
@ -55,6 +57,7 @@ export class FloorDamageExtends
|
|||||||
if (!this.sprite || !floor) return;
|
if (!this.sprite || !floor) return;
|
||||||
const map = core.status.maps[floor];
|
const map = core.status.maps[floor];
|
||||||
this.sprite.setMapSize(map.width, map.height);
|
this.sprite.setMapSize(map.width, map.height);
|
||||||
|
const { ensureFloorDamage } = Mota.require('@user/data-state');
|
||||||
ensureFloorDamage(floor);
|
ensureFloorDamage(floor);
|
||||||
const enemy = core.status.maps[floor].enemy;
|
const enemy = core.status.maps[floor].enemy;
|
||||||
|
|
||||||
@ -75,6 +78,7 @@ export class FloorDamageExtends
|
|||||||
|
|
||||||
private onUpdate = (floor: FloorIds) => {
|
private onUpdate = (floor: FloorIds) => {
|
||||||
if (!this.floorBinder.bindThisFloor) {
|
if (!this.floorBinder.bindThisFloor) {
|
||||||
|
const { ensureFloorDamage } = Mota.require('@user/data-state');
|
||||||
ensureFloorDamage(floor);
|
ensureFloorDamage(floor);
|
||||||
core.status.maps[floor].enemy.calRealAttribute();
|
core.status.maps[floor].enemy.calRealAttribute();
|
||||||
}
|
}
|
||||||
@ -323,7 +327,7 @@ export class Damage extends RenderItem<EDamageEvent> {
|
|||||||
const y = enemy.y!;
|
const y = enemy.y!;
|
||||||
const { damage } = enemy.calDamage();
|
const { damage } = enemy.calDamage();
|
||||||
const cri = enemy.calCritical(1)[0]?.atkDelta ?? Infinity;
|
const cri = enemy.calCritical(1)[0]?.atkDelta ?? Infinity;
|
||||||
const real = enemy.getRealInfo();
|
const real = enemy.getRealInfo() as UserEnemyInfo;
|
||||||
|
|
||||||
const dam1: DamageRenderable = {
|
const dam1: DamageRenderable = {
|
||||||
align: 'left',
|
align: 'left',
|
||||||
@ -587,4 +591,9 @@ export class Damage extends RenderItem<EDamageEvent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注册为内部元素
|
||||||
|
tagMap.register<EDamageEvent, Damage>('damage', (_0, _1, _props) => {
|
||||||
|
return new Damage();
|
||||||
|
});
|
||||||
|
|
||||||
// const adapter = new RenderAdapter<Damage>('damage');
|
// const adapter = new RenderAdapter<Damage>('damage');
|
@ -3,9 +3,12 @@ import { defineComponent } from 'vue';
|
|||||||
import { UIController } from '@motajs/system-ui';
|
import { UIController } from '@motajs/system-ui';
|
||||||
import { mainSceneUI } from './ui/main';
|
import { mainSceneUI } from './ui/main';
|
||||||
import { MAIN_HEIGHT, MAIN_WIDTH } from './shared';
|
import { MAIN_HEIGHT, MAIN_WIDTH } from './shared';
|
||||||
import { TextboxStore } from './components';
|
import { hook } from '@user/data-base';
|
||||||
|
import { createItemDetail } from './itemDetail';
|
||||||
|
import { createLoopMap } from './loopMap';
|
||||||
|
import { createGameCanvas } from './legacy/gameCanvas';
|
||||||
|
|
||||||
export function create() {
|
export function createGameRenderer() {
|
||||||
const main = new MotaRenderer();
|
const main = new MotaRenderer();
|
||||||
main.size(MAIN_WIDTH, MAIN_HEIGHT);
|
main.size(MAIN_WIDTH, MAIN_HEIGHT);
|
||||||
|
|
||||||
@ -23,20 +26,22 @@ export function create() {
|
|||||||
main.hide();
|
main.hide();
|
||||||
createApp(App).mount(main);
|
createApp(App).mount(main);
|
||||||
|
|
||||||
Mota.require('var', 'hook').on('reset', () => {
|
hook.on('reset', () => {
|
||||||
main.show();
|
main.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
Mota.require('var', 'hook').on('restart', () => {
|
hook.on('restart', () => {
|
||||||
main.hide();
|
main.hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(main);
|
console.log(main);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mota.register('module', 'MainUI', {
|
export function createRender() {
|
||||||
TextboxStore
|
createGameCanvas();
|
||||||
});
|
createItemDetail();
|
||||||
|
createLoopMap();
|
||||||
|
}
|
||||||
|
|
||||||
export * from './components';
|
export * from './components';
|
||||||
export * from './ui';
|
export * from './ui';
|
@ -1,13 +1,13 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { mainSetting } from '@motajs/legacy-ui';
|
import { mainSetting } from '@motajs/legacy-ui';
|
||||||
import {
|
import {
|
||||||
Damage,
|
|
||||||
DamageRenderable,
|
|
||||||
FloorDamageExtends,
|
|
||||||
LayerGroupFloorBinder,
|
LayerGroupFloorBinder,
|
||||||
ILayerGroupRenderExtends,
|
ILayerGroupRenderExtends,
|
||||||
LayerGroup
|
LayerGroup
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
|
import { hook } from '@user/data-base';
|
||||||
|
import { ItemState } from '@user/data-state';
|
||||||
|
import { Damage, DamageRenderable, FloorDamageExtends } from './damage';
|
||||||
|
|
||||||
interface ItemDetailData {
|
interface ItemDetailData {
|
||||||
x: number;
|
x: number;
|
||||||
@ -21,12 +21,13 @@ interface ItemData {
|
|||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemState = Mota.require('module', 'State').ItemState;
|
export function createItemDetail() {
|
||||||
Mota.require('var', 'hook').on('setBlock', (x, y, floorId, block) => {
|
hook.on('setBlock', (x, y, floorId, block) => {
|
||||||
FloorItemDetail.listened.forEach(v => {
|
FloorItemDetail.listened.forEach(v => {
|
||||||
v.setBlock(block, x, y);
|
v.setBlock(block, x, y);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
export class FloorItemDetail implements ILayerGroupRenderExtends {
|
export class FloorItemDetail implements ILayerGroupRenderExtends {
|
||||||
id: string = 'item-detail';
|
id: string = 'item-detail';
|
||||||
@ -199,8 +200,7 @@ export class FloorItemDetail implements ILayerGroupRenderExtends {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
ItemState.item(id)?.itemEffectFn?.();
|
||||||
ItemState.item(id)?.itemEffectFn();
|
|
||||||
detail?.set(index, { x, y, diff });
|
detail?.set(index, { x, y, diff });
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -4,6 +4,7 @@ import {
|
|||||||
ILayerGroupRenderExtends,
|
ILayerGroupRenderExtends,
|
||||||
LayerGroup
|
LayerGroup
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
|
import { loading } from '@user/data-base';
|
||||||
|
|
||||||
const filterMap: [FloorIds[], string][] = [];
|
const filterMap: [FloorIds[], string][] = [];
|
||||||
|
|
||||||
@ -11,15 +12,19 @@ function getCanvasFilterByFloorId(floorId: FloorIds = core.status.floorId) {
|
|||||||
return filterMap.find(v => v[0].includes(floorId))?.[1] ?? '';
|
return filterMap.find(v => v[0].includes(floorId))?.[1] ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('coreInit', () => {
|
export function createGameCanvas() {
|
||||||
filterMap.push(
|
loading.once('coreInit', () => {
|
||||||
[['MT50', 'MT60', 'MT61'], 'contrast(120%)'], // 童心佬的滤镜(
|
filterMap.push(
|
||||||
[
|
[['MT50', 'MT60', 'MT61'], 'contrast(120%)'], // 童心佬的滤镜(
|
||||||
core.floorIds.slice(61, 70).concat(core.floorIds.slice(72, 107)),
|
[
|
||||||
'contrast(120%)'
|
core.floorIds
|
||||||
] // 童心佬的滤镜(
|
.slice(61, 70)
|
||||||
);
|
.concat(core.floorIds.slice(72, 107)),
|
||||||
});
|
'contrast(120%)'
|
||||||
|
] // 童心佬的滤镜(
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export class LayerGroupFilter implements ILayerGroupRenderExtends {
|
export class LayerGroupFilter implements ILayerGroupRenderExtends {
|
||||||
id: string = 'filter';
|
id: string = 'filter';
|
@ -8,8 +8,7 @@ import {
|
|||||||
Sprite,
|
Sprite,
|
||||||
Transform
|
Transform
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
|
import { gameListener, hook } from '@user/data-base';
|
||||||
const gameListener = Mota.require('var', 'gameListener');
|
|
||||||
|
|
||||||
export class LayerGroupHalo implements ILayerGroupRenderExtends {
|
export class LayerGroupHalo implements ILayerGroupRenderExtends {
|
||||||
id: string = 'halo';
|
id: string = 'halo';
|
||||||
@ -130,7 +129,7 @@ function updateHalo(block: Block) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mota.require('var', 'hook').on('enemyExtract', col => {
|
hook.on('enemyExtract', col => {
|
||||||
LayerGroupHalo.sprites.forEach(v => {
|
LayerGroupHalo.sprites.forEach(v => {
|
||||||
const floor = v.binder.getFloor();
|
const floor = v.binder.getFloor();
|
||||||
if (col.floorId === floor) {
|
if (col.floorId === floor) {
|
@ -7,7 +7,7 @@ import {
|
|||||||
LayerGroup,
|
LayerGroup,
|
||||||
Sprite
|
Sprite
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import type { BluePalace } from '@/game/mechanism/misc';
|
import { BluePalace } from '@user/data-state';
|
||||||
|
|
||||||
/** 最大粒子数 */
|
/** 最大粒子数 */
|
||||||
const MAX_PARTICLES = 10;
|
const MAX_PARTICLES = 10;
|
||||||
@ -24,7 +24,7 @@ export class LayerGroupPortal implements ILayerGroupRenderExtends {
|
|||||||
portal!: Portal;
|
portal!: Portal;
|
||||||
|
|
||||||
private onFloorChange = (floor: FloorIds) => {
|
private onFloorChange = (floor: FloorIds) => {
|
||||||
const data = Mota.require('module', 'Mechanism').BluePalace.portals;
|
const data = BluePalace.portals;
|
||||||
this.portal.cellSize = this.group.cellSize;
|
this.portal.cellSize = this.group.cellSize;
|
||||||
this.portal.setData(data[floor] ?? []);
|
this.portal.setData(data[floor] ?? []);
|
||||||
};
|
};
|
@ -1,25 +1,28 @@
|
|||||||
import {
|
import {
|
||||||
Container,
|
Container,
|
||||||
FloorDamageExtends,
|
|
||||||
LayerGroupFloorBinder,
|
LayerGroupFloorBinder,
|
||||||
FloorLayer,
|
FloorLayer,
|
||||||
LayerGroup,
|
LayerGroup,
|
||||||
FloorViewport,
|
FloorViewport,
|
||||||
MotaRenderer
|
MotaRenderer
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import { FloorItemDetail } from '@/plugin/fx/itemDetail';
|
import { hook } from '@user/data-base';
|
||||||
|
import { MiscData } from '@user/data-state';
|
||||||
|
import { FloorDamageExtends } from './damage';
|
||||||
|
import { FloorItemDetail } from './itemDetail';
|
||||||
|
|
||||||
const loopMaps = Mota.require('module', 'Mechanism').MiscData.loopMaps;
|
const loopMaps = MiscData.loopMaps;
|
||||||
|
|
||||||
let loopLayer: LayerGroup;
|
let loopLayer: LayerGroup;
|
||||||
let show: boolean = false;
|
let show: boolean = false;
|
||||||
/** 循环式地图中,更新视角的委托ticker */
|
/** 循环式地图中,更新视角的委托ticker */
|
||||||
let delegation: number = -1;
|
let delegation: number = -1;
|
||||||
|
|
||||||
const hook = Mota.require('var', 'hook');
|
export function createLoopMap() {
|
||||||
hook.on('changingFloor', (floorId, heroLoc) => {
|
hook.on('changingFloor', (floorId, heroLoc) => {
|
||||||
enableLoopMapElement(floorId);
|
enableLoopMapElement(floorId);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function createLayer() {
|
function createLayer() {
|
||||||
const group = new LayerGroup();
|
const group = new LayerGroup();
|
@ -1,7 +1,6 @@
|
|||||||
import { LayerShadowExtends } from '@/core/fx/shadow';
|
import { LayerShadowExtends } from '@motajs/legacy-ui';
|
||||||
import {
|
import {
|
||||||
ILayerGroupRenderExtends,
|
ILayerGroupRenderExtends,
|
||||||
FloorDamageExtends,
|
|
||||||
LayerGroupAnimate,
|
LayerGroupAnimate,
|
||||||
FloorViewport,
|
FloorViewport,
|
||||||
ILayerRenderExtends,
|
ILayerRenderExtends,
|
||||||
@ -11,13 +10,7 @@ import {
|
|||||||
LayerGroup,
|
LayerGroup,
|
||||||
Font
|
Font
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import { WeatherController } from '@/module/weather';
|
import { WeatherController } from '../../weather';
|
||||||
import { FloorChange } from '@/plugin/fallback';
|
|
||||||
import { LayerGroupFilter } from '@/plugin/fx/gameCanvas';
|
|
||||||
import { LayerGroupHalo } from '@/plugin/fx/halo';
|
|
||||||
import { FloorItemDetail } from '@/plugin/fx/itemDetail';
|
|
||||||
import { PopText } from '@/plugin/fx/pop';
|
|
||||||
import { LayerGroupPortal } from '@/plugin/fx/portal';
|
|
||||||
import { defineComponent, onMounted, reactive, ref } from 'vue';
|
import { defineComponent, onMounted, reactive, ref } from 'vue';
|
||||||
import { Textbox, Tip } from '../components';
|
import { Textbox, Tip } from '../components';
|
||||||
import { GameUI, UIController } from '@motajs/system-ui';
|
import { GameUI, UIController } from '@motajs/system-ui';
|
||||||
@ -35,6 +28,16 @@ import {
|
|||||||
} from './statusBar';
|
} from './statusBar';
|
||||||
import { onLoaded } from '../use';
|
import { onLoaded } from '../use';
|
||||||
import { ReplayingStatus } from './toolbar';
|
import { ReplayingStatus } from './toolbar';
|
||||||
|
import { getHeroStatusOn, HeroSkill, NightSpecial } from '@user/data-state';
|
||||||
|
import { jumpIgnoreFloor } from '@user/legacy-plugin-data';
|
||||||
|
import { hook } from '@user/data-base';
|
||||||
|
import { FloorDamageExtends } from '../damage';
|
||||||
|
import { FloorItemDetail } from '../itemDetail';
|
||||||
|
import { LayerGroupPortal } from '../legacy/portal';
|
||||||
|
import { LayerGroupFilter } from '../legacy/gameCanvas';
|
||||||
|
import { LayerGroupHalo } from '../legacy/halo';
|
||||||
|
import { FloorChange } from '../legacy/fallback';
|
||||||
|
import { PopText } from '../legacy/pop';
|
||||||
|
|
||||||
const MainScene = defineComponent(() => {
|
const MainScene = defineComponent(() => {
|
||||||
const layerGroupExtends: ILayerGroupRenderExtends[] = [
|
const layerGroupExtends: ILayerGroupRenderExtends[] = [
|
||||||
@ -112,8 +115,6 @@ const MainScene = defineComponent(() => {
|
|||||||
night: 0
|
night: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
const { getHeroStatusOn } = Mota.requireAll('fn');
|
|
||||||
|
|
||||||
const updateStatus = () => {
|
const updateStatus = () => {
|
||||||
if (!core.status || !core.status.hero || !core.status.floorId) return;
|
if (!core.status || !core.status.hero || !core.status.floorId) return;
|
||||||
hideStatus.value = core.getFlag('hideStatusBar', false);
|
hideStatus.value = core.getFlag('hideStatusBar', false);
|
||||||
@ -135,7 +136,6 @@ const MainScene = defineComponent(() => {
|
|||||||
leftStatus.exAtk = getHeroStatusOn('mana');
|
leftStatus.exAtk = getHeroStatusOn('mana');
|
||||||
leftStatus.magicDef = getHeroStatusOn('magicDef');
|
leftStatus.magicDef = getHeroStatusOn('magicDef');
|
||||||
|
|
||||||
const { HeroSkill, NightSpecial } = Mota.require('module', 'Mechanism');
|
|
||||||
rightStatus.autoSkill = HeroSkill.getAutoSkill();
|
rightStatus.autoSkill = HeroSkill.getAutoSkill();
|
||||||
rightStatus.skillName = HeroSkill.getSkillName();
|
rightStatus.skillName = HeroSkill.getSkillName();
|
||||||
rightStatus.skillDesc = HeroSkill.getSkillDesc();
|
rightStatus.skillDesc = HeroSkill.getSkillDesc();
|
||||||
@ -148,7 +148,7 @@ const MainScene = defineComponent(() => {
|
|||||||
replayStatus.played = totalList.length - toReplay.length;
|
replayStatus.played = totalList.length - toReplay.length;
|
||||||
replayStatus.total = totalList.length;
|
replayStatus.total = totalList.length;
|
||||||
if (HeroSkill.learnedSkill(HeroSkill.Jump)) {
|
if (HeroSkill.learnedSkill(HeroSkill.Jump)) {
|
||||||
if (Mota.Plugin.require('skill_g').jumpIgnoreFloor.has(floor)) {
|
if (jumpIgnoreFloor.has(floor)) {
|
||||||
rightStatus.jumpCount = -2;
|
rightStatus.jumpCount = -2;
|
||||||
} else {
|
} else {
|
||||||
rightStatus.jumpCount = 3 - (flags[`jump_${floor}`] ?? 0);
|
rightStatus.jumpCount = 3 - (flags[`jump_${floor}`] ?? 0);
|
||||||
@ -168,7 +168,7 @@ const MainScene = defineComponent(() => {
|
|||||||
loaded.value = true;
|
loaded.value = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
Mota.require('var', 'hook').on('statusBarUpdate', updateStatus);
|
hook.on('statusBarUpdate', updateStatus);
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<container id="main-scene" width={MAIN_WIDTH} height={MAIN_HEIGHT}>
|
<container id="main-scene" width={MAIN_WIDTH} height={MAIN_HEIGHT}>
|
@ -14,7 +14,7 @@ import { mainUi } from '@motajs/legacy-ui';
|
|||||||
import { gameKey } from '@motajs/system-action';
|
import { gameKey } from '@motajs/system-action';
|
||||||
import { generateKeyboardEvent } from '@motajs/system-action';
|
import { generateKeyboardEvent } from '@motajs/system-action';
|
||||||
import { getVitualKeyOnce } from '@motajs/legacy-ui';
|
import { getVitualKeyOnce } from '@motajs/legacy-ui';
|
||||||
import { getAllSavesData, getSaveData } from '@/module/utils';
|
import { getAllSavesData, getSaveData } from '../../utils';
|
||||||
|
|
||||||
export interface SettingsProps extends Partial<ChoicesProps>, UIComponentProps {
|
export interface SettingsProps extends Partial<ChoicesProps>, UIComponentProps {
|
||||||
loc: ElementLocator;
|
loc: ElementLocator;
|
||||||
@ -410,7 +410,9 @@ export const DownloadSaveSelect = defineComponent<SettingsProps>(props => {
|
|||||||
{ text: '请等待处理完毕' }
|
{ text: '请等待处理完毕' }
|
||||||
);
|
);
|
||||||
core.download(
|
core.download(
|
||||||
`${core.firstData.name}_${core.formatDate2(new Date())}.h5save`,
|
`${core.firstData.name}_${core.formatDate2(
|
||||||
|
new Date()
|
||||||
|
)}.h5save`,
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -426,7 +428,9 @@ export const DownloadSaveSelect = defineComponent<SettingsProps>(props => {
|
|||||||
if (confirm) {
|
if (confirm) {
|
||||||
const data = await getSaveData(core.saves.saveIndex);
|
const data = await getSaveData(core.saves.saveIndex);
|
||||||
core.download(
|
core.download(
|
||||||
`${core.firstData.name}_${core.formatDate2(new Date())}.h5save`,
|
`${core.firstData.name}_${core.formatDate2(
|
||||||
|
new Date()
|
||||||
|
)}.h5save`,
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -18,6 +18,7 @@ import {
|
|||||||
ReplayingStatus,
|
ReplayingStatus,
|
||||||
ReplayingToolbar
|
ReplayingToolbar
|
||||||
} from './toolbar';
|
} from './toolbar';
|
||||||
|
import { HeroSkill } from '@user/data-state';
|
||||||
|
|
||||||
export interface ILeftHeroStatus {
|
export interface ILeftHeroStatus {
|
||||||
hp: number;
|
hp: number;
|
||||||
@ -275,7 +276,6 @@ export const RightStatusBar = defineComponent<StatusBarProps<IRightHeroStatus>>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const changeAutoSkill = () => {
|
const changeAutoSkill = () => {
|
||||||
const { HeroSkill } = Mota.require('module', 'Mechanism');
|
|
||||||
const auto = !s.autoSkill;
|
const auto = !s.autoSkill;
|
||||||
HeroSkill.setAutoSkill(auto);
|
HeroSkill.setAutoSkill(auto);
|
||||||
core.status.route.push(`set:autoSkill:${auto}`);
|
core.status.route.push(`set:autoSkill:${auto}`);
|
@ -13,17 +13,14 @@ import {
|
|||||||
StepForward,
|
StepForward,
|
||||||
ViewMapIcon
|
ViewMapIcon
|
||||||
} from '../components/icons';
|
} from '../components/icons';
|
||||||
import {
|
import { getVitualKeyOnce, openDanmakuPoster } from '@motajs/legacy-ui';
|
||||||
generateBinary,
|
|
||||||
getVitualKeyOnce,
|
|
||||||
openDanmakuPoster
|
|
||||||
} from '@motajs/legacy-ui';
|
|
||||||
import { gameKey } from '@motajs/system-action';
|
import { gameKey } from '@motajs/system-action';
|
||||||
import { generateKeyboardEvent } from '@motajs/system-action';
|
import { generateKeyboardEvent } from '@motajs/system-action';
|
||||||
import { transitioned } from '../use';
|
import { transitioned } from '../use';
|
||||||
import { linear } from 'mutate-animate';
|
import { linear } from 'mutate-animate';
|
||||||
import { KeyCode } from '@motajs/client-base';
|
import { KeyCode } from '@motajs/client-base';
|
||||||
import { Progress } from '../components/misc';
|
import { Progress } from '../components/misc';
|
||||||
|
import { generateBinary } from '@motajs/legacy-common';
|
||||||
|
|
||||||
interface ToolbarProps extends DefaultProps {
|
interface ToolbarProps extends DefaultProps {
|
||||||
loc?: ElementLocator;
|
loc?: ElementLocator;
|
@ -1,3 +1,4 @@
|
|||||||
|
import { loading } from '@user/data-base';
|
||||||
import { TimingFn, Transition } from 'mutate-animate';
|
import { TimingFn, Transition } from 'mutate-animate';
|
||||||
import {
|
import {
|
||||||
ComponentInternalInstance,
|
ComponentInternalInstance,
|
||||||
@ -59,7 +60,6 @@ export function onOrientationChange(hook: OrientationHook) {
|
|||||||
* @param hook 当游戏加载完成时执行的函数
|
* @param hook 当游戏加载完成时执行的函数
|
||||||
*/
|
*/
|
||||||
export function onLoaded(hook: () => void) {
|
export function onLoaded(hook: () => void) {
|
||||||
const loading = Mota.require('var', 'loading');
|
|
||||||
if (!loading.loaded) {
|
if (!loading.loaded) {
|
||||||
loading.once('loaded', hook);
|
loading.once('loaded', hook);
|
||||||
} else {
|
} else {
|
0
packages-user/client-modules/src/weather/cloud.ts
Normal file
0
packages-user/client-modules/src/weather/cloud.ts
Normal file
@ -10,6 +10,7 @@ import {
|
|||||||
MotaOffscreenCanvas2D
|
MotaOffscreenCanvas2D
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import { IWeather } from './weather';
|
import { IWeather } from './weather';
|
||||||
|
import { loading } from '@user/data-base';
|
||||||
|
|
||||||
const snowVs = /* glsl */ `
|
const snowVs = /* glsl */ `
|
||||||
in vec2 a_snowVertex;
|
in vec2 a_snowVertex;
|
||||||
@ -105,7 +106,7 @@ void main() {
|
|||||||
/** 雨滴顶点坐标 */
|
/** 雨滴顶点坐标 */
|
||||||
const vertex = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
|
const vertex = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('coreInit', () => {
|
loading.once('coreInit', () => {
|
||||||
const shader = new SnowShader();
|
const shader = new SnowShader();
|
||||||
const gl = shader.gl;
|
const gl = shader.gl;
|
||||||
shader.size(480, 480);
|
shader.size(480, 480);
|
@ -7,6 +7,9 @@ interface GameLoadEvent {
|
|||||||
autotileLoaded: [];
|
autotileLoaded: [];
|
||||||
coreInit: [];
|
coreInit: [];
|
||||||
loaded: [];
|
loaded: [];
|
||||||
|
registered: [];
|
||||||
|
dataRegistered: [];
|
||||||
|
clientRegistered: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class GameLoading extends EventEmitter<GameLoadEvent> {
|
class GameLoading extends EventEmitter<GameLoadEvent> {
|
||||||
@ -58,6 +61,25 @@ class GameLoading extends EventEmitter<GameLoadEvent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const loading = new GameLoading();
|
export const loading = new GameLoading();
|
||||||
|
main.loading = loading;
|
||||||
|
|
||||||
|
let clientRegistered = false;
|
||||||
|
let dataRegistered = false;
|
||||||
|
|
||||||
|
function checkRegistered() {
|
||||||
|
if (clientRegistered && dataRegistered) {
|
||||||
|
loading.emit('registered');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.once('clientRegistered', () => {
|
||||||
|
clientRegistered = true;
|
||||||
|
checkRegistered();
|
||||||
|
});
|
||||||
|
loading.once('dataRegistered', () => {
|
||||||
|
dataRegistered = true;
|
||||||
|
checkRegistered();
|
||||||
|
});
|
||||||
|
|
||||||
export interface GameEvent {
|
export interface GameEvent {
|
||||||
/** Emitted in libs/events.js resetGame. */
|
/** Emitted in libs/events.js resetGame. */
|
||||||
@ -107,6 +129,8 @@ export interface GameEvent {
|
|||||||
];
|
];
|
||||||
/** Emitted in lib/control.js */
|
/** Emitted in lib/control.js */
|
||||||
replayStatus: [replaying: boolean];
|
replayStatus: [replaying: boolean];
|
||||||
|
/** Emitted in project/functions.js */
|
||||||
|
loadData: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hook = new EventEmitter<GameEvent>();
|
export const hook = new EventEmitter<GameEvent>();
|
||||||
|
@ -16,8 +16,9 @@ export interface CurrentEnemy {
|
|||||||
onMapEnemy: DamageEnemy[];
|
onMapEnemy: DamageEnemy[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
export function patchBattle() {
|
||||||
const patch = new Patch(PatchClass.Enemys);
|
const patch = new Patch(PatchClass.Enemys);
|
||||||
|
const patch2 = new Patch(PatchClass.Events);
|
||||||
|
|
||||||
patch.add('canBattle', function (x, y, floorId) {
|
patch.add('canBattle', function (x, y, floorId) {
|
||||||
const enemy = typeof x === 'number' ? getEnemy(x, y!, floorId) : x;
|
const enemy = typeof x === 'number' ? getEnemy(x, y!, floorId) : x;
|
||||||
@ -31,7 +32,7 @@ function init() {
|
|||||||
return damage < core.status.hero.hp;
|
return damage < core.status.hero.hp;
|
||||||
});
|
});
|
||||||
|
|
||||||
core.events.battle = function battle(
|
function battle(
|
||||||
x: number | DamageEnemy,
|
x: number | DamageEnemy,
|
||||||
y: number,
|
y: number,
|
||||||
force: boolean = false,
|
force: boolean = false,
|
||||||
@ -59,7 +60,7 @@ function init() {
|
|||||||
// 战后事件
|
// 战后事件
|
||||||
core.afterBattle(enemy, isLoc ? x : enemy.x, y);
|
core.afterBattle(enemy, isLoc ? x : enemy.x, y);
|
||||||
callback?.();
|
callback?.();
|
||||||
};
|
}
|
||||||
|
|
||||||
const getFacedId = (enemy: DamageEnemy) => {
|
const getFacedId = (enemy: DamageEnemy) => {
|
||||||
const e = enemy.enemy;
|
const e = enemy.enemy;
|
||||||
@ -69,9 +70,7 @@ function init() {
|
|||||||
return e.id;
|
return e.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
core.enemys.getCurrentEnemys = function getCurrentEnemys(
|
patch.add('getCurrentEnemys', function (floorId = core.status.floorId) {
|
||||||
floorId = core.status.floorId
|
|
||||||
) {
|
|
||||||
floorId = floorId || core.status.floorId;
|
floorId = floorId || core.status.floorId;
|
||||||
const enemys: CurrentEnemy[] = [];
|
const enemys: CurrentEnemy[] = [];
|
||||||
const used: Record<string, DamageEnemy[]> = {};
|
const used: Record<string, DamageEnemy[]> = {};
|
||||||
@ -100,9 +99,9 @@ function init() {
|
|||||||
const bd = b.enemy.calDamage().damage;
|
const bd = b.enemy.calDamage().damage;
|
||||||
return ad - bd;
|
return ad - bd;
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
|
|
||||||
core.events._sys_battle = function (data: Block, callback?: () => void) {
|
patch2.add('_sys_battle', function (data: Block, callback?: () => void) {
|
||||||
// 检查战前事件
|
// 检查战前事件
|
||||||
const floor = core.floors[core.status.floorId];
|
const floor = core.floors[core.status.floorId];
|
||||||
const beforeBattle: MotaEvent = [];
|
const beforeBattle: MotaEvent = [];
|
||||||
@ -126,11 +125,11 @@ function init() {
|
|||||||
core.insertAction(beforeBattle, data.x, data.y, callback);
|
core.insertAction(beforeBattle, data.x, data.y, callback);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
core.battle(data.x, data.y, false, callback);
|
battle(data.x, data.y, false, callback);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
core.events._action_battle = function (data, x, y, prefix) {
|
patch2.add('_action_battle', function (data, x, y, prefix) {
|
||||||
if (data.id) {
|
if (data.id) {
|
||||||
const enemy = getSingleEnemy(data.id as EnemyIds);
|
const enemy = getSingleEnemy(data.id as EnemyIds);
|
||||||
// todo: 与不在地图上的怪物战斗
|
// todo: 与不在地图上的怪物战斗
|
||||||
@ -139,120 +138,125 @@ function init() {
|
|||||||
core.doAction();
|
core.doAction();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const [ex, ey] = this.__action_getLoc(
|
const [ex, ey] = core.events.__action_getLoc(
|
||||||
data.loc,
|
data.loc,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
prefix
|
prefix
|
||||||
) as LocArr;
|
) as LocArr;
|
||||||
core.battle(ex, ey, true, core.doAction);
|
battle(ex, ey, true, core.doAction);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
core.events.afterBattle = function afterBattle(
|
patch2.add(
|
||||||
enemy: DamageEnemy,
|
'afterBattle',
|
||||||
x?: number,
|
function (enemy: DamageEnemy, x?: number, y?: number) {
|
||||||
y?: number
|
const floorId = core.status.floorId;
|
||||||
) {
|
const special = enemy.info.special;
|
||||||
const floorId = core.status.floorId;
|
|
||||||
const special = enemy.info.special;
|
|
||||||
|
|
||||||
// 播放战斗动画
|
// 播放战斗动画
|
||||||
let animate: AnimationIds = 'hand';
|
let animate: AnimationIds = 'hand';
|
||||||
// 检查当前装备是否存在攻击动画
|
// 检查当前装备是否存在攻击动画
|
||||||
const equipId = core.getEquip(0);
|
const equipId = core.getEquip(0);
|
||||||
if (equipId && (core.material.items[equipId].equip || {}).animate)
|
if (equipId && (core.material.items[equipId].equip || {}).animate)
|
||||||
animate = core.material.items[equipId].equip.animate;
|
animate = core.material.items[equipId].equip.animate;
|
||||||
|
|
||||||
// 检查该动画是否存在SE,如果不存在则使用默认音效
|
// 检查该动画是否存在SE,如果不存在则使用默认音效
|
||||||
if (!core.material.animates[animate]?.se) core.playSound('attack.opus');
|
if (!core.material.animates[animate]?.se)
|
||||||
|
core.playSound('attack.opus');
|
||||||
|
|
||||||
// 战斗伤害
|
// 战斗伤害
|
||||||
const info = enemy.calDamage(core.status.hero);
|
const info = enemy.calDamage(core.status.hero);
|
||||||
const damage = info.damage;
|
const damage = info.damage;
|
||||||
// 判定是否致死
|
// 判定是否致死
|
||||||
if (damage >= core.status.hero.hp) {
|
if (damage >= core.status.hero.hp) {
|
||||||
core.status.hero.hp = 0;
|
core.status.hero.hp = 0;
|
||||||
core.updateStatusBar(false, true);
|
core.updateStatusBar(false, true);
|
||||||
core.events.lose('战斗失败');
|
core.events.lose('战斗失败');
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 扣减体力值并记录统计数据
|
||||||
|
core.status.hero.hp -= damage;
|
||||||
|
core.status.hero.statistics.battleDamage += damage;
|
||||||
|
core.status.hero.statistics.battle++;
|
||||||
|
|
||||||
|
// 智慧之源
|
||||||
|
if (special.has(14) && flags.hard === 2) {
|
||||||
|
core.addFlag(
|
||||||
|
'inte_' + floorId,
|
||||||
|
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10
|
||||||
|
);
|
||||||
|
core.status.hero.mdef -=
|
||||||
|
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 极昼永夜
|
||||||
|
if (special.has(22)) {
|
||||||
|
NightSpecial.addNight(floorId, -enemy.info.night!);
|
||||||
|
}
|
||||||
|
if (special.has(23)) {
|
||||||
|
NightSpecial.addNight(floorId, enemy.info.day!);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是融化怪,需要特殊标记一下
|
||||||
|
if (special.has(25) && !isNil(x) && !isNil(y)) {
|
||||||
|
flags[`melt_${floorId}`] ??= {};
|
||||||
|
flags[`melt_${floorId}`][`${x},${y}`] = enemy.info.melt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得金币
|
||||||
|
const money = enemy.info.money!;
|
||||||
|
core.status.hero.money += money;
|
||||||
|
core.status.hero.statistics.money += money;
|
||||||
|
|
||||||
|
// 获得经验
|
||||||
|
const exp = enemy.info.exp!;
|
||||||
|
core.status.hero.exp += exp;
|
||||||
|
core.status.hero.statistics.exp += exp;
|
||||||
|
|
||||||
|
const hint =
|
||||||
|
'打败 ' +
|
||||||
|
enemy.enemy.name +
|
||||||
|
',金币+' +
|
||||||
|
money +
|
||||||
|
',经验+' +
|
||||||
|
exp;
|
||||||
|
core.drawTip(hint, enemy.id);
|
||||||
|
|
||||||
|
HeroSkill.disableSkill();
|
||||||
|
|
||||||
|
// 事件的处理
|
||||||
|
const todo: MotaEvent = [];
|
||||||
|
|
||||||
|
// 战后事件
|
||||||
|
if (!isNil(core.status.floorId)) {
|
||||||
|
const loc = `${x},${y}` as LocString;
|
||||||
|
todo.push(
|
||||||
|
...(core.floors[core.status.floorId].afterBattle[loc] ?? [])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
todo.push(...(enemy.enemy.afterBattle ?? []));
|
||||||
|
|
||||||
|
// 如果事件不为空,将其插入
|
||||||
|
if (todo.length > 0) core.insertAction(todo, x, y);
|
||||||
|
|
||||||
|
if (!isNil(x) && !isNil(y)) {
|
||||||
|
core.drawAnimate(animate, x, y);
|
||||||
|
core.removeBlock(x, y);
|
||||||
|
} else core.drawHeroAnimate(animate);
|
||||||
|
|
||||||
|
// 如果已有事件正在处理中
|
||||||
|
if (core.status.event.id == null) core.continueAutomaticRoute();
|
||||||
|
else core.clearContinueAutomaticRoute();
|
||||||
|
|
||||||
|
core.checkAutoEvents();
|
||||||
|
|
||||||
|
hook.emit('afterBattle', enemy, x, y);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
// 扣减体力值并记录统计数据
|
|
||||||
core.status.hero.hp -= damage;
|
|
||||||
core.status.hero.statistics.battleDamage += damage;
|
|
||||||
core.status.hero.statistics.battle++;
|
|
||||||
|
|
||||||
// 智慧之源
|
|
||||||
if (special.has(14) && flags.hard === 2) {
|
|
||||||
core.addFlag(
|
|
||||||
'inte_' + floorId,
|
|
||||||
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10
|
|
||||||
);
|
|
||||||
core.status.hero.mdef -=
|
|
||||||
Math.ceil((core.status.hero.mdef / 10) * 0.3) * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 极昼永夜
|
|
||||||
if (special.has(22)) {
|
|
||||||
NightSpecial.addNight(floorId, -enemy.info.night!);
|
|
||||||
}
|
|
||||||
if (special.has(23)) {
|
|
||||||
NightSpecial.addNight(floorId, enemy.info.day!);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果是融化怪,需要特殊标记一下
|
|
||||||
if (special.has(25) && !isNil(x) && !isNil(y)) {
|
|
||||||
flags[`melt_${floorId}`] ??= {};
|
|
||||||
flags[`melt_${floorId}`][`${x},${y}`] = enemy.info.melt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获得金币
|
|
||||||
const money = enemy.info.money!;
|
|
||||||
core.status.hero.money += money;
|
|
||||||
core.status.hero.statistics.money += money;
|
|
||||||
|
|
||||||
// 获得经验
|
|
||||||
const exp = enemy.info.exp!;
|
|
||||||
core.status.hero.exp += exp;
|
|
||||||
core.status.hero.statistics.exp += exp;
|
|
||||||
|
|
||||||
const hint =
|
|
||||||
'打败 ' + enemy.enemy.name + ',金币+' + money + ',经验+' + exp;
|
|
||||||
core.drawTip(hint, enemy.id);
|
|
||||||
|
|
||||||
HeroSkill.disableSkill();
|
|
||||||
|
|
||||||
// 事件的处理
|
|
||||||
const todo: MotaEvent = [];
|
|
||||||
|
|
||||||
// 战后事件
|
|
||||||
if (!isNil(core.status.floorId)) {
|
|
||||||
const loc = `${x},${y}` as LocString;
|
|
||||||
todo.push(
|
|
||||||
...(core.floors[core.status.floorId].afterBattle[loc] ?? [])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
todo.push(...(enemy.enemy.afterBattle ?? []));
|
|
||||||
|
|
||||||
// 如果事件不为空,将其插入
|
|
||||||
if (todo.length > 0) core.insertAction(todo, x, y);
|
|
||||||
|
|
||||||
if (!isNil(x) && !isNil(y)) {
|
|
||||||
core.drawAnimate(animate, x, y);
|
|
||||||
core.removeBlock(x, y);
|
|
||||||
} else core.drawHeroAnimate(animate);
|
|
||||||
|
|
||||||
// 如果已有事件正在处理中
|
|
||||||
if (core.status.event.id == null) core.continueAutomaticRoute();
|
|
||||||
else core.clearContinueAutomaticRoute();
|
|
||||||
|
|
||||||
core.checkAutoEvents();
|
|
||||||
|
|
||||||
hook.emit('afterBattle', enemy, x, y);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
loading.once('coreInit', init);
|
loading.once('coreInit', patchBattle);
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Enemys {
|
interface Enemys {
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
import { patchBattle } from './battle';
|
||||||
|
|
||||||
|
export function patchAll() {
|
||||||
|
patchBattle();
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
import { getHeroStatusOf, getHeroStatusOn } from '../state/hero';
|
import { getHeroStatusOf, getHeroStatusOn } from '../state/hero';
|
||||||
import { Range } from '@user/data-utils';
|
import { Range, ensureArray, has, manhattan } from '@user/data-utils';
|
||||||
import { ensureArray, has, manhattan } from '@/plugin/game/utils';
|
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import { hook } from '@user/data-base';
|
import { hook } from '@user/data-base';
|
||||||
import { HeroSkill, NightSpecial } from '../mechanism/misc';
|
import { HeroSkill, NightSpecial } from '../mechanism';
|
||||||
import {
|
import {
|
||||||
EnemyInfo,
|
EnemyInfo,
|
||||||
DamageInfo,
|
DamageInfo,
|
||||||
@ -14,8 +13,10 @@ import {
|
|||||||
HaloFn,
|
HaloFn,
|
||||||
IEnemyCollection,
|
IEnemyCollection,
|
||||||
IDamageEnemy,
|
IDamageEnemy,
|
||||||
HaloType
|
HaloType,
|
||||||
|
IEnemyCollectionEvent
|
||||||
} from '@motajs/types';
|
} from '@motajs/types';
|
||||||
|
import { isNil } from 'lodash-es';
|
||||||
|
|
||||||
// todo: 光环划分优先级,从而可以实现光环的多级运算
|
// todo: 光环划分优先级,从而可以实现光环的多级运算
|
||||||
|
|
||||||
@ -53,13 +54,8 @@ specialValue
|
|||||||
.set(31, ['hpHalo'])
|
.set(31, ['hpHalo'])
|
||||||
.set(32, ['assimilateRange']);
|
.set(32, ['assimilateRange']);
|
||||||
|
|
||||||
interface EnemyCollectionEvent {
|
|
||||||
extract: [];
|
|
||||||
calculated: [];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class EnemyCollection
|
export class EnemyCollection
|
||||||
extends EventEmitter<EnemyCollectionEvent>
|
extends EventEmitter<IEnemyCollectionEvent>
|
||||||
implements IEnemyCollection
|
implements IEnemyCollection
|
||||||
{
|
{
|
||||||
floorId: FloorIds;
|
floorId: FloorIds;
|
||||||
@ -298,7 +294,7 @@ export class DamageEnemy implements IDamageEnemy {
|
|||||||
|
|
||||||
// 融化,融化不属于怪物光环,因此不能用provide和inject计算,需要在这里计算
|
// 融化,融化不属于怪物光环,因此不能用provide和inject计算,需要在这里计算
|
||||||
const melt = flags[`melt_${floorId}`];
|
const melt = flags[`melt_${floorId}`];
|
||||||
if (has(melt) && has(this.x) && has(this.y)) {
|
if (!isNil(melt) && !isNil(this.x) && !isNil(this.y)) {
|
||||||
for (const [loc, per] of Object.entries(melt)) {
|
for (const [loc, per] of Object.entries(melt)) {
|
||||||
const [mx, my] = loc.split(',').map(v => parseInt(v));
|
const [mx, my] = loc.split(',').map(v => parseInt(v));
|
||||||
if (
|
if (
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export * from './misc';
|
export * from './misc';
|
||||||
|
export * from './skillTree';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { backDir, has } from '@/plugin/game/utils';
|
import { backDir, has } from '@user/data-utils';
|
||||||
import { loading } from '@user/data-base';
|
import { loading } from '@user/data-base';
|
||||||
import type { LayerDoorAnimate } from '@motajs/render';
|
import type { LayerDoorAnimate } from '@motajs/render';
|
||||||
import { getSkillLevel } from '@/plugin/game/skillTree';
|
import { getSkillLevel } from './skillTree';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一些零散机制的数据
|
* 一些零散机制的数据
|
||||||
@ -48,131 +48,6 @@ export namespace NightSpecial {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace HeroSkill {
|
|
||||||
export const enum Skill {
|
|
||||||
None,
|
|
||||||
/** 断灭之刃 */
|
|
||||||
Blade,
|
|
||||||
/** 铸剑为盾 */
|
|
||||||
Shield,
|
|
||||||
/** 跳跃 */
|
|
||||||
Jump
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Blade = Skill.Blade;
|
|
||||||
export const Shield = Skill.Shield;
|
|
||||||
export const Jump = Skill.Jump;
|
|
||||||
|
|
||||||
const skillNameMap = new Map<Skill, string>([
|
|
||||||
[Skill.Blade, '断灭之刃'],
|
|
||||||
[Skill.Shield, '铸剑为盾'],
|
|
||||||
[Skill.Jump, '跳跃']
|
|
||||||
]);
|
|
||||||
|
|
||||||
const skillDesc = new Map<Skill, (level: number) => string>([
|
|
||||||
[
|
|
||||||
Skill.Blade,
|
|
||||||
level => `攻击上升 ${level * 10}%,防御下降 ${level * 10}%`
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Skill.Shield,
|
|
||||||
level => `防御上升 ${level * 10}%,攻击下降 ${level * 10}%`
|
|
||||||
],
|
|
||||||
[Skill.Jump, () => `跳过前方障碍,或踢走面前的怪物`]
|
|
||||||
]);
|
|
||||||
|
|
||||||
interface SkillSave {
|
|
||||||
autoSkill: boolean;
|
|
||||||
learned: Skill[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const learned = new Set<Skill>();
|
|
||||||
let autoSkill = true;
|
|
||||||
let enabled: Skill = Skill.None;
|
|
||||||
|
|
||||||
export function getLevel(skill: Skill = getEnabled()) {
|
|
||||||
switch (skill) {
|
|
||||||
case Blade:
|
|
||||||
return getSkillLevel(2);
|
|
||||||
case Jump:
|
|
||||||
return learned.has(Jump) ? 1 : 0;
|
|
||||||
case Shield:
|
|
||||||
return getSkillLevel(10);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSkillName(skill: Skill = getEnabled()) {
|
|
||||||
return skillNameMap.get(skill) ?? '未开启技能';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSkillDesc(
|
|
||||||
skill: Skill = getEnabled(),
|
|
||||||
level: number = getLevel()
|
|
||||||
) {
|
|
||||||
return skillDesc.get(skill)?.(level) ?? '';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setAutoSkill(auto: boolean) {
|
|
||||||
autoSkill = auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAutoSkill() {
|
|
||||||
return autoSkill;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function learnedSkill(skill: Skill) {
|
|
||||||
return learned.has(skill);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function learnSkill(skill: Skill) {
|
|
||||||
learned.add(skill);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function forgetSkill(skill: Skill) {
|
|
||||||
learned.delete(skill);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearSkill() {
|
|
||||||
learned.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function saveSkill(): SkillSave {
|
|
||||||
return { autoSkill, learned: [...learned] };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loadSkill(skills: SkillSave) {
|
|
||||||
learned.clear();
|
|
||||||
for (const skill of skills.learned) {
|
|
||||||
learned.add(skill);
|
|
||||||
}
|
|
||||||
autoSkill = skills.autoSkill;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAll() {
|
|
||||||
return learned;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleSkill(skill: Skill) {
|
|
||||||
if (!learned.has(skill)) return;
|
|
||||||
if (enabled !== skill) enabled = skill;
|
|
||||||
else enabled = Skill.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function enableSkill(skill: Skill) {
|
|
||||||
if (!learned.has(skill)) return;
|
|
||||||
enabled = skill;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function disableSkill() {
|
|
||||||
enabled = Skill.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace BluePalace {
|
export namespace BluePalace {
|
||||||
type DoorConvertInfo = [id: AllIds, x: number, y: number];
|
type DoorConvertInfo = [id: AllIds, x: number, y: number];
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { HeroSkill } from '@/game/mechanism/misc';
|
|
||||||
|
|
||||||
let levels: number[] = [];
|
let levels: number[] = [];
|
||||||
|
|
||||||
export type Chapter = 'chapter1' | 'chapter2';
|
export type Chapter = 'chapter1' | 'chapter2';
|
||||||
@ -233,7 +231,7 @@ export function getSkillConsume(skill: number) {
|
|||||||
|
|
||||||
export function openTree() {
|
export function openTree() {
|
||||||
if (main.replayChecking) return;
|
if (main.replayChecking) return;
|
||||||
Mota.require('var', 'mainUi').open('skillTree');
|
Mota.require('@motajs/legacy-ui').mainUi.open('skillTree');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -314,3 +312,128 @@ export function saveSkillTree() {
|
|||||||
export function loadSkillTree(data: number[]) {
|
export function loadSkillTree(data: number[]) {
|
||||||
levels = data ?? [];
|
levels = data ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export namespace HeroSkill {
|
||||||
|
export const enum Skill {
|
||||||
|
None,
|
||||||
|
/** 断灭之刃 */
|
||||||
|
Blade,
|
||||||
|
/** 铸剑为盾 */
|
||||||
|
Shield,
|
||||||
|
/** 跳跃 */
|
||||||
|
Jump
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Blade = Skill.Blade;
|
||||||
|
export const Shield = Skill.Shield;
|
||||||
|
export const Jump = Skill.Jump;
|
||||||
|
|
||||||
|
const skillNameMap = new Map<Skill, string>([
|
||||||
|
[Skill.Blade, '断灭之刃'],
|
||||||
|
[Skill.Shield, '铸剑为盾'],
|
||||||
|
[Skill.Jump, '跳跃']
|
||||||
|
]);
|
||||||
|
|
||||||
|
const skillDesc = new Map<Skill, (level: number) => string>([
|
||||||
|
[
|
||||||
|
Skill.Blade,
|
||||||
|
level => `攻击上升 ${level * 10}%,防御下降 ${level * 10}%`
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Skill.Shield,
|
||||||
|
level => `防御上升 ${level * 10}%,攻击下降 ${level * 10}%`
|
||||||
|
],
|
||||||
|
[Skill.Jump, () => `跳过前方障碍,或踢走面前的怪物`]
|
||||||
|
]);
|
||||||
|
|
||||||
|
interface SkillSave {
|
||||||
|
autoSkill: boolean;
|
||||||
|
learned: Skill[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const learned = new Set<Skill>();
|
||||||
|
let autoSkill = true;
|
||||||
|
let enabled: Skill = Skill.None;
|
||||||
|
|
||||||
|
export function getLevel(skill: Skill = getEnabled()) {
|
||||||
|
switch (skill) {
|
||||||
|
case Blade:
|
||||||
|
return getSkillLevel(2);
|
||||||
|
case Jump:
|
||||||
|
return learned.has(Jump) ? 1 : 0;
|
||||||
|
case Shield:
|
||||||
|
return getSkillLevel(10);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSkillName(skill: Skill = getEnabled()) {
|
||||||
|
return skillNameMap.get(skill) ?? '未开启技能';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSkillDesc(
|
||||||
|
skill: Skill = getEnabled(),
|
||||||
|
level: number = getLevel()
|
||||||
|
) {
|
||||||
|
return skillDesc.get(skill)?.(level) ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setAutoSkill(auto: boolean) {
|
||||||
|
autoSkill = auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAutoSkill() {
|
||||||
|
return autoSkill;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function learnedSkill(skill: Skill) {
|
||||||
|
return learned.has(skill);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function learnSkill(skill: Skill) {
|
||||||
|
learned.add(skill);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function forgetSkill(skill: Skill) {
|
||||||
|
learned.delete(skill);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearSkill() {
|
||||||
|
learned.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveSkill(): SkillSave {
|
||||||
|
return { autoSkill, learned: [...learned] };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadSkill(skills: SkillSave) {
|
||||||
|
learned.clear();
|
||||||
|
for (const skill of skills.learned) {
|
||||||
|
learned.add(skill);
|
||||||
|
}
|
||||||
|
autoSkill = skills.autoSkill;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAll() {
|
||||||
|
return learned;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toggleSkill(skill: Skill) {
|
||||||
|
if (!learned.has(skill)) return;
|
||||||
|
if (enabled !== skill) enabled = skill;
|
||||||
|
else enabled = Skill.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enableSkill(skill: Skill) {
|
||||||
|
if (!learned.has(skill)) return;
|
||||||
|
enabled = skill;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function disableSkill() {
|
||||||
|
enabled = Skill.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
import { HeroSkill, NightSpecial } from '../mechanism/misc';
|
import { HeroSkill, NightSpecial } from '../mechanism';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取勇士在某一点的属性
|
* 获取勇士在某一点的属性
|
||||||
@ -59,7 +59,7 @@ function getRealStatus(
|
|||||||
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
||||||
floorId: FloorIds = core.status.floorId
|
floorId: FloorIds = core.status.floorId
|
||||||
): any {
|
): any {
|
||||||
const { getSkillLevel } = Mota.Plugin.require('skillTree_g');
|
const { getSkillLevel } = Mota.require('@user/legacy-plugin-data');
|
||||||
if (name instanceof Array) {
|
if (name instanceof Array) {
|
||||||
const res: any = {};
|
const res: any = {};
|
||||||
name.forEach(v => {
|
name.forEach(v => {
|
||||||
|
@ -11,7 +11,7 @@ import type {
|
|||||||
LayerMovingRenderable,
|
LayerMovingRenderable,
|
||||||
LayerFloorBinder
|
LayerFloorBinder
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import type { HeroKeyMover } from '@/module/action/move';
|
import type { HeroKeyMover } from '@user/client-modules';
|
||||||
import { BluePalace, MiscData } from '../mechanism/misc';
|
import { BluePalace, MiscData } from '../mechanism/misc';
|
||||||
import { sleep } from '@motajs/common';
|
import { sleep } from '@motajs/common';
|
||||||
|
|
||||||
@ -939,7 +939,7 @@ export const heroMoveCollection: HeroMoveCollection = {
|
|||||||
loading.once('coreInit', () => {
|
loading.once('coreInit', () => {
|
||||||
// 注册按键操作
|
// 注册按键操作
|
||||||
Mota.r(() => {
|
Mota.r(() => {
|
||||||
const { HeroKeyMover } = Mota.require('@motajs/system-action');
|
const { HeroKeyMover } = Mota.require('@user/client-modules');
|
||||||
const { gameKey } = Mota.require('@motajs/system-action');
|
const { gameKey } = Mota.require('@motajs/system-action');
|
||||||
const keyMover = new HeroKeyMover(gameKey, heroMover);
|
const keyMover = new HeroKeyMover(gameKey, heroMover);
|
||||||
heroMoveCollection.keyMover = keyMover;
|
heroMoveCollection.keyMover = keyMover;
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export * from './range';
|
export * from './range';
|
||||||
|
export * from './utils';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@motajs/entry-client",
|
"name": "@user/entry-client",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@motajs/client": "workspace:*",
|
"@motajs/client": "workspace:*",
|
||||||
"@motajs/client-base": "workspace:*",
|
"@motajs/client-base": "workspace:*",
|
||||||
@ -16,6 +16,8 @@
|
|||||||
"@motajs/legacy-client": "workspace:*",
|
"@motajs/legacy-client": "workspace:*",
|
||||||
"@motajs/legacy-data": "workspace:*",
|
"@motajs/legacy-data": "workspace:*",
|
||||||
"@motajs/legacy-ui": "workspace:*",
|
"@motajs/legacy-ui": "workspace:*",
|
||||||
"@motajs/legacy-system": "workspace:*"
|
"@motajs/legacy-system": "workspace:*",
|
||||||
|
"@user/client-modules": "workspace:*",
|
||||||
|
"@user/legacy-plugin-client": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,8 +14,15 @@ import * as RenderVue from '@motajs/render-vue';
|
|||||||
import * as System from '@motajs/system';
|
import * as System from '@motajs/system';
|
||||||
import * as SystemAction from '@motajs/system-action';
|
import * as SystemAction from '@motajs/system-action';
|
||||||
import * as SystemUI from '@motajs/system-ui';
|
import * as SystemUI from '@motajs/system-ui';
|
||||||
|
import * as ClientModules from '@user/client-modules';
|
||||||
|
import * as LegacyPluginClient from '@user/legacy-plugin-client';
|
||||||
|
import * as MutateAnimate from 'mutate-animate';
|
||||||
|
import * as Vue from 'vue';
|
||||||
|
import { hook, loading } from '@user/data-base';
|
||||||
|
|
||||||
export function create() {
|
export function create() {
|
||||||
|
loading.once('registered', createModule);
|
||||||
|
|
||||||
Mota.register('@motajs/client', Client);
|
Mota.register('@motajs/client', Client);
|
||||||
Mota.register('@motajs/client-base', ClientBase);
|
Mota.register('@motajs/client-base', ClientBase);
|
||||||
Mota.register('@motajs/common', Common);
|
Mota.register('@motajs/common', Common);
|
||||||
@ -31,4 +38,20 @@ export function create() {
|
|||||||
Mota.register('@motajs/system', System);
|
Mota.register('@motajs/system', System);
|
||||||
Mota.register('@motajs/system-action', SystemAction);
|
Mota.register('@motajs/system-action', SystemAction);
|
||||||
Mota.register('@motajs/system-ui', SystemUI);
|
Mota.register('@motajs/system-ui', SystemUI);
|
||||||
|
Mota.register('@user/client-modules', ClientModules);
|
||||||
|
Mota.register('@user/legacy-plugin-client', LegacyPluginClient);
|
||||||
|
Mota.register('MutateAnimate', MutateAnimate);
|
||||||
|
Mota.register('Vue', Vue);
|
||||||
|
|
||||||
|
loading.emit('clientRegistered');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createModule() {
|
||||||
|
LegacyUI.create();
|
||||||
|
RenderElements.create();
|
||||||
|
ClientModules.create();
|
||||||
|
|
||||||
|
await import('ant-design-vue/dist/antd.dark.css');
|
||||||
|
main.renderLoaded = true;
|
||||||
|
hook.emit('renderLoaded');
|
||||||
}
|
}
|
||||||
|
@ -1 +1,5 @@
|
|||||||
export * from './create';
|
import { create } from './create';
|
||||||
|
|
||||||
|
export function createGame() {
|
||||||
|
create();
|
||||||
|
}
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@user/entry-data"
|
"name": "@user/entry-data",
|
||||||
|
"dependencies": {
|
||||||
|
"@motajs/legacy-common": "workspace:*",
|
||||||
|
"@user/data-base": "workspace:*",
|
||||||
|
"@user/data-fallback": "workspace:*",
|
||||||
|
"@user/data-state": "workspace:*",
|
||||||
|
"@user/data-utils": "workspace:*",
|
||||||
|
"@user/legacy-plugin-data": "workspace:*"
|
||||||
|
}
|
||||||
}
|
}
|
22
packages-user/entry-data/src/create.ts
Normal file
22
packages-user/entry-data/src/create.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Mota } from './mota';
|
||||||
|
import * as DataBase from '@user/data-base';
|
||||||
|
import * as DataFallback from '@user/data-fallback';
|
||||||
|
import * as DataState from '@user/data-state';
|
||||||
|
import * as DataUtils from '@user/data-utils';
|
||||||
|
import * as LegacyPluginData from '@user/legacy-plugin-data';
|
||||||
|
|
||||||
|
export function create() {
|
||||||
|
DataBase.loading.once('registered', createModule);
|
||||||
|
|
||||||
|
Mota.register('@user/data-base', DataBase);
|
||||||
|
Mota.register('@user/data-fallback', DataFallback);
|
||||||
|
Mota.register('@user/data-state', DataState);
|
||||||
|
Mota.register('@user/data-utils', DataUtils);
|
||||||
|
Mota.register('@user/legacy-plugin-data', LegacyPluginData);
|
||||||
|
|
||||||
|
DataBase.loading.emit('dataRegistered');
|
||||||
|
}
|
||||||
|
|
||||||
|
function createModule() {
|
||||||
|
LegacyPluginData.create();
|
||||||
|
}
|
@ -1,5 +1,15 @@
|
|||||||
import { createMota } from './mota';
|
import { createMota } from './mota';
|
||||||
|
import { create } from './create';
|
||||||
|
import { patchAll } from '@user/data-fallback';
|
||||||
|
import { loading } from '@user/data-base';
|
||||||
|
import { Patch } from '@motajs/legacy-common';
|
||||||
|
|
||||||
createMota();
|
createMota();
|
||||||
|
patchAll();
|
||||||
|
create();
|
||||||
|
|
||||||
|
loading.once('coreInit', () => {
|
||||||
|
Patch.patchAll();
|
||||||
|
});
|
||||||
|
|
||||||
export * from './mota';
|
export * from './mota';
|
||||||
|
@ -13,6 +13,16 @@ import type * as RenderVue from '@motajs/render-vue';
|
|||||||
import type * as System from '@motajs/system';
|
import type * as System from '@motajs/system';
|
||||||
import type * as SystemAction from '@motajs/system-action';
|
import type * as SystemAction from '@motajs/system-action';
|
||||||
import type * as SystemUI from '@motajs/system-ui';
|
import type * as SystemUI from '@motajs/system-ui';
|
||||||
|
import type * as ClientModules from '@user/client-modules';
|
||||||
|
import type * as DataBase from '@user/data-base';
|
||||||
|
import type * as DataFallback from '@user/data-fallback';
|
||||||
|
import type * as DataState from '@user/data-state';
|
||||||
|
import type * as DataUtils from '@user/data-utils';
|
||||||
|
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';
|
||||||
|
|
||||||
interface ModuleInterface {
|
interface ModuleInterface {
|
||||||
'@motajs/client': typeof Client;
|
'@motajs/client': typeof Client;
|
||||||
@ -30,6 +40,16 @@ interface ModuleInterface {
|
|||||||
'@motajs/system': typeof System;
|
'@motajs/system': typeof System;
|
||||||
'@motajs/system-action': typeof SystemAction;
|
'@motajs/system-action': typeof SystemAction;
|
||||||
'@motajs/system-ui': typeof SystemUI;
|
'@motajs/system-ui': typeof SystemUI;
|
||||||
|
'@user/client-modules': typeof ClientModules;
|
||||||
|
'@user/data-base': typeof DataBase;
|
||||||
|
'@user/data-fallback': typeof DataFallback;
|
||||||
|
'@user/data-state': typeof DataState;
|
||||||
|
'@user/data-utils': typeof DataUtils;
|
||||||
|
'@user/legacy-plugin-client': typeof LegacyPluginClient;
|
||||||
|
'@user/legacy-plugin-data': typeof LegacyPluginData;
|
||||||
|
// ---------- 必要的第三方库
|
||||||
|
MutateAnimate: typeof MutateAnimate;
|
||||||
|
Vue: typeof Vue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMota {
|
export interface IMota {
|
||||||
@ -73,10 +93,6 @@ class MotaSystem implements IMota {
|
|||||||
r = r;
|
r = r;
|
||||||
rf = rf;
|
rf = rf;
|
||||||
|
|
||||||
constructor() {
|
|
||||||
throw new Error(`System interface class cannot be constructed.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
require(key: string): any {
|
require(key: string): any {
|
||||||
const data = this.modules[key];
|
const data = this.modules[key];
|
||||||
if (data) return data;
|
if (data) return data;
|
||||||
@ -137,7 +153,7 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Mota = new MotaSystem();
|
export const Mota: IMota = new MotaSystem();
|
||||||
|
|
||||||
export function createMota() {
|
export function createMota() {
|
||||||
window.Mota = Mota;
|
window.Mota = Mota;
|
||||||
|
7
packages-user/legacy-plugin-client/package.json
Normal file
7
packages-user/legacy-plugin-client/package.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "@user/legacy-plugin-client",
|
||||||
|
"dependencies": {
|
||||||
|
"@user/client-modules": "workspace:*",
|
||||||
|
"@user/data-state": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ import {
|
|||||||
RenderItemPosition,
|
RenderItemPosition,
|
||||||
Transform
|
Transform
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import { IStateDamageable } from '@/game/state/interface';
|
import { IStateDamageable } from '@user/data-state';
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import { Ticker } from 'mutate-animate';
|
import { Ticker } from 'mutate-animate';
|
||||||
|
|
@ -1,3 +1,4 @@
|
|||||||
|
import { hook } from '@user/data-base';
|
||||||
import { BarrageBoss } from './barrage';
|
import { BarrageBoss } from './barrage';
|
||||||
import { TowerBoss } from './towerBoss';
|
import { TowerBoss } from './towerBoss';
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ export function getBoss<T extends BarrageBoss>(): T | null {
|
|||||||
return boss as T;
|
return boss as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mota.require('var', 'hook').on('reset', () => {
|
hook.on('reset', () => {
|
||||||
if (boss) {
|
if (boss) {
|
||||||
boss.end();
|
boss.end();
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { IStateDamageable } from '@/game/state/interface';
|
import { IStateDamageable } from '@user/data-state';
|
||||||
import { BarrageBoss, BossSprite, Hitbox } from './barrage';
|
import { BarrageBoss, BossSprite, Hitbox } from './barrage';
|
||||||
import {
|
import {
|
||||||
Container,
|
Container,
|
||||||
@ -9,11 +9,13 @@ import {
|
|||||||
Transform,
|
Transform,
|
||||||
MotaOffscreenCanvas2D
|
MotaOffscreenCanvas2D
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import { Pop } from '../fx/pop';
|
import { Pop } from '../../../client-modules/src/render/legacy/pop';
|
||||||
import { SplittableBall } from './palaceBossProjectile';
|
import { SplittableBall } from './palaceBossProjectile';
|
||||||
import { PointEffect } from '../fx/pointShader';
|
import { PointEffect } from '../fx/pointShader';
|
||||||
|
import { loading } from '@user/data-base';
|
||||||
|
import { clip } from '@user/legacy-plugin-data';
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('coreInit', () => {
|
loading.once('coreInit', () => {
|
||||||
const shader = new Shader();
|
const shader = new Shader();
|
||||||
shader.size(480, 480);
|
shader.size(480, 480);
|
||||||
shader.setHD(true);
|
shader.setHD(true);
|
||||||
@ -102,7 +104,7 @@ export class PalaceBoss extends BarrageBoss {
|
|||||||
PalaceBoss.effect.end();
|
PalaceBoss.effect.end();
|
||||||
core.status.hero.hp = this.heroHp;
|
core.status.hero.hp = this.heroHp;
|
||||||
|
|
||||||
Mota.Plugin.require('replay_g').clip('choices:0');
|
clip('choices:0');
|
||||||
}
|
}
|
||||||
|
|
||||||
ai(time: number, frame: number): void {}
|
ai(time: number, frame: number): void {}
|
@ -1,5 +1,5 @@
|
|||||||
import { Transform, MotaOffscreenCanvas2D } from '@motajs/render';
|
import { Transform, MotaOffscreenCanvas2D } from '@motajs/render';
|
||||||
import { IStateDamageable } from '@/game/state/interface';
|
import { IStateDamageable } from '@user/data-state';
|
||||||
import { Hitbox, Projectile } from './barrage';
|
import { Hitbox, Projectile } from './barrage';
|
||||||
import type { PalaceBoss } from './palaceBoss';
|
import type { PalaceBoss } from './palaceBoss';
|
||||||
import { clamp } from '@motajs/legacy-ui';
|
import { clamp } from '@motajs/legacy-ui';
|
@ -21,11 +21,13 @@ import {
|
|||||||
ThunderBallProjectile,
|
ThunderBallProjectile,
|
||||||
ThunderProjectile
|
ThunderProjectile
|
||||||
} from './towerBossProjectile';
|
} from './towerBossProjectile';
|
||||||
import { IStateDamageable } from '@/game/state/interface';
|
import { IStateDamageable } from '@user/data-state';
|
||||||
import { Pop } from '../fx/pop';
|
import { Pop } from '../../../client-modules/src/render/legacy/pop';
|
||||||
import { WeatherController } from '@/module';
|
import { loading } from '@user/data-base';
|
||||||
|
import { clip } from '@user/legacy-plugin-data';
|
||||||
|
import { WeatherController } from '@user/client-modules';
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('coreInit', () => {
|
loading.once('coreInit', () => {
|
||||||
const shader = new Shader();
|
const shader = new Shader();
|
||||||
shader.size(480, 480);
|
shader.size(480, 480);
|
||||||
shader.setHD(true);
|
shader.setHD(true);
|
||||||
@ -198,7 +200,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
TowerBoss.effect.end();
|
TowerBoss.effect.end();
|
||||||
core.status.hero.hp = this.heroHp;
|
core.status.hero.hp = this.heroHp;
|
||||||
|
|
||||||
Mota.Plugin.require('replay_g').clip('choices:0');
|
clip('choices:0');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
@ -2,7 +2,7 @@ import { hyper, power, TimingFn } from 'mutate-animate';
|
|||||||
import { Hitbox, Projectile } from './barrage';
|
import { Hitbox, Projectile } from './barrage';
|
||||||
import { MotaOffscreenCanvas2D, Transform } from '@motajs/render';
|
import { MotaOffscreenCanvas2D, Transform } from '@motajs/render';
|
||||||
import type { TowerBoss } from './towerBoss';
|
import type { TowerBoss } from './towerBoss';
|
||||||
import { IStateDamageable } from '@/game/state/interface';
|
import { IStateDamageable } from '@user/data-state';
|
||||||
import { PointEffect, PointEffectType } from '../fx/pointShader';
|
import { PointEffect, PointEffectType } from '../fx/pointShader';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
|
|
@ -9,7 +9,12 @@ import {
|
|||||||
disableViewport,
|
disableViewport,
|
||||||
enableViewport
|
enableViewport
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import type { HeroMover, MoveStep } from '@/game/state/move';
|
import { loading } from '@user/data-base';
|
||||||
|
import {
|
||||||
|
heroMoveCollection,
|
||||||
|
type HeroMover,
|
||||||
|
type MoveStep
|
||||||
|
} from '@user/data-state';
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
|
|
||||||
export interface IChaseController {
|
export interface IChaseController {
|
||||||
@ -108,7 +113,7 @@ export class Chase extends EventEmitter<ChaseEvent> {
|
|||||||
const layer = render.getElementById('layer-main')! as LayerGroup;
|
const layer = render.getElementById('layer-main')! as LayerGroup;
|
||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
|
|
||||||
const mover = Mota.require('module', 'State').heroMoveCollection.mover;
|
const mover = heroMoveCollection.mover;
|
||||||
this.heroMove = mover;
|
this.heroMove = mover;
|
||||||
|
|
||||||
mover.on('stepEnd', this.onStepEnd);
|
mover.on('stepEnd', this.onStepEnd);
|
||||||
@ -345,7 +350,7 @@ export class Chase extends EventEmitter<ChaseEvent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('coreInit', () => {
|
loading.once('coreInit', () => {
|
||||||
const shader = new Shader();
|
const shader = new Shader();
|
||||||
Chase.shader = shader;
|
Chase.shader = shader;
|
||||||
shader.size(480, 480);
|
shader.size(480, 480);
|
@ -1,6 +1,6 @@
|
|||||||
import { Animation, hyper, linear, power, sleep } from 'mutate-animate';
|
import { Animation, hyper, linear, power, sleep } from 'mutate-animate';
|
||||||
import { Chase, ChaseData, IChaseController } from './chase';
|
import { Chase, ChaseData, IChaseController } from './chase';
|
||||||
import { completeAchievement } from '@motajs/legacy-ui';
|
// import { completeAchievement } from '@motajs/legacy-ui';
|
||||||
import {
|
import {
|
||||||
Camera,
|
Camera,
|
||||||
CameraAnimation,
|
CameraAnimation,
|
||||||
@ -10,7 +10,9 @@ import {
|
|||||||
Sprite
|
Sprite
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import { PointEffect, PointEffectType } from '../fx/pointShader';
|
import { PointEffect, PointEffectType } from '../fx/pointShader';
|
||||||
import { bgmController } from '@/module';
|
import { bgmController } from '@user/client-modules';
|
||||||
|
import { loading } from '@user/data-base';
|
||||||
|
import { chaseInit1, clip } from '@user/legacy-plugin-data';
|
||||||
|
|
||||||
const path: Partial<Record<FloorIds, LocArr[]>> = {
|
const path: Partial<Record<FloorIds, LocArr[]>> = {
|
||||||
MT16: [
|
MT16: [
|
||||||
@ -107,7 +109,7 @@ let back: Sprite | undefined;
|
|||||||
let contrastId: number = 0;
|
let contrastId: number = 0;
|
||||||
const effect = new PointEffect();
|
const effect = new PointEffect();
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('loaded', () => {
|
loading.once('loaded', () => {
|
||||||
effect.create(Chase.shader, 40);
|
effect.create(Chase.shader, 40);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -204,7 +206,7 @@ export function initChase(): IChaseController {
|
|||||||
core.removeFlag('chaseId');
|
core.removeFlag('chaseId');
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
completeAchievement('challenge', 0);
|
// completeAchievement('challenge', 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -215,7 +217,7 @@ export function initChase(): IChaseController {
|
|||||||
para3(chase, ani);
|
para3(chase, ani);
|
||||||
processScale(chase, ani, scale, camera);
|
processScale(chase, ani, scale, camera);
|
||||||
|
|
||||||
Mota.Plugin.require('chase_g').chaseInit1();
|
chaseInit1();
|
||||||
|
|
||||||
chase.on('end', () => {
|
chase.on('end', () => {
|
||||||
effect.end();
|
effect.end();
|
||||||
@ -712,7 +714,7 @@ function para3(chase: Chase, ani: Animation) {
|
|||||||
});
|
});
|
||||||
chase.onceLoc(21, 7, 'MT14', async () => {
|
chase.onceLoc(21, 7, 'MT14', async () => {
|
||||||
flags.finishChase1 = true;
|
flags.finishChase1 = true;
|
||||||
Mota.Plugin.require('replay_g').clip('choices:0');
|
clip('choices:0');
|
||||||
core.showStatusBar();
|
core.showStatusBar();
|
||||||
ani.time(750).apply('rect', 0);
|
ani.time(750).apply('rect', 0);
|
||||||
chase.end(true);
|
chase.end(true);
|
@ -1,5 +1,5 @@
|
|||||||
import { Animation, linear, sleep } from 'mutate-animate';
|
import { Animation, linear, sleep } from 'mutate-animate';
|
||||||
import { has } from '@motajs/legacy-ui';
|
// import { has } from '@motajs/legacy-ui';
|
||||||
|
|
||||||
// todo: 移植到渲染树
|
// todo: 移植到渲染树
|
||||||
|
|
||||||
@ -28,37 +28,37 @@ const FRAG_TIMING = linear();
|
|||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
return;
|
return;
|
||||||
Mota.rewrite(core.events, 'afterBattle', 'add', (_, enemy, x, y) => {
|
// Mota.rewrite(core.events, 'afterBattle', 'add', (_, enemy, x, y) => {
|
||||||
// 打怪特效
|
// // 打怪特效
|
||||||
const setting = Mota.require('var', 'mainSetting');
|
// const setting = Mota.require('var', 'mainSetting');
|
||||||
if (setting.getValue('fx.frag') && has(x) && has(y)) {
|
// if (setting.getValue('fx.frag') && has(x) && has(y)) {
|
||||||
const frame = core.status.globalAnimateStatus % 2;
|
// const frame = core.status.globalAnimateStatus % 2;
|
||||||
const canvas = document.createElement('canvas');
|
// const canvas = document.createElement('canvas');
|
||||||
canvas.width = 32;
|
// canvas.width = 32;
|
||||||
canvas.height = 32;
|
// canvas.height = 32;
|
||||||
core.drawIcon(canvas, enemy.id, 0, 0, 32, 32, frame);
|
// core.drawIcon(canvas, enemy.id, 0, 0, 32, 32, frame);
|
||||||
const manager = applyFragWith(canvas);
|
// const manager = applyFragWith(canvas);
|
||||||
const frag = manager.canvas;
|
// const frag = manager.canvas;
|
||||||
frag.style.imageRendering = 'pixelated';
|
// frag.style.imageRendering = 'pixelated';
|
||||||
frag.style.width = `${frag.width * core.domStyle.scale}px`;
|
// frag.style.width = `${frag.width * core.domStyle.scale}px`;
|
||||||
frag.style.height = `${frag.height * core.domStyle.scale}px`;
|
// frag.style.height = `${frag.height * core.domStyle.scale}px`;
|
||||||
const left =
|
// const left =
|
||||||
(x * 32 + 16 - frag.width / 2 - core.bigmap.offsetX) *
|
// (x * 32 + 16 - frag.width / 2 - core.bigmap.offsetX) *
|
||||||
core.domStyle.scale;
|
// core.domStyle.scale;
|
||||||
const top =
|
// const top =
|
||||||
(y * 32 + 16 - frag.height / 2 - core.bigmap.offsetY) *
|
// (y * 32 + 16 - frag.height / 2 - core.bigmap.offsetY) *
|
||||||
core.domStyle.scale;
|
// core.domStyle.scale;
|
||||||
frag.style.left = `${left}px`;
|
// frag.style.left = `${left}px`;
|
||||||
frag.style.top = `${top}px`;
|
// frag.style.top = `${top}px`;
|
||||||
frag.style.zIndex = '45';
|
// frag.style.zIndex = '45';
|
||||||
frag.style.position = 'absolute';
|
// frag.style.position = 'absolute';
|
||||||
frag.style.filter = 'sepia(20%)brightness(120%)';
|
// frag.style.filter = 'sepia(20%)brightness(120%)';
|
||||||
core.dom.gameDraw.appendChild(frag);
|
// core.dom.gameDraw.appendChild(frag);
|
||||||
manager.onEnd.then(() => {
|
// manager.onEnd.then(() => {
|
||||||
frag.remove();
|
// frag.remove();
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyFragWith(
|
export function applyFragWith(
|
1
packages-user/legacy-plugin-client/src/fx/index.ts
Normal file
1
packages-user/legacy-plugin-client/src/fx/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './pointShader';
|
3
packages-user/legacy-plugin-client/src/index.ts
Normal file
3
packages-user/legacy-plugin-client/src/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './boss';
|
||||||
|
export * from './chase';
|
||||||
|
export * from './fx';
|
8
packages-user/legacy-plugin-data/package.json
Normal file
8
packages-user/legacy-plugin-data/package.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "@user/legacy-plugin-data",
|
||||||
|
"dependencies": {
|
||||||
|
"@user/data-state": "workspace:*",
|
||||||
|
"@user/data-base": "workspace:*",
|
||||||
|
"@user/data-utils": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
///<reference path="../../../../src/types/core.d.ts" />
|
// @ts-nocheck
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
|
||||||
/* @__PURE__ */ (function () {
|
/* @__PURE__ */ (function () {
|
||||||
@ -55,8 +56,8 @@ export {};
|
|||||||
core.status.maps[data].enemy?.calRealAttribute();
|
core.status.maps[data].enemy?.calRealAttribute();
|
||||||
core.updateStatusBar(true, true);
|
core.updateStatusBar(true, true);
|
||||||
}
|
}
|
||||||
Mota.require('module', 'Shadow').Shadow.update(true);
|
Mota.require('@motajs/legacy-ui').Shadow.update(true);
|
||||||
const Binder = Mota.require('module', 'Render').LayerGroupFloorBinder;
|
const Binder = Mota.require('@motajs/render').LayerGroupFloorBinder;
|
||||||
Binder.activedBinder.forEach(v => {
|
Binder.activedBinder.forEach(v => {
|
||||||
if (v.getFloor() === core.status.floorId) {
|
if (v.getFloor() === core.status.floorId) {
|
||||||
v.updateBindData();
|
v.updateBindData();
|
@ -1,4 +1,4 @@
|
|||||||
import { has, ofDir } from '@/plugin/game/utils';
|
import { has, ofDir } from '@user/data-utils';
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
// 伤害弹出
|
// 伤害弹出
|
||||||
@ -11,11 +11,11 @@ export function init() {
|
|||||||
const damage = info?.damage;
|
const damage = info?.damage;
|
||||||
if (damage) {
|
if (damage) {
|
||||||
if (!main.replayChecking) {
|
if (!main.replayChecking) {
|
||||||
Mota.Plugin.require('pop_r').addPop(
|
// addPop(
|
||||||
(x - core.bigmap.offsetX / 32) * 32 + 12,
|
// (x - core.bigmap.offsetX / 32) * 32 + 12,
|
||||||
(y - core.bigmap.offsetY / 32) * 32 + 20,
|
// (y - core.bigmap.offsetY / 32) * 32 + 20,
|
||||||
(-damage).toString()
|
// (-damage).toString()
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
core.status.hero.hp -= damage;
|
core.status.hero.hp -= damage;
|
||||||
const type = [...info.type];
|
const type = [...info.type];
|
6
packages-user/legacy-plugin-data/src/enemy/index.ts
Normal file
6
packages-user/legacy-plugin-data/src/enemy/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { init as initCheckBlock } from './checkblock';
|
||||||
|
|
||||||
|
initCheckBlock();
|
||||||
|
|
||||||
|
export * from './checkblock';
|
||||||
|
export * from './remainEnemy';
|
720
packages-user/legacy-plugin-data/src/fallback.ts
Normal file
720
packages-user/legacy-plugin-data/src/fallback.ts
Normal file
@ -0,0 +1,720 @@
|
|||||||
|
import type {
|
||||||
|
RenderAdapter,
|
||||||
|
LayerDoorAnimate,
|
||||||
|
LayerGroupAnimate,
|
||||||
|
LayerFloorBinder,
|
||||||
|
HeroRenderer,
|
||||||
|
Layer,
|
||||||
|
LayerGroup,
|
||||||
|
FloorViewport
|
||||||
|
} from '@motajs/render';
|
||||||
|
import type { TimingFn } from 'mutate-animate';
|
||||||
|
import { BlockMover, heroMoveCollection, MoveStep } from '@user/data-state';
|
||||||
|
import { hook, loading } from '@user/data-base';
|
||||||
|
import { Patch, PatchClass } from '@motajs/legacy-common';
|
||||||
|
|
||||||
|
// 向后兼容用,会充当两个版本间过渡的作用
|
||||||
|
|
||||||
|
interface Adapters {
|
||||||
|
'hero-adapter'?: RenderAdapter<HeroRenderer>;
|
||||||
|
'door-animate'?: RenderAdapter<LayerDoorAnimate>;
|
||||||
|
animate?: RenderAdapter<LayerGroupAnimate>;
|
||||||
|
layer?: RenderAdapter<Layer>;
|
||||||
|
viewport?: RenderAdapter<FloorViewport>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const adapters: Adapters = {};
|
||||||
|
|
||||||
|
export function initFallback() {
|
||||||
|
let fallbackIds: number = 1e8;
|
||||||
|
|
||||||
|
if (!main.replayChecking && main.mode === 'play') {
|
||||||
|
const Adapter = Mota.require('@motajs/render').RenderAdapter;
|
||||||
|
const hero = Adapter.get<HeroRenderer>('hero-adapter');
|
||||||
|
const doorAnimate = Adapter.get<LayerDoorAnimate>('door-animate');
|
||||||
|
const animate = Adapter.get<LayerGroupAnimate>('animate');
|
||||||
|
const layer = Adapter.get<Layer>('layer');
|
||||||
|
const viewport = Adapter.get<FloorViewport>('viewport');
|
||||||
|
|
||||||
|
adapters['hero-adapter'] = hero;
|
||||||
|
adapters['door-animate'] = doorAnimate;
|
||||||
|
adapters['animate'] = animate;
|
||||||
|
adapters['layer'] = layer;
|
||||||
|
adapters['viewport'] = viewport;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<3> {
|
||||||
|
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, Math.ceil(y)];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Mota.r(() => {
|
||||||
|
// ----- 引入
|
||||||
|
const { Camera, MotaRenderer: Renderer } =
|
||||||
|
Mota.require('@motajs/render');
|
||||||
|
const Animation = Mota.require('MutateAnimate');
|
||||||
|
|
||||||
|
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 (data: any, x: number, y: number, prefix: any) {
|
||||||
|
if (core.canMoveHero()) {
|
||||||
|
var 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-ignore
|
||||||
|
core.status.hero.loc[name] = value;
|
||||||
|
if ((name === 'x' || name === 'y') && !noGather) {
|
||||||
|
core.control.gatherFollowers();
|
||||||
|
}
|
||||||
|
if (name === 'direction') {
|
||||||
|
adapters['hero-adapter']?.sync('turn', value);
|
||||||
|
adapters['hero-adapter']?.sync('setAnimateDir', value);
|
||||||
|
setHeroDirection(value as Dir);
|
||||||
|
} else if (name === 'x') {
|
||||||
|
// 为了防止逆天样板出问题
|
||||||
|
core.bigmap.posX = value as number;
|
||||||
|
adapters['hero-adapter']?.sync('setHeroLoc', value);
|
||||||
|
} else {
|
||||||
|
// 为了防止逆天样板出问题
|
||||||
|
core.bigmap.posY = value as number;
|
||||||
|
adapters['hero-adapter']?.sync('setHeroLoc', void 0, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
const img = core.material.images.images[name];
|
||||||
|
if (!img) return;
|
||||||
|
core.status.hero.image = name;
|
||||||
|
adapters['hero-adapter']?.sync('setImage', img);
|
||||||
|
});
|
||||||
|
|
||||||
|
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
|
||||||
|
) {
|
||||||
|
var block = core.getBlock(x, y);
|
||||||
|
core.saveAndStopAutomaticRoute();
|
||||||
|
if (!core.events._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;
|
||||||
|
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;
|
||||||
|
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 as AllIdsOf<'animates'>,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
patch2.add(
|
||||||
|
'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;
|
||||||
|
core.events._openDoor_animate(block, x, y, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//#region 动画
|
||||||
|
|
||||||
|
patch3.add(
|
||||||
|
'drawAnimate',
|
||||||
|
function (
|
||||||
|
name: AnimationIds,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
alignWindow?: boolean,
|
||||||
|
callback?: () => void
|
||||||
|
) {
|
||||||
|
// @ts-ignore
|
||||||
|
name = core.getMappedName(name);
|
||||||
|
|
||||||
|
// 正在播放录像:不显示动画
|
||||||
|
if (
|
||||||
|
core.isReplaying() ||
|
||||||
|
!core.material.animates[name] ||
|
||||||
|
x == null ||
|
||||||
|
y == null
|
||||||
|
) {
|
||||||
|
if (callback) 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-ignore
|
||||||
|
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);
|
||||||
|
|
||||||
|
const list = adapters.layer?.items ?? [];
|
||||||
|
const items = [...list].filter(v => {
|
||||||
|
if (v.layer !== 'event') return false;
|
||||||
|
const ex = v.getExtends('floor-binder') as LayerFloorBinder;
|
||||||
|
if (!ex) return false;
|
||||||
|
return ex.getFloor() === core.status.floorId;
|
||||||
|
});
|
||||||
|
const width = core.status.thisMap.width;
|
||||||
|
const index = sx + sy * width;
|
||||||
|
|
||||||
|
const promise = Promise.all(
|
||||||
|
items.map(v => {
|
||||||
|
return v.moveAs(index, ex, ey, fn, time, keep);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
core.updateStatusBar();
|
||||||
|
core.removeBlock(sx, sy);
|
||||||
|
await promise;
|
||||||
|
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;
|
||||||
|
|
||||||
|
const sx = core.getHeroLoc('x');
|
||||||
|
const sy = core.getHeroLoc('y');
|
||||||
|
adapters.viewport?.all('mutateTo', ex, ey, time);
|
||||||
|
|
||||||
|
const locked = core.status.lockControl;
|
||||||
|
core.lockControl();
|
||||||
|
const list = adapters['hero-adapter']?.items ?? [];
|
||||||
|
const items = [...list];
|
||||||
|
|
||||||
|
time /= core.status.replay.speed;
|
||||||
|
if (core.status.replay.speed === 24) time = 1;
|
||||||
|
const fn = generateJumpFn(ex - sx, ey - sy);
|
||||||
|
await Promise.all(
|
||||||
|
items.map(v => {
|
||||||
|
if (!v.renderable) return Promise.reject();
|
||||||
|
return v.layer.moveRenderable(
|
||||||
|
v.renderable,
|
||||||
|
sx,
|
||||||
|
sy,
|
||||||
|
fn,
|
||||||
|
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
|
||||||
|
) {
|
||||||
|
const main = Renderer.get('render-main');
|
||||||
|
const layer = main?.getElementById('layer-main') as LayerGroup;
|
||||||
|
if (!layer) return;
|
||||||
|
const camera = Camera.for(layer);
|
||||||
|
camera.clearOperation();
|
||||||
|
const translate = camera.addTranslate();
|
||||||
|
|
||||||
|
const animateTime =
|
||||||
|
time / Math.max(core.status.replay.speed, 1);
|
||||||
|
const animate = new Animation.Animation();
|
||||||
|
animate
|
||||||
|
.absolute()
|
||||||
|
.time(1)
|
||||||
|
.mode(Animation.linear())
|
||||||
|
.move(core.bigmap.offsetX, core.bigmap.offsetY);
|
||||||
|
animate.time(animateTime).move(x * 32, y * 32);
|
||||||
|
|
||||||
|
camera.applyTranslateAnimation(
|
||||||
|
translate,
|
||||||
|
animate,
|
||||||
|
animateTime + 50
|
||||||
|
);
|
||||||
|
camera.transform = layer.camera;
|
||||||
|
|
||||||
|
const end = () => {
|
||||||
|
core.bigmap.offsetX = x * 32;
|
||||||
|
core.bigmap.offsetY = y * 32;
|
||||||
|
camera.destroy();
|
||||||
|
callback?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
const timeout = window.setTimeout(end, animateTime + 50);
|
||||||
|
|
||||||
|
const id = fallbackIds++;
|
||||||
|
core.animateFrame.lastAsyncId = id;
|
||||||
|
core.animateFrame.asyncId[id] = () => {
|
||||||
|
end();
|
||||||
|
clearTimeout(timeout);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user