diff --git a/packages-user/client-modules/src/action/hotkey.ts b/packages-user/client-modules/src/action/hotkey.ts index f7e2517..04b124e 100644 --- a/packages-user/client-modules/src/action/hotkey.ts +++ b/packages-user/client-modules/src/action/hotkey.ts @@ -1,6 +1,5 @@ import { KeyCode } from '@motajs/client-base'; import { gameKey, HotkeyJSON } from '@motajs/system-action'; -import { hovered, mainUi, openDanmakuPoster } from '@motajs/legacy-ui'; import { GameStorage } from '@motajs/legacy-system'; export const mainScope = Symbol.for('@key_main'); @@ -92,16 +91,6 @@ gameKey name: '浏览地图_2', defaults: KeyCode.PageDown }) - .register({ - id: 'skillTree', - name: '技能树', - defaults: KeyCode.KeyJ - }) - .register({ - id: 'desc', - name: '百科全书', - defaults: KeyCode.KeyH - }) //#region 功能按键 .group('function', '功能按键') .register({ @@ -139,27 +128,6 @@ gameKey name: '轻按_2', defaults: KeyCode.Digit7 }) - .register({ - id: 'mark', - name: '标记怪物', - defaults: KeyCode.KeyM - }) - .register({ - id: 'special', - name: '鼠标位置怪物属性', - defaults: KeyCode.KeyE - }) - .register({ - id: 'critical', - name: '鼠标位置怪物临界', - defaults: KeyCode.KeyC - }) - .register({ - id: 'danmaku', - name: '发送弹幕', - defaults: KeyCode.KeyA, - ctrl: true - }) .register({ id: 'quickEquip_1', name: '切换/保存套装_1', @@ -524,12 +492,6 @@ gameKey .realize('shop', () => { core.openQuickShop(true); }) - .realize('skillTree', () => { - core.useItem('skill1', true); - }) - .realize('desc', () => { - core.useItem('I560', true); - }) .realize('undo', () => { core.doSL('autoSave', 'load'); }) @@ -542,31 +504,6 @@ gameKey .realize('getNext', () => { core.getNextItem(); }) - .realize('mark', () => { - const cls = hovered?.event.cls; - if (cls === 'enemys' || cls === 'enemy48') { - // const id = hovered!.event.id as EnemyIds; - // if (hasMarkedEnemy(id)) unmarkEnemy(id); - // else markEnemy(id); - } - }) - .realize('special', () => { - if (hovered) { - const { x, y } = hovered; - const enemy = core.status.thisMap.enemy.get(x, y); - if (enemy) mainUi.open('fixedDetail', { panel: 'special' }); - } - }) - .realize('critical', () => { - if (hovered) { - const { x, y } = hovered; - const enemy = core.status.thisMap.enemy.get(x, y); - if (enemy) mainUi.open('fixedDetail', { panel: 'critical' }); - } - }) - .realize('danmaku', () => { - openDanmakuPoster(); - }) .realize('restart', () => { core.confirmRestart(); }) diff --git a/packages-user/client-modules/src/fallback/audio.ts b/packages-user/client-modules/src/fallback/audio.ts index 7a14a14..b11a581 100644 --- a/packages-user/client-modules/src/fallback/audio.ts +++ b/packages-user/client-modules/src/fallback/audio.ts @@ -17,7 +17,8 @@ export function patchAudio() { }; patch.add('playBgm', function (bgm, startTime) { - play(bgm, startTime); + const name = core.getMappedName(bgm) as BgmIds; + play(name, startTime); }); patch.add('pauseBgm', function () { pause(); diff --git a/packages-user/client-modules/src/render/index.tsx b/packages-user/client-modules/src/render/index.tsx index da307a3..5798087 100644 --- a/packages-user/client-modules/src/render/index.tsx +++ b/packages-user/client-modules/src/render/index.tsx @@ -13,12 +13,13 @@ import { createWeather } from './weather'; export function createGameRenderer() { const App = defineComponent(_props => { return () => ( - + {sceneController.render()} ); }); + mainRenderer.setAntiAliasing(false); mainRenderer.hide(); createApp(App).mount(mainRenderer); diff --git a/packages-user/client-modules/src/render/legacy/halo.ts b/packages-user/client-modules/src/render/legacy/halo.ts deleted file mode 100644 index 6b4b0d9..0000000 --- a/packages-user/client-modules/src/render/legacy/halo.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { logger } from '@motajs/common'; -import { MotaOffscreenCanvas2D } from '@motajs/render'; -import { mainSetting } from '@motajs/legacy-ui'; -import { Sprite, Transform } from '@motajs/render'; -import { gameListener, hook } from '@user/data-base'; -import { - ILayerGroupRenderExtends, - LayerGroup, - LayerGroupFloorBinder -} from '../elements'; - -export class LayerGroupHalo implements ILayerGroupRenderExtends { - id: string = 'halo'; - - group!: LayerGroup; - binder!: LayerGroupFloorBinder; - halo!: Halo; - - static sprites: Set = new Set(); - - awake(group: LayerGroup): void { - this.group = group; - const ex = group.getExtends('floor-binder'); - if (ex instanceof LayerGroupFloorBinder) { - this.binder = ex; - this.halo = new Halo(); - this.halo.setHD(true); - this.halo.size(group.width, group.height); - this.halo.setZIndex(75); - this.halo.binder = ex; - group.appendChild(this.halo); - LayerGroupHalo.sprites.add(this.halo); - } else { - logger.error(1401); - group.removeExtends('halo'); - } - } - - onDestroy(_group: LayerGroup): void { - this.halo?.destroy(); - LayerGroupHalo.sprites.delete(this.halo); - } -} - -const haloColor: Record = { - 21: ['cyan'], - 25: ['purple'], - 26: ['blue'], - 27: ['red'], - 31: ['#3CFF49'], - 29: ['#51E9FF'], - 32: ['#fff966'] -}; - -class Halo extends Sprite { - /** 单元格大小 */ - cellSize: number = 32; - /** 当前楼层,用于获取有哪些光环 */ - binder!: LayerGroupFloorBinder; - - constructor() { - super('static', true); - - this.setRenderFn((canvas, transform) => { - this.drawHalo(canvas, transform); - }); - } - - drawHalo(canvas: MotaOffscreenCanvas2D, _transform: Transform) { - if (!mainSetting.getValue('screen.halo', true)) return; - const floorId = this.binder.getFloor(); - if (!floorId) return; - const col = core.status.maps[floorId].enemy; - if (!col) return; - const [dx, dy] = col.translation; - const list = col.haloList.concat( - Object.keys(flags[`melt_${floorId}`] ?? {}).map(v => { - const [x, y] = v.split(',').map(v => parseInt(v)); - return { - type: 'square', - data: { - x: x + dx, - y: y + dy, - d: 3 - }, - special: 25 - }; - }) - ); - const { ctx } = canvas; - const cell = this.cellSize; - ctx.lineWidth = 1; - for (const halo of list) { - if (halo.type === 'square') { - const { x, y, d } = halo.data; - let [color, border] = haloColor[halo.special]; - let alpha = 0.1; - let borderAlpha = 0.6; - const { mouseX, mouseY } = gameListener; - if (mouseX === halo.from?.x && mouseY === halo.from?.y) { - alpha = 0.3; - borderAlpha = 0.8; - color = '#ff0'; - border = '#ff0'; - } - const r = Math.floor(d / 2); - const left = x - r; - const top = y - r; - ctx.fillStyle = color; - ctx.strokeStyle = border ?? color; - ctx.globalAlpha = alpha; - ctx.fillRect(left * cell, top * cell, d * cell, d * cell); - ctx.globalAlpha = borderAlpha; - ctx.strokeRect(left * cell, top * cell, d * cell, d * cell); - } - } - } -} - -function updateHalo(block: Block) { - if (block.event.cls === 'enemys' || block.event.cls === 'enemy48') { - LayerGroupHalo.sprites.forEach(v => { - const floor = v.binder.getFloor(); - if (floor === core.status.floorId) { - v.update(); - } - }); - } -} - -hook.on('enemyExtract', col => { - LayerGroupHalo.sprites.forEach(v => { - const floor = v.binder.getFloor(); - if (col.floorId === floor) { - v.update(); - } - }); -}); -gameListener.on('hoverBlock', updateHalo); -gameListener.on('leaveBlock', updateHalo); diff --git a/packages-user/client-modules/src/render/ui/main.tsx b/packages-user/client-modules/src/render/ui/main.tsx index 2973282..058505c 100644 --- a/packages-user/client-modules/src/render/ui/main.tsx +++ b/packages-user/client-modules/src/render/ui/main.tsx @@ -38,7 +38,6 @@ import { ReplayingStatus } from './toolbar'; import { getHeroStatusOn } from '@user/data-state'; import { hook } from '@user/data-base'; import { FloorDamageExtends, FloorItemDetail } from '../elements'; -import { LayerGroupHalo } from '../legacy/halo'; import { FloorChange } from '../legacy/fallback'; import { mainUIController } from './controller'; import { @@ -57,7 +56,6 @@ const MainScene = defineComponent(() => { const layerGroupExtends: ILayerGroupRenderExtends[] = [ new FloorDamageExtends(), new FloorItemDetail(), - new LayerGroupHalo(), new LayerGroupAnimate(), new FloorViewport() ]; @@ -252,7 +250,12 @@ const MainScene = defineComponent(() => { }; return () => ( - + { onClick={clickMap} onDown={downMap} onMove={moveMap} + noanti > diff --git a/packages-user/client-modules/src/render/ui/settings.tsx b/packages-user/client-modules/src/render/ui/settings.tsx index 795c0a2..452c895 100644 --- a/packages-user/client-modules/src/render/ui/settings.tsx +++ b/packages-user/client-modules/src/render/ui/settings.tsx @@ -127,7 +127,7 @@ export const MainSettings = defineComponent(props => { choices={choices} width={POP_BOX_WIDTH} onChoose={choose} - maxHeight={MAIN_HEIGHT - 64} + maxHeight={MAIN_HEIGHT - 32} interval={8} scope={scope} /> diff --git a/packages-user/client-modules/src/render/ui/viewmap.tsx b/packages-user/client-modules/src/render/ui/viewmap.tsx index 052ad7a..adf29b1 100644 --- a/packages-user/client-modules/src/render/ui/viewmap.tsx +++ b/packages-user/client-modules/src/render/ui/viewmap.tsx @@ -31,7 +31,6 @@ import { LayerGroup, LayerGroupFloorBinder } from '../elements'; -import { LayerGroupHalo } from '../legacy/halo'; import { Font } from '@motajs/render-style'; import { clamp, mean } from 'lodash-es'; import { calculateStatisticsOne, StatisticsDataOneFloor } from './statistics'; @@ -65,7 +64,6 @@ export const ViewMap = defineComponent(props => { const layerGroupExtends: ILayerGroupRenderExtends[] = [ new FloorDamageExtends(), new FloorItemDetail(), - new LayerGroupHalo(), new LayerGroupAnimate() ]; diff --git a/packages/legacy-ui/src/components/index.ts b/packages/legacy-ui/src/components/index.ts index d8700d7..5c95dfa 100644 --- a/packages/legacy-ui/src/components/index.ts +++ b/packages/legacy-ui/src/components/index.ts @@ -2,5 +2,4 @@ export { default as Box } from './box.vue'; export { default as BoxAnimate } from './boxAnimate.vue'; export { default as Column } from './colomn.vue'; export { default as EnemyOne } from './enemyOne.vue'; -export { default as Minimap } from './minimap.vue'; export { default as Scroll } from './scroll.vue'; diff --git a/packages/legacy-ui/src/components/minimap.vue b/packages/legacy-ui/src/components/minimap.vue deleted file mode 100644 index 186d3d3..0000000 --- a/packages/legacy-ui/src/components/minimap.vue +++ /dev/null @@ -1,176 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/danmaku.ts b/packages/legacy-ui/src/danmaku.ts deleted file mode 100644 index 6324956..0000000 --- a/packages/legacy-ui/src/danmaku.ts +++ /dev/null @@ -1,488 +0,0 @@ -import { EventEmitter } from 'eventemitter3'; -import { logger } from '@motajs/common'; -import { ResponseBase } from '@motajs/client-base'; -import axios, { AxiosResponse, toFormData } from 'axios'; -import { VNode, h, shallowReactive } from 'vue'; -import { ensureArray, parseCss } from './utils'; -import { deleteWith } from '@motajs/legacy-common'; -import { tip } from './use'; -// /* @__PURE__ */ import { id, password } from '../../../../user'; - -type CSSObj = Partial>; - -interface DanmakuResponse extends ResponseBase { - total: number; - list: DanmakuInfo[]; -} - -interface DanmakuInfo { - id: string; - comment: string; - tags: string; - love: string; - my_love_type: boolean; - userid: string; - deler: string; - upload_time: string; - tower_name: string; -} - -interface DanmakuPostInfo extends Partial { - type: 1 | 2 | 3; - towername: 'HumanBreak'; - id?: number; -} - -interface DanmakuContentInfo { - comment: string; - tags: string; -} - -interface PostDanmakuResponse extends ResponseBase { - id: number; -} - -interface PostLikeResponse extends ResponseBase { - liked: boolean; -} - -interface DanmakuEvent { - showStart: [danmaku: Danmaku]; - showEnd: [danmaku: Danmaku]; - like: [liked: boolean, danmaku: Danmaku]; -} - -type SpecContentFn = (content: string, type: string) => VNode; - -interface AllowedCSS { - property: string; - check: (value: string, prop: string) => true | string; -} - -const allowedCSS: Partial> = { - color: { - property: 'color', - check: () => true - }, - backgroundColor: { - property: 'backgroundColor', - check: () => true - }, - fontSize: { - property: 'fontSize', - check: value => { - if (!/^\d+%$/.test(value)) { - return '字体大小只能设置为百分格式'; - } - if (parseInt(value) > 200) { - return '字体最大只能为200%'; - } - return true; - } - } -}; - -export class Danmaku extends EventEmitter { - static backend: string = `/backend/tower/barrage.php`; - static all: Set = new Set(); - static allInPos: Partial>> = - {}; - - static showList: Danmaku[] = shallowReactive([]); - static showMap: Map = new Map(); - static specList: Record = {}; - - static lastEditoredDanmaku?: Danmaku; - - id: number = -1; - text: string = ''; - x: number = 0; - y: number = 0; - floor?: FloorIds; - showing: boolean = false; - likedNum: number = 0; - liked: boolean = false; - - style: CSSObj = {}; - textColor: string = 'white'; - strokeColor: string = 'black'; - - private posted: boolean = false; - vNode?: VNode; - private posting: boolean = false; - - /** - * 发送弹幕 - * @returns 弹幕发送的 Axios Post 信息,为 Promise - */ - async post(): Promise> { - if (this.posted || this.posting) { - logger.warn(5); - return Promise.reject(); - } - - const data: DanmakuPostInfo = { - type: 2, - towername: 'HumanBreak', - ...this.encode() - }; - - this.posting = true; - const form = toFormData(data); - // /* @__PURE__ */ form.append('userid', id); - // /* @__PURE__ */ form.append('password', password); - - try { - const res = await axios.post( - Danmaku.backend, - form - ); - - this.id = res.data.id; - this.posting = false; - - if (res.data.code === 0) { - this.posted = true; - tip('success', '发送成功'); - this.addToList(); - } else { - tip('error', res.data.message); - } - - return res; - } catch (e) { - this.posted = false; - this.posting = false; - logger.error(1, String(e)); - return Promise.reject(); - } - } - - /** - * 将弹幕整合为可以发送的格式 - */ - encode(): DanmakuContentInfo { - const css = this.getEncodedCSS(); - return { - comment: this.text, - tags: JSON.stringify([ - `!css:${JSON.stringify(css)}`, - `!pos:${this.x},${this.y},${this.floor}` - ]) - }; - } - - /** - * 解析弹幕信息 - * @param info 要被解析的弹幕信息 - */ - decode(info: DanmakuContentInfo) { - this.text = info.comment; - - ensureArray(JSON.parse(info.tags) as string[]).forEach(v => { - if (v.startsWith('!css:')) { - this.style = JSON.parse(v.slice(5)); - } else if (v.startsWith('!pos:')) { - const [x, y, f] = v.slice(5).split(','); - this.x = parseInt(x); - this.y = parseInt(y); - this.floor = f as FloorIds; - } else { - logger.warn(3, v); - } - }); - } - - getEncodedCSS() { - const css = JSON.parse(JSON.stringify(this.style)) as CSSObj; - if (!css.color) css.color = this.textColor; - if (!css.textShadow) - css.textShadow = `1px 1px 1px ${this.strokeColor}, 1px -1px 1px ${this.strokeColor}, -1px 1px 1px ${this.strokeColor}, -1px -1px 1px ${this.strokeColor}`; - return { ...css, ...this.style }; - } - - /** - * 设置文字的颜色 - * @param fill 填充颜色 - * @param stroke 描边颜色 - */ - color(fill?: string, stroke?: string) { - if (fill) this.textColor = fill; - if (stroke) this.strokeColor = stroke; - } - - /** - * 添加一个图标 - * @param icon 要显示的图标id - */ - addIcon(icon: AllIds) { - this.text += `[i:${icon}]`; - } - - /** - * 设置这个弹幕整体的css信息 - * @param str css字符串 - * @param overwrite 是否完全覆写原来的css - */ - css(str: string, overwrite?: boolean): void; - /** - * 设置这个弹幕整体的css信息 - * @param str css对象,参考 CSSStyleDeclaration - * @param overwrite 是否完全覆写原来的css - */ - css(obj: CSSObj, overwrite?: boolean): void; - css(obj: string | CSSObj, overwrite: boolean = false) { - const res = typeof obj === 'string' ? parseCss(obj) : obj; - const allow = Danmaku.checkCSSAllow(res); - if (allow.length === 0) { - if (overwrite) this.style = res; - else { - this.style = { ...this.style, ...res }; - } - } else { - logger.error(8, allow.join(',')); - } - } - - /** - * 将这个弹幕添加至弹幕列表 - */ - addToList() { - Danmaku.all.add(this); - if (!this.floor) return; - Danmaku.allInPos[this.floor] ??= {}; - Danmaku.allInPos[this.floor]![`${this.x},${this.y}`] ??= []; - Danmaku.allInPos[this.floor]![`${this.x},${this.y}`].push(this); - } - - /** - * 解析这个弹幕为 VNode - */ - parse() { - let pointer = -1; - let ignore = false; - - let str = ''; - - let spec = false; - let specType = ''; - let specTypeEnd = false; - let specContent = ''; - - const children: VNode[] = []; - - while (++pointer < this.text.length) { - const char = this.text[pointer]; - - if (char === '\\' && !ignore) { - ignore = true; - continue; - } - - if (ignore) { - str += char; - continue; - } - - if (char === '[') { - spec = true; - children.push(h('span', str)); - str = ''; - continue; - } - - if (char === ']') { - if (!spec) { - logger.warn(4); - str += char; - } else { - spec = false; - specTypeEnd = false; - children.push(this.createSpecVNode(specType, specContent)); - specType = ''; - specContent = ''; - } - continue; - } - - if (spec) { - if (!specTypeEnd) { - if (char !== ':') { - specType += char; - } else { - specTypeEnd = true; - } - } else { - specContent += char; - } - continue; - } - - str += char; - } - - if (str.length > 0) { - children.push(h('span', str)); - } - - return h( - 'span', - { class: 'danmaku', style: this.getEncodedCSS() }, - children - ); - } - - /** - * 获取本弹幕的VNode - */ - getVNode(nocache: boolean = false) { - if (nocache) return (this.vNode = this.parse()); - return this.vNode ?? (this.vNode = this.parse()); - } - - /** - * 显示这个弹幕 - */ - show() { - if (this.showing) return; - this.showing = true; - Danmaku.showList.push(this); - Danmaku.showMap.set(this.id, this); - this.emit('showStart', this); - } - - /** - * 显示结束这个弹幕 - */ - showEnd() { - if (!this.showing) return; - this.showing = false; - deleteWith(Danmaku.showList, this); - Danmaku.showMap.delete(this.id); - this.emit('showEnd', this); - } - - /** - * 点赞或取消点赞 - */ - async triggerLike() { - const post: DanmakuPostInfo = { - type: 3, - towername: 'HumanBreak', - id: this.id - }; - - const form = toFormData(post); - // /* @__PURE__ */ form.append('userid', id); - // /* @__PURE__ */ form.append('password', password); - - const res = await axios.post(Danmaku.backend, form); - if (res.data.code !== 0) { - logger.warn(18, this.id.toString()); - tip('error', `Error ${res.data.code}. ${res.data.message}`); - } else { - tip('success', res.data.message); - - if (res.data.liked) { - this.liked = true; - this.likedNum++; - } else { - this.liked = false; - this.likedNum--; - } - this.emit('like', this.liked, this); - } - - return res; - } - - /** - * 销毁这个弹幕 - */ - destroy() { - this.showEnd(); - Danmaku.all.delete(this); - if (this.floor) { - const floor = Danmaku.allInPos[this.floor]; - if (floor) { - delete floor[`${this.x},${this.y}`]; - } - } - } - - private createSpecVNode(type: string, content: string): VNode { - if (Danmaku.specList[type]) { - return Danmaku.specList[type](content, type); - } else { - logger.warn(7, type); - } - - return h('span'); - } - - /** - * 检查CSS内容是否符合发弹幕要求 - * @param css 要检查的CSS内容 - */ - static checkCSSAllow(css: CSSObj) { - const problem: string[] = []; - for (const [key, value] of Object.entries(css)) { - if (!allowedCSS[key as CanParseCss]) { - problem.push(`不允许的CSS:${key}`); - continue; - } else { - const res = allowedCSS[key as CanParseCss]!.check(value, key); - if (res !== true) { - problem.push(res); - } - } - } - - return problem; - } - - /** - * 拉取本塔所有弹幕 - */ - static async fetch() { - Danmaku.all.clear(); - Danmaku.allInPos = {}; - const form = toFormData({ - type: 1, - towername: 'HumanBreak' - }); - // /* @__PURE__ */ form.append('userid', id); - // /* @__PURE__ */ form.append('password', password); - const data = await axios.post(Danmaku.backend, form); - - data.data.list.forEach(v => { - const dan = new Danmaku(); - dan.id = parseInt(v.id); - dan.likedNum = parseInt(v.love); - dan.liked = v.my_love_type; - dan.decode(v); - dan.posted = true; - dan.addToList(); - }); - } - - /** - * 显示一个弹幕 - * @param dan 要显示的弹幕 - */ - static show(dan: Danmaku) { - dan.show(); - } - - /** - * 注册一个特殊显示内容 - * @param type 特殊内容类型 - * @param fn 特殊内容显示函数,返回VNode - */ - static registerSpecContent(type: string, fn: SpecContentFn) { - if (this.specList[type]) { - logger.warn(6, type); - } - this.specList[type] = fn; - } -} diff --git a/packages/legacy-ui/src/data/achievement.json b/packages/legacy-ui/src/data/achievement.json deleted file mode 100644 index 9e27d59..0000000 --- a/packages/legacy-ui/src/data/achievement.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "normal": [ - { - "name": "虚惊一场", - "text": ["打完山洞门口的兽人后只剩一滴血"], - "point": 30 - }, - { - "name": "真能刷", - "text": [ - "勇气之路的刷血怪刷到 15w 以上的血" - ], - "point": 30 - } - ], - "challenge": [ - { - "name": "逃出生天", - "text": ["通过山路追逐战的困难难度"], - "point": 20 - }, - { - "name": "冰与火之舞", - "text": ["完成第二章音游特殊战的困难难度"], - "point": 50 - } - ], - "explore": [ - { - "name": "勇气巅峰", - "text": ["第一章完成度达到100%"], - "progress": "${Mota.require('completion_r').getChapterCompletion(1)} / 100", - "percent": true, - "point": 50 - }, - { - "name": "你是怎么办到的?!", - "text": ["与山路上的若干个神秘木牌对话"], - "progress": "${core.getLocalStorage('mountSign', 0)} / 5", - "hide": "该探索成就需要你自己探索如何达成", - "point": 25 - }, - { - "name": "智慧之心", - "text": ["第二章完成度达到100%"], - "progress": "${Mota.require('completion_r').getChapterCompletion(2)} / 100", - "percent": true, - "point": 50 - }, - { - "name": "源头?", - "text": [ - "在冰封雪原第一个山洞的水源处使用跳跃技能,并向前一步触发剧情" - ], - "hide": "该探索成就需要你自己探索如何达成", - "point": 30 - }, - { - "name": "学坏了", - "text": ["学习电摇嘲讽技能"], - "hide": "该探索成就需要你自己探索如何达成", - "point": 20 - }, - { - "name": "满腹经纶", - "text": ["把第二章中所有能学习的技能都学一遍"], - "hide": "该探索成就需要你自己探索如何达成", - "progress": "", - "point": 50 - } - ] -} diff --git a/packages/legacy-ui/src/data/desc.json b/packages/legacy-ui/src/data/desc.json deleted file mode 100644 index d90807f..0000000 --- a/packages/legacy-ui/src/data/desc.json +++ /dev/null @@ -1,523 +0,0 @@ -{ - "tip": { - "text": "注意事项", - "condition": "true", - "desc": [ - "这里显示本塔中需要注意的事项。", - "
", - "
", - "1. ", - "本百科全书字数很多,可以选择性地阅读。不过本条目最好可以全部阅读一遍。", - "
", - "
", - "2. 本百科全书的内容会随着游戏的推进而增加新内容,", - "同时每次增加新内容时都会有提示。", - "
", - "
", - "3. 背包中的系统设置同样非常重要,有些问题可以在那里找到原因。", - "例如当你获得技能时可能会发现开启不了技能,", - "就是因为你打开了自动切换技能的功能,在系统设置里面有说。", - "
", - "
", - "4. 重要!!!本塔没有考虑录像的二次播放性,", - "这意味着如果你从头播放一个录像,播放完成后继续游玩,提交成绩后不能保证绿录像,请谨慎考虑。", - "
", - "
", - "5. 本塔中几乎所有 ui 都可以纵向滚动,如果发现显示不全,", - "可以尝试上下拖动,就像浏览网页一样。电脑端还可以使用滚轮上下滚动。", - "大部分可以纵向滚动的 ui 都会在右方有一个滚动条,也可以拖动它进行滚动,例如本百科全书的条目列表和", - "条目说明都是可以通过上述方式滚动的。", - "
", - "
", - "6. 本塔主要面向电脑端设计,", - "建议使用电脑游玩以获得更好的游戏体验,同时使用约16:9的比例游玩更加合适", - "。但是手机依然可以游玩本塔,", - "但部分操作可能不是很方便,ui 也可能不是很美观,不过依然可以完整体验本游戏。", - "
", - "
", - "7. 对于手机端,可以点击右下角的难度文字来切换工具栏至数字键。", - "这样,你可以更加方便地进行使用技能等操作。", - "
", - "
", - "8. 本塔中几乎所有 ui 在打开时都会有一个0.6s的动画,如果不想要,可以在开头捡的系统设置里面关闭(默认关闭)。", - "同时,几乎所有 ui 的退出按钮都在左上角。", - "
", - "
", - "9. 地图上显示的怪物临界有可能不准,当其与折线图有差异时,请以折线图为准。" - ] - }, - "about": { - "text": "关于游戏", - "condition": "true", - "desc": [ - "使用样板:Vite 魔塔样板", - "
", - "样板版本:V2.10.0", - "
", - "游戏版本:V1.0.0-alpha", - "
", - "游戏作者:古祠", - "
", - "游戏开源地址:", - "https://github.com/unanmed/HumanBreak", - "
", - "本塔遵循MIT开源协议。查看开源协议", - "
", - "音乐来源:网易云音乐等", - "
", - "素材来源:大素材库、爱给网、网站素材库等", - "
", - "特别说明:素材与音乐均来自网络,不得用于商业用途,仅用于参考与学习", - "
", - "特别鸣谢(排名不分先后):", - "
", - "1. 无名甲烷菌(提供部分特殊属性与机制想法)", - "
", - "测试(排名不分先后):", - "
", - "1. 永葆一颗童心", - "
", - "2. 影法师", - "
", - "3. 夜战天明889", - "
", - "4. 霸道的老鼠" - ] - }, - "tutorial": { - "text": "新手教程", - "condition": "true", - "desc": [ - "本条目是魔塔游戏的新手教程,如果对魔塔有一定的了解,可以直接忽略。", - "
", - "
", - "魔塔是一种固定数值rpg游戏,在打怪的时候,遵循我打你一下,你打我一下", - "的原则,造成的伤害是己方攻击减去对方防御,最后怪物的伤害便是你在战斗中失去的生命值。当然,为了游戏体验,", - "战斗过程会被省略。", - "
", - "
", - "宝石可以增加你的属性,在大部分魔塔中,红宝石增加攻击,蓝宝石增加防御,本塔也不例外。血瓶可以增加你的生命值。", - "一般情况下,拾取宝物的优先级是红宝石 > 蓝宝石 > 血瓶,", - "但部分情况可能不是这样,这需要你自己的游玩经验等。", - "
", - "
", - "本塔还拥有升级机制,升级时能够给你增加大量的属性,因此,一般情况下当你接近升级时,需要尽快打怪升级。", - "
", - "
", - "然后是门。在魔塔中,很多门都不是必开的门,它们的作用一般是可以躲开怪物拿宝石,或者门里面有血瓶等。", - "当你血量足够时,这些门可以不用开,不然可能会有必开的门无法开启导致卡关。对于钥匙,每种颜色的钥匙开对应颜色的门,", - "价值是红 > 蓝 > 黄。", - "
", - "
", - "为了更加方便,本塔增加了宝石血瓶显示数据的功能,这样你可以清晰地知道每个宝石增加了多少属性。", - "
", - "
", - "下面是勇士基础属性的说明:", - "
", - "1. 生命值:", - "勇士的血量,当它归零时,游戏结束", - "
", - "2. 攻击:", - "勇士的攻击,攻击越高,每回合对怪物造成的伤害越高", - "
", - "3. 防御:", - "勇士的防御,防御越高,怪物每回合对你造成的伤害越低", - "
", - "4. 经验:", - "勇士的经验,到达一定值后会升级。本塔在状态栏中显示为距离升级剩余的经验", - "
", - "5. 金币:", - "勇士的金币,可以用于购买物品。本塔中在进入第二章后会有用", - "
", - "6. 护盾:", - "勇士的护盾,用处是能够在战后减少同等数值的伤害,在本塔中可以使伤害变为负值。本塔中,在点开无上之盾技能后,", - "智慧会充当护盾。更多信息可以查看“勇士属性”条目。" - ] - }, - "noun": { - "text": "名词解释", - "condition": "true", - "desc": [ - "本条目会解释诸如临界等魔塔术语,对魔塔有一定了解的可以直接忽略。", - "
", - "
", - "1. 临界:", - "在魔塔中,临界是一个非常重要的东西。首先,我们很容易可以得到,吃攻击时只有当减少了战斗回合数时怪物的伤害会减少,", - "那么,吃攻击时怪物的减伤是不连续的。而距离下一次减少怪物的伤害需要加的攻击的量", - "便是临界。当我们吃一个攻击恰好使怪物伤害减少时,称为“踩临界”。一般情况下,踩临界的减伤要比吃防御要高,", - "因此,当能踩到临界时,我们应当先踩临界,再吃防御。", - "
", - "
", - "2. 加防:", - "加防指的是加防对怪物的减伤。在本塔中,会以“n防”的形式显示在怪物手册或其他地方。在本塔中,一般你不需要刻意计算", - "临界与加防减伤,你可以在怪物手册中查看减伤折线图,", - "更多信息请查看“怪物手册”条目。", - "
", - "
", - "3. 咸鱼:", - "一般来讲,开不必开的门,或者使用不必使用的道具被称为咸鱼,或者是咸门,咸道具。一般情况下,说“咸”便是指咸鱼。", - "一般情况下,门后面有宝石且无法通过其他方式进入的都是必开门,而只有血瓶的都是咸鱼门。" - ] - }, - "shortcut": { - "text": "快捷键", - "condition": "true", - "desc": [ - "这里包含本塔中所有的快捷键。对于手机端,可以点击工具栏的难度的位置切换工具栏至数字键。", - "下面会分为样板快捷键和本塔快捷键两类分别说明。可以ctrl+F进行搜索快捷键的功能。", - "
", - "
", - "下面是样板中的所有快捷键:", - "
", - "X:打开怪物手册", - "
", - "S:打开存档界面", - "
", - "D:打开读档界面", - "
", - "A或5:读取自动存档", - "
", - "W或6:撤销读取的自动存档", - "
", - "Q:打开装备栏", - "
", - "T:打开道具栏", - "
", - "G:打开楼层传送器", - "
", - "Z或单击勇士:勇士转向", - "
", - "空格或双击勇士或7:轻按(拾取勇士周围的宝物但不移动勇士)", - "
", - "Esc:打开游戏菜单", - "
", - "R:打开录像回放菜单", - "
", - "N:询问是否返回游戏主菜单", - "
", - "V:打开快捷商店", - "
", - "B:打开数据统计界面", - "
", - "Alt + 数字键:快速换装", - "
", - "PgUp或PgDn:浏览地图", - "
", - "P:打开评论区", - "
", - "
", - "下面是本塔中新增的快捷键(不包括技能,技能快捷键请在查看技能界面中查看):", - "
", - "M:快速标记怪物", - "
", - "J:打开技能树", - "
", - "H:打开百科全书", - "
", - "E:查看鼠标位置怪物的特殊属性信息", - "
", - "C:查看鼠标位置怪物的详细临界信息" - ] - }, - "extraAttr": { - "text": "勇士属性", - "condition": "true", - "desc": [ - "这里只对本塔中新增的勇士属性进行说明。", - "
", - "
", - "1. 智慧:", - "智慧是该塔的核心属性之一。智慧可用于智慧加点,该功能会在进入第一章后开启。使用智慧可以点技能树。", - "除此之外,智慧也有其它功能。例如点开无上之盾技能后智慧还可以充当护盾,第二章点开学习技能后可以使用智慧学习怪物技能等。", - "
", - "
", - "2. 生命回复:", - "生命回复指的是勇士每回合回复的生命值。当与怪物战斗时,勇士每回合都会回复对应量的生命值。因此,当吃攻击时,", - "与怪物战斗的回合数可能会减少,导致生命回复的总回复量减少。不过大部分情况下不需要在意这一点,", - "减少一回合并不会对吸的血造成很大的影响,除了一些特殊情况。", - "该项会显示在状态栏的生命值右方偏下的位置。该项不会超过勇士防御的十分之一,如果真实值溢出,那么多余部分会忽略,", - "当防御提高时,其值会一同改变", - "
", - "
", - "3. 额外攻击:", - "额外攻击指的是勇士每回合的额外造成的伤害。一般情况下,当勇士破了怪物的防御时,该项便会起作用。", - "额外攻击相当于魔攻,无法通过一般方式减免。当勇士攻击怪物时,每回合都会附加对应量的伤害,对坚固怪同样有效。", - "额外攻击会显示在状态栏的攻击右方偏下的位置。" - ] - }, - "statusBar": { - "text": "状态栏", - "condition": "true", - "desc": [ - "在本塔中,状态栏与游戏画面是分开的。你可以自由拖动状态栏,也可以修改其大小。", - "具体方法如下:点击一下状态栏之后,左上角的拖拽图标会放大,此时你可以按住它拖动状态栏。", - "你可以直接将鼠标放到状态栏的边框上,然后直接拖动以改变状态栏的大小。手机端可以先点击一下状态栏使边框", - "变宽,然后拖动。电脑端点击状态栏也可以使边框变宽。如果你想折叠状态栏,完全可以拖动状态栏的下边框,", - "然后直接拖动至上方,这时状态栏便会变成一条线,相当于折叠了状态栏", - "
", - "
", - "状态栏可以纵向滚动,", - "如果你发现状态栏显示不全,可以尝试拉大状态栏,或者纵向拖动状态栏,就像网页上下滚动一样。", - "电脑端还可以使用滚轮上下滚动。", - "
", - "
", - "如果你觉得状态栏有些碍事,你完全可以将其缩小,或者把它放到不碍事的地方。", - "
", - "
", - "状态栏上面可能会有按钮,你可以直接点击。", - "
", - "
", - "对状态栏布局的说明。", - "
", - "本塔的状态栏的布局较为灵活。它是横向的布局,在状态栏较宽时可以看到,属性会横向依次显示。按照显示顺序,", - "状态栏显示项依次为:", - "
", - "
", - "1. 楼层名,点击后进入浏览地图界面", - "
", - "2. 勇士等级", - "
", - "3. 当前开启的技能", - "
", - "4. 当前勇士生命值,右方偏下为每回合回复的生命值", - ",当点开治愈之泉技能时,右方偏上会显示距离增加生命回复剩余血瓶数", - "
", - "5. 当前勇士的攻击,右方偏下为勇士的额外攻击", - "
", - "6. 当前勇士的防御,当有魔法防御时,右方偏下为勇士的魔法防御", - "
", - "7. 当前勇士的智慧,可以用于智慧加点等", - "
", - "8. 当前勇士的金币", - "
", - "9. 当前勇士距离升级剩余经验数", - "
", - "10. 三色钥匙", - "
", - "11. 打开技能树(进入第一章后开启)", - "
", - "12. 查看勇士的技能(进入第一章后开启)" - ] - }, - "markEnemy": { - "text": "标记怪物", - "condition": "true", - "desc": [ - "标记怪物可以使你能够更加方便地了解一个怪物的情况。", - "
", - "你可以通过以下两种方式标记怪物:", - "
", - "1. 打开怪物手册,选中怪物,进入怪物更多信息栏,点击标记怪物。", - "
", - "2. 将鼠标移动到你想要标记的怪物上面,", - "按下M键,即可标记怪物,注意浏览地图中不能用该方式标记。", - "手机端暂时没有快速标记怪物的方式。", - "
", - "
", - "当一个怪物被标记后,怪物会有以下行为:", - "
", - "1. 当勇士恰好能打败怪物时,会进行提示", - "
", - "2. 当怪物的伤害恰好低于勇士生命值的2/3或1/3时,会进行提示", - "
", - "3. 当勇士恰好踩到怪物的临界时,会进行提示", - "
", - "4. 当怪物零伤时,会进行提示", - "
", - "5. 被标记的怪物会出现类似于状态栏的盒子,可以随意拖动和改变大小。你也可以选择关闭这个盒子,", - "被关闭后可以通过重新标记来打开。这个盒子会显示标记的怪物的临界与伤害信息等,与状态栏一样,可以纵向滚动。", - "
", - "
", - "这个功能可以用于标记boss或者较强的挡路怪,当这些怪能够攻击时你可以直接收到信息,不需要再时刻费心注意怪物的伤害。", - "
", - "
", - "注意,标记的怪物是不计入存档的,同时标记的怪物只在本次游戏中有效,刷新页面后便会消失。" - ] - }, - "book": { - "text": "怪物手册", - "condition": "true", - "desc": [ - "本塔的怪物手册功能很多,下面一一介绍。", - "
", - "
", - "首先,你可以按X打开怪物手册。除此之外,将鼠标移动到怪物上也可以定点查看怪物的粗略信息。", - "将鼠标移动到一个怪物上,按下", - "E键,可以查看该怪物的特殊属性信息。按下", - "C键,可以查看该怪物的详细临界信息。", - "
", - "
", - "怪物手册打开的时候有一个0.6秒的动画,如果不想要可以在开头捡的系统设置里面关闭(默认关闭)。", - "
", - "
", - "打开怪物手册后,怪物手册的布局与样板自带的类似。与样板不同的是,这里的怪物手册不再是翻页式结构。", - "这里的怪物手册是滚动式结构,", - "你可以像浏览网页一样,用手指或鼠标上下滚动或者拖动右边的滚动条,电脑端还可以使用滚轮。", - "对于电脑端,还可以使用键盘操作。上和下可以上下选择怪物,左和右可以向上或向下移动5个怪物。这些操作与样板都类似。", - "
", - "
", - "点击一个怪物或者按下回车空格后,将进入怪物详细信息界面。这个界面分为多个栏,分别是特殊属性栏,详细临界栏,更多信息栏。", - "进入怪物详细信息后默认在特殊属性栏,该栏可以查看怪物的特殊属性。", - "注意特殊属性依然可以纵向滚动。在特殊属性下方,", - "是怪物的临界表,可以粗略地查看怪物的临界信息。在下方,你可以点击详细临界信息进入详细临界栏。", - "
", - "
", - "在详细临界栏中,怪物的伤害会以可视化折线图的方式显示出来,", - "从而你可以更为清晰地看出怪物减伤趋势。", - "除了查看怪物伤害曲线,你还可以规划宝石。每个折线图下方都有一个滑动条,你可以拖动来模拟吃宝石。", - "注意,拖动时,滑动条左边会显示当前的加攻或加防次数,这个数值指的是在勇士所在地图中需要吃的最弱的宝石数量。", - "例如,当前勇士所在地图中最弱的宝石加2点攻击,加攻次数为3,那么勇士的攻击增加量就为6。", - "勇士增加的攻击数值也会在下方显示。当加攻次数和加防次数改变时,折线图也会变化。", - "当前状态下怪物的伤害以及减伤总量也会在下方显示。", - "注意在此栏中无法通过点击屏幕回到怪物手册界面,更多信息请查看最后一段。", - "
", - "
", - "在特殊属性栏,点击下方的怪物更多信息可以进入更多信息栏。此栏中,你可以查看怪物描述。但这不是这一栏的核心功能。", - "这一栏的核心功能是标记怪物。被标记的怪物会有一些非常方便的行为,这些行为可以在“", - "标记怪物”条目中查看。", - "
", - "
", - "注意,在怪物详细信息中,除详细临界栏外均可以通过点击屏幕返回到怪物手册界面。", - "如果你是电脑端,在任意栏目中按下X键会退出怪物手册,返回游戏,", - "按下回车(Enter)键会回到怪物手册界面。" - ] - }, - "fly": { - "text": "楼层传送器", - "condition": "true", - "desc": [ - "楼传界面打开时会有一个0.6秒的动画,如果不想要可以在开头捡的系统设置里面关闭。(默认关闭)", - "
", - "
", - "本塔的楼层传送器是一个集分区、小地图、楼层传送、浏览地图于一体的多功能楼传。", - "你也可以点击这里查看所有区域的缩略图。", - "下面是楼传的具体说明:", - "
", - "
", - "首先,对于电脑端,最左侧显示区域信息,手机端则在上方的左侧。", - "
", - "
", - "然后,区域的右侧是小地图栏,这一栏会显示楼层的平面结构。你可以拖动,也可以使用滚轮或者双指放缩,当放缩到一定大小时,", - "会显示地图的缩略图。直接点击地图也可以选中地图,再次点击会传送至目标地图。", - "
", - "
", - "对于电脑端,最右侧是当前选中的地图的缩略图,手机则在下方,点击缩略图也可以传送。缩略图的下方是当前选中的地图名,", - "左右各有两个按钮,表示后退10层、后退1层、前进1层、前进10层,与样板的楼传的按钮功能类似,对于小地图无法显示的单层,", - "可以使用该功能到达。", - "
", - "
", - "最下方是设置按钮,可以切换无边框模式,电脑端还可以切换传统按键模式,传统按键模式下按键遵循样板的楼传按键方式。", - "对于非传统模式,上下左右可以移动地图,", - "PageUp和PageDown可以前进1层或后退1层。" - ] - }, - "tools": { - "text": "道具栏与装备栏", - "condition": "true", - "desc": [ - "道具栏与装备栏打开时会有一个0.6秒的动画,如果不想要可以在开头捡的系统设置里面关闭。(默认关闭)", - "
", - "
", - "本塔的道具栏没有特别之处,这里不需要说明。主要是装备栏。", - "
", - "
", - "本塔的装备栏手机和电脑端不同,电脑端比手机端多了一个勇士属性的显示。在装备栏的装备列表栏,", - "上方有两个选择框与一个排序方式的选项。", - "这三个可以筛选你拥有的装备并进行排序,从而让你能够更清楚地知道哪个装备更强。", - "第一个选择框可以筛选装备增加的属性,如果装备不增加选择的属性,那么会不显示。第二个选择框可以筛选增加的属性的方式,", - "有数值增加和百分比增加两种。在这个选择框右边有一个图标,这个图标可以改变武器的排序方式,有升序和降序两种,默认为升序。", - "例如,你拥有两个装备,分别增加10攻击和20攻击,三者你分别选择了攻击,数值,升序,那么增加10攻击的装备会排在上面,", - "而增加20攻击的装备会排在下面。", - "
", - "
", - "对于电脑端,如果你想装装备,可以直接拖动装备至装备孔,", - "也可以选中装备后再次点击。手机端暂时无法拖动装备。当选中一个装备后,", - "电脑端和手机端均会显示装备增加或减少的属性,注意有的装备可能不增加属性但是有特殊功能。", - "对于电脑端,还会直接在勇士属性栏显示增加或减少的属性。" - ] - }, - "achievement": { - "text": "成就", - "condition": "true", - "desc": [ - "成就系统是本塔的一个独立系统。它不会像勇士属性一样跟随存档变化,而是只要你完成了成就,那么就永远完成了,", - "除非你清理了浏览器。每个成就都有成就点,成就点目前没有实际用途,", - "只是一个收集要素,对游戏进程没有任何影响。", - "
", - "
", - "成就分为三种,普通成就,挑战成就和探索成就。普通成就完成难度一般较低,挑战成就完成难度较高,", - "而探索成就一般需要你自己探索如何完成。对于完成度类型的探索成就,它的完成度由到达过的地图与本章完成的成就数决定。", - "
", - "
", - "调试模式下无法完成成就!" - ] - }, - "score": { - "text": "计分方式", - "condition": "true", - "desc": [ - "第一章计分方式:血量 + 黄 * 5000 + 蓝 * 15000", - "
", - "第二章计分方式:血量 / 10 + 黄 * 2000 + 蓝 * 5000 + 红 * 10000" - ] - }, - "skillTree": { - "text": "技能树", - "condition": "flags.chapter > 0", - "desc": [ - "打开技能树可以点击状态栏的", - "技能树按钮(如果发现没有显示可以尝试上下滚动状态栏),还可以按", - "快捷键J打开。", - "
", - "
", - "技能树是本塔的主要玩法之一。它可以让你使用智慧来学习技能,增加属性等。智慧在状态栏显示在防御的下一项,", - "绿宝石可以增加勇士的智慧。", - "
", - "
", - "打开技能树页面后,你可以在上方看到技能的名称与描述,下方会显示技能树,以及升级要求等。点击一个技能可以选中技能,", - "再次点击可以升级技能。注意,前置技能栏可以上下滚动,因此如果发现显示不全,可以尝试上下滚动前置技能栏", - "
", - "
", - "注意,技能在点开之后是无法取消的,因此,加点时请慎重加点。注意,部分技能是必点技能,这些技能会在技能说明中明确指出,", - "这些技能一般需要尽早点出。" - ] - }, - "special1": { - "text": "第一章怪物特技", - "condition": "flags.chapter > 0", - "desc": [ - "这里会展示第一章的怪物中需要特别说明的怪物特技。", - "
", - "
", - "1. 坚固:", - "在本塔中,额外攻击可以对坚固怪造成额外伤害。", - "
", - "
", - "2. 绝对防御:", - "该怪物一般可以用于刷血。该怪物可以使你每回合对怪物造成的伤害恰好为1,导致战斗回合数很高,因此可以刷血。", - "
", - "
", - "3. 致命一击、勇气之刃、勇气冲锋:", - "造成的伤害为怪物每回合对勇士的伤害的一定倍数,而非攻击提高一定倍数。" - ] - }, - "special2": { - "text": "第二章怪物特技", - "condition": "flags.chapter > 1", - "desc": [ - "这里会展示第二章的怪物中需要特别说明的怪物特技。", - "
", - "
", - "1. 电摇嘲讽:", - "该特技会撞碎路上的所有地形和门,不需要消耗钥匙,拾取路上的所有道具,与路上的怪物战斗,最后与该怪物战斗。", - "如果怪物所在位置可以被嘲讽,那么勇士会被继续嘲讽。如果在被嘲讽的路上可以被其他怪物嘲讽,则不会触发。", - "如果一个点可以被多个怪物嘲讽,那么会优先选择最靠左上角的怪物。在地图上会标记出勇士的移动方向。", - "在被嘲讽之前会自动存档。", - "
", - "
", - "2. 永夜极昼:", - "战斗后会在本楼层中加减怪物与勇士的攻防,每个楼层会单独存储。例如你在1楼层增加了100点攻击,2楼层减少了100点攻击,", - "那么当你从2楼层到1楼层时,攻击会增加200点,反之亦然。注意这里没有计算buff。" - ] - } -} \ No newline at end of file diff --git a/packages/legacy-ui/src/data/skill.json b/packages/legacy-ui/src/data/skill.json deleted file mode 100644 index f50b20e..0000000 --- a/packages/legacy-ui/src/data/skill.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "none": { - "text": "无", - "opened": "true", - "desc": [ - "当前未选择技能" - ] - }, - "blade": { - "text": "1:断灭之刃", - "opened": "true", - "desc": [ - "快捷键1,开启后勇士攻击增加${level:2 * 10}%,", - "同时防御减少${level:2 * 10}%。", - "
", - "
", - "当前等级:${level:2}" - ] - }, - "jump": { - "text": "2:跳跃", - "opened": "true", - "desc": [ - "快捷键2,消耗200点生命值,困难消耗400点,一个地图只能使用3次,", - "如果前方为可通行的地面,则不能使用该技能,如果前方为怪物,则将怪物移至勇士视线上第一个不能通行的方块后", - "如果前方为障碍物,则直接跳到该障碍物的后方。", - "
", - "
", - "进入第二章后不再消耗生命值。" - ] - }, - "shield": { - "text": "3:铸剑为盾", - "opened": "true", - "desc": [ - "快捷键3,开启后勇士防御增加${level:10 * 10}%,", - "同时攻击减少${level:10 * 10}%。", - "
", - "
", - "当前等级:${level:10}" - ] - } -} \ No newline at end of file diff --git a/packages/legacy-ui/src/data/tips.json b/packages/legacy-ui/src/data/tips.json deleted file mode 100644 index 73d0b62..0000000 --- a/packages/legacy-ui/src/data/tips.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - "按下C可以查看鼠标位置怪物临界", - "按下E可以查看鼠标位置怪物的详细属性", - "将鼠标移动到光环怪上以查看其产生的光环", - "字体太大?试试在背包的系统设置里面调整字体大小吧!", - "字体太小?试试在背包的系统设置里面调整字体大小吧!", - "按键不合心意?试试在背包的系统设置里面自定义快捷键", - "拖动状态栏左上角可以移动状态栏哦!", - "拖动状态栏右下角可以缩放状态栏哦!", - "按下M键,鼠标位置的怪物的信息就会被你看光啦!", - "咱就是说,要不要试一下工具栏的最后一个按钮?", - "要不要试试工具栏倒数第二个按钮呢?", - "想自定义工具栏?去背包的系统设置看看吧!", - "冷知识:临界界面可以拖动滚动条来查看减伤情况", - "可以用滚轮或者双指缩放小地图!", - "楼传的最左侧一栏可以选择区域!", - "冷知识:装备栏左栏最上面可以修改装备排序", - "冷冷冷知识:装备栏左栏最上面右侧可以更改顺序或倒序", - "第一章使用跳跃技能可是要扣血的!要注意!", - "按H查看本游戏的百科全书", - "给别人炫耀一下自己的成就点吧!虽然不能记榜(", - "抱团属性会在怪物右上角显示加成数量!", - "乾坤挪移属性会在怪物左上角显示“乾”字!", - "电脑端可以试试按F11全屏游玩!", - "手机端要不试试横屏玩?", - "不在楼梯边也可以使用楼传!", - "技能树的右下角可以切换章节!", - "开启自动切换技能就会自动帮你选择最优技能了!", - "魔塔不仅有撤回,还有恢复,按W或6就可以了!", - "觉得卡顿?可以去试着设置里面关闭一些特性!", - "从第二章开始,怪物负伤害量不会超过其生命的1/4", - "生命回复不会超过防御的十分之一", - "不想看小贴士?设置里面可以关掉!", - "不小心进入了追猎范围?读取自动存档撤回到进入前吧!", - "不小心进入了电摇嘲讽范围?读取自动存档撤回到进入前吧!", - "小地图出现卡顿?试试在背包中系统设置里把小地图懒更新打开吧!" -] \ No newline at end of file diff --git a/packages/legacy-ui/src/fx/index.ts b/packages/legacy-ui/src/fx/index.ts deleted file mode 100644 index 3f94642..0000000 --- a/packages/legacy-ui/src/fx/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './webgl'; diff --git a/packages/legacy-ui/src/fx/webgl.ts b/packages/legacy-ui/src/fx/webgl.ts deleted file mode 100644 index 23cc414..0000000 --- a/packages/legacy-ui/src/fx/webgl.ts +++ /dev/null @@ -1,288 +0,0 @@ -import { ensureArray } from '../utils'; -import { sleep } from 'mutate-animate'; -import { logger } from '@motajs/common'; -import { tip } from '../use'; - -const { gl, gl2 } = checkSupport(); - -function checkSupport() { - const canvas = document.createElement('canvas'); - const canvas2 = document.createElement('canvas'); - const gl = canvas.getContext('webgl'); - const gl2 = canvas2.getContext('webgl2'); - if (!gl) { - sleep(3000).then(() => { - tip( - 'warning', - `您的浏览器不支持WebGL,大部分效果将会无法显示,请更新你的浏览器` - ); - }); - } - if (!gl2) { - sleep(3000).then(() => { - tip( - 'warning', - `您的浏览器不支持WebGL2,大部分效果将会无法显示,请更新你的浏览器` - ); - }); - } - return { gl: !!gl, gl2: !!gl2 }; -} - -export function isWebGLSupported() { - return gl; -} - -export function isWebGL2Supported() { - return gl2; -} - -export type WebGLColorArray = [number, number, number, number]; - -interface WebGLShaderInfo { - vertex: WebGLShader; - fragment: WebGLShader; -} - -type UniformBinderNum = 1 | 2 | 3 | 4; -type UniformBinderType = 'f' | 'i'; -type UniformFunc< - N extends UniformBinderNum, - T extends UniformBinderType, - V extends 'v' | '' -> = `uniform${N}${T}${V}`; - -type UniformBinderValue = N extends 1 - ? number - : N extends 2 - ? [number, number] - : N extends 3 - ? [number, number, number] - : [number, number, number, number]; - -interface UniformBinder< - N extends UniformBinderNum, - T extends UniformBinderType, - V extends 'v' | '' -> { - value: UniformBinderValue; - set(value: UniformBinderValue): void; - get(): UniformBinderValue; -} - -abstract class WebGLBase { - abstract canvas: HTMLCanvasElement; - abstract gl: WebGLRenderingContext | WebGL2RenderingContext; - - background: WebGLColorArray = [0, 0, 0, 0]; - - vsSource: string = ''; - fsSource: string = ''; - - program: WebGLProgram | null = null; - shader: WebGLShaderInfo | null = null; - - resetCanvas() { - this.gl.clearColor(...this.background); - this.gl.clear(this.gl.COLOR_BUFFER_BIT); - } - - setSize(width: number, height: number) { - this.canvas.width = width; - this.canvas.height = height; - } - - compile() { - const gl = this.gl; - gl.deleteProgram(this.program); - gl.deleteShader(this.shader?.vertex ?? null); - gl.deleteShader(this.shader?.fragment ?? null); - - this.program = this.createProgram(); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); - gl.useProgram(this.program); - } - - vs(vs: string) { - this.vsSource = vs; - } - - fs(fs: string) { - this.fsSource = fs; - } - - /** - * 创建一个全局变量绑定器,用于操作全局变量 - * @param uniform 全局变量的变量名 - * @param num 变量的元素数量,float和int视为1,vec2 vec3 vec4分别视为 2 3 4 - * @param type 数据类型,可以填'f',表示浮点型,或者填'i',表示整型 - * @param vector 是否为向量,可以填'v',表示是向量,或者填'',表示不是向量 - * @returns 一个uniform绑定器,用于操作全局变量uniform - */ - createUniformBinder< - N extends UniformBinderNum, - T extends UniformBinderType, - V extends 'v' | '' - >(uniform: string, num: N, type: T, vector: V): UniformBinder { - if (!this.program) { - throw new Error( - `Uniform binder should be use when the program initialized.` - ); - } - - const suffix = `${num}${type}${vector ? 'v' : ''}`; - const func = `uniform${suffix}` as UniformFunc; - const value = ( - num === 1 ? 0 : Array(num).fill(0) - ) as UniformBinderValue; - - const loc = this.gl.getUniformLocation(this.program, uniform); - const gl = this.gl; - - return { - value, - set(value) { - this.value = value; - let v; - if (vector === 'v') { - let _v = ensureArray(value); - if (type === 'f') { - v = new Float32Array(_v); - } else { - v = new Int32Array(_v); - } - } else { - v = ensureArray(value); - } - // 对uniform赋值 - if (vector === 'v') { - // @ts-ignore - gl[func](loc, v); - } else { - // @ts-ignore - gl[func](loc, ...v); - } - }, - get() { - return this.value; - } - }; - } - - protected createProgram() { - const gl = this.gl; - const vs = this.loadShader(gl.VERTEX_SHADER, this.vsSource); - const fs = this.loadShader(gl.FRAGMENT_SHADER, this.fsSource); - - this.shader = { - vertex: vs, - fragment: fs - }; - - const program = gl.createProgram()!; - gl.attachShader(program, vs); - gl.attachShader(program, fs); - gl.linkProgram(program); - - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - logger.error(9, gl.getProgramInfoLog(program) ?? ''); - } - - return program; - } - - protected loadShader(type: number, source: string) { - const gl = this.gl; - const shader = gl.createShader(type)!; - gl.shaderSource(shader, source); - gl.compileShader(shader); - - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - throw new Error( - `Cannot compile ${ - type === gl.VERTEX_SHADER ? 'vertex' : 'fragment' - } shader. Error info: ${gl.getShaderInfoLog(shader)}` - ); - } - - return shader; - } -} - -export class WebGLCanvas extends WebGLBase { - canvas: HTMLCanvasElement; - gl: WebGLRenderingContext; - - constructor(canvas?: HTMLCanvasElement) { - super(); - this.canvas = canvas ?? document.createElement('canvas'); - this.gl = this.canvas.getContext('webgl')!; - } -} - -export class WebGL2Canvas extends WebGLBase { - canvas: HTMLCanvasElement; - gl: WebGL2RenderingContext; - - constructor(canvas?: HTMLCanvasElement) { - super(); - this.canvas = canvas ?? document.createElement('canvas'); - this.gl = this.canvas.getContext('webgl2')!; - } - - vs(vs: string): void { - if (!vs.startsWith('#version 300 es')) { - this.vsSource = `#version 300 es\n` + vs; - } else { - this.vsSource = vs; - } - } - - fs(fs: string): void { - if (!fs.startsWith('#version 300 es')) { - this.fsSource = `#version 300 es\n` + fs; - } else { - this.vsSource = fs; - } - } -} - -export function loadShader( - gl: WebGLRenderingContext, - type: number, - source: string -) { - const shader = gl.createShader(type)!; - gl.shaderSource(shader, source); - gl.compileShader(shader); - - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - logger.error( - 10, - type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', - gl.getShaderInfoLog(shader) ?? '' - ); - } - - return shader; -} - -export function createProgram( - gl: WebGLRenderingContext, - vsSource: string, - fsSource: string -) { - const vs = loadShader(gl, gl.VERTEX_SHADER, vsSource); - const fs = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); - - const program = gl.createProgram()!; - gl.attachShader(program, vs); - gl.attachShader(program, fs); - gl.linkProgram(program); - - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - logger.error(9, gl.getProgramInfoLog(program) ?? ''); - } - - return program; -} diff --git a/packages/legacy-ui/src/index.ts b/packages/legacy-ui/src/index.ts index 898957b..d5453e5 100644 --- a/packages/legacy-ui/src/index.ts +++ b/packages/legacy-ui/src/index.ts @@ -8,12 +8,8 @@ export * as UI from './ui'; export * as Components from './components'; export * from './preset'; export * from './tools'; -export * from './fx'; - export * from './animateController'; export * from './controller'; -export * from './danmaku'; -// export * from './mark'; export * from './setting'; export * from './use'; export * from './utils'; diff --git a/packages/legacy-ui/src/preset/danmaku.ts b/packages/legacy-ui/src/preset/danmaku.ts deleted file mode 100644 index 20932b1..0000000 --- a/packages/legacy-ui/src/preset/danmaku.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Danmaku } from '../danmaku'; -import { Component, h } from 'vue'; -import { mainSetting } from './settingIns'; -import { getIconHeight } from '../utils'; -import { BoxAnimate } from '../components'; - -// 图标类型 -Danmaku.registerSpecContent('i', content => { - const height = getIconHeight(content as AllIds); - - return h(BoxAnimate as Component, { - id: content, - noborder: true, - noAnimate: true, - width: 32, - height - }); -}); - -if (import.meta.env.DEV) { - Danmaku.backend = `/danmaku`; -} - -export function createDanmaku() { - const { hook } = Mota.require('@user/data-base'); - - hook.once('reset', () => { - Danmaku.fetch(); - }); - - // 勇士移动后显示弹幕 - hook.on('moveOneStep', (x, y, floor) => { - const enabled = mainSetting.getValue('ui.danmaku', true); - if (!enabled) return; - const f = Danmaku.allInPos[floor]; - if (f) { - const danmaku = f[`${x},${y}`]; - if (danmaku) { - danmaku.forEach(v => { - setTimeout(() => { - v.show(); - }, Math.random() * 1000); - }); - } - } - }); -} diff --git a/packages/legacy-ui/src/preset/fixed.ts b/packages/legacy-ui/src/preset/fixed.ts deleted file mode 100644 index d196f01..0000000 --- a/packages/legacy-ui/src/preset/fixed.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { debounce } from 'lodash-es'; -import { ref } from 'vue'; -import { sleep } from 'mutate-animate'; - -const close = ref(false); - -let cx = 0; -let cy = 0; - -/** - * 显示定点查看 - */ -const showFixed = debounce((block: Block) => { - const e = core.material.enemys[block.event.id as EnemyIds]; - if (!e) return; - const enemy = core.status.thisMap.enemy.get(block.x, block.y); - if (!enemy) return; - const { fixedUi } = Mota.require('@motajs/legacy-ui'); - fixedUi.open( - 'fixed', - { enemy, close, loc: [cx, cy], hovered }, - { close: closeFixed } - ); -}, 200); - -/** - * 关闭定点查看 - */ -const closeFixed = () => { - close.value = true; - sleep(200).then(() => { - const { fixedUi } = Mota.require('@motajs/legacy-ui'); - fixedUi.closeByName('fixed'); - close.value = false; - }); -}; - -// todo: 应当在这里实现查看临界与特殊属性的功能 -export let hovered: Block | null; - -export function createFixed() { - const { hook, gameListener } = Mota.require('@user/data-base'); - - gameListener.on('hoverBlock', block => { - closeFixed(); - hovered = block; - }); - gameListener.on('leaveBlock', (_, __, leaveGame) => { - showFixed.cancel(); - if (!leaveGame) closeFixed(); - hovered = null; - }); - gameListener.on('mouseMove', e => { - cx = e.clientX; - cy = e.clientY; - showFixed.cancel(); - if (hovered) { - showFixed(hovered); - } - }); - - hook.once('mounted', () => { - const { mainUi } = Mota.require('@motajs/legacy-ui'); - mainUi.on('start', () => { - showFixed.cancel(); - closeFixed(); - }); - }); -} diff --git a/packages/legacy-ui/src/preset/index.ts b/packages/legacy-ui/src/preset/index.ts index 8b00c2e..9d0f50b 100644 --- a/packages/legacy-ui/src/preset/index.ts +++ b/packages/legacy-ui/src/preset/index.ts @@ -1,18 +1,12 @@ -import { createDanmaku } from './danmaku'; -import { createFixed } from './fixed'; import { createSetting, createUI } from './ui'; export function createPreset() { - createDanmaku(); - createFixed(); createUI(); createSetting(); } export * from './ui'; export * from './settings'; -export * from './danmaku'; -export * from './fixed'; export * from './keyboard'; export * from './uiIns'; export * from './settingIns'; diff --git a/packages/legacy-ui/src/preset/uiIns.ts b/packages/legacy-ui/src/preset/uiIns.ts index ff82705..4c76d98 100644 --- a/packages/legacy-ui/src/preset/uiIns.ts +++ b/packages/legacy-ui/src/preset/uiIns.ts @@ -8,26 +8,13 @@ mainUi.register( new GameUi('toolbox', UI.Toolbox), new GameUi('equipbox', UI.Equipbox), new GameUi('settings', UI.Settings), - new GameUi('desc', UI.Desc), - new GameUi('skill', UI.Skill), - new GameUi('skillTree', UI.SkillTree), new GameUi('fly', UI.Fly), - new GameUi('fixedDetail', UI.FixedDetail), new GameUi('shop', UI.Shop), - // new GameUi('achievement', UI.Achievement), new GameUi('hotkey', UI.Hotkey), new GameUi('virtualKey', VirtualKey) ); mainUi.showAll(); export const fixedUi = new UiController(true); -fixedUi.register( - new GameUi('fixed', UI.Fixed), - new GameUi('chapter', UI.Chapter), - new GameUi('start', UI.Start), - new GameUi('load', UI.Load), - new GameUi('danmaku', UI.Danmaku), - new GameUi('danmakuEditor', UI.DanmakuEditor), - new GameUi('tips', UI.Tips) -); +fixedUi.register(new GameUi('load', UI.Load)); fixedUi.showAll(); diff --git a/packages/legacy-ui/src/tools/index.ts b/packages/legacy-ui/src/tools/index.ts index aa0ab0f..462345c 100644 --- a/packages/legacy-ui/src/tools/index.ts +++ b/packages/legacy-ui/src/tools/index.ts @@ -1,8 +1,3 @@ -// import { init } from './achievement'; - -// init(); - -// export * from './achievement'; export * from './book'; export * from './common'; export * from './equipbox'; diff --git a/packages/legacy-ui/src/ui/chapter.vue b/packages/legacy-ui/src/ui/chapter.vue deleted file mode 100644 index abf1428..0000000 --- a/packages/legacy-ui/src/ui/chapter.vue +++ /dev/null @@ -1,143 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/danmaku.vue b/packages/legacy-ui/src/ui/danmaku.vue deleted file mode 100644 index 9743d8e..0000000 --- a/packages/legacy-ui/src/ui/danmaku.vue +++ /dev/null @@ -1,225 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/danmakuEditor.vue b/packages/legacy-ui/src/ui/danmakuEditor.vue deleted file mode 100644 index 66aeb52..0000000 --- a/packages/legacy-ui/src/ui/danmakuEditor.vue +++ /dev/null @@ -1,671 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/desc.vue b/packages/legacy-ui/src/ui/desc.vue deleted file mode 100644 index 0f7e96c..0000000 --- a/packages/legacy-ui/src/ui/desc.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/fixed.vue b/packages/legacy-ui/src/ui/fixed.vue deleted file mode 100644 index 4deea64..0000000 --- a/packages/legacy-ui/src/ui/fixed.vue +++ /dev/null @@ -1,174 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/fixedDetail.vue b/packages/legacy-ui/src/ui/fixedDetail.vue deleted file mode 100644 index 2c7f5ac..0000000 --- a/packages/legacy-ui/src/ui/fixedDetail.vue +++ /dev/null @@ -1,47 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/index.ts b/packages/legacy-ui/src/ui/index.ts index a247b63..e40b40e 100644 --- a/packages/legacy-ui/src/ui/index.ts +++ b/packages/legacy-ui/src/ui/index.ts @@ -1,19 +1,9 @@ export { default as Book } from './book.vue'; export { default as BookDetail } from './bookDetail.vue'; -export { default as Chapter } from './chapter.vue'; -export { default as Desc } from './desc.vue'; export { default as Equipbox } from './equipbox.vue'; -export { default as Fixed } from './fixed.vue'; -export { default as FixedDetail } from './fixedDetail.vue'; export { default as Fly } from './fly.vue'; export { default as Settings } from './settings.vue'; export { default as Shop } from './shop.vue'; -export { default as Skill } from './skill.vue'; -export { default as SkillTree } from './skillTree.vue'; -export { default as Start } from './start.vue'; export { default as Toolbox } from './toolbox.vue'; export { default as Hotkey } from './hotkey.vue'; export { default as Load } from './load.vue'; -export { default as Danmaku } from './danmaku.vue'; -export { default as DanmakuEditor } from './danmakuEditor.vue'; -export { default as Tips } from './tips.vue'; diff --git a/packages/legacy-ui/src/ui/skill.vue b/packages/legacy-ui/src/ui/skill.vue deleted file mode 100644 index 869752b..0000000 --- a/packages/legacy-ui/src/ui/skill.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/skillTree.vue b/packages/legacy-ui/src/ui/skillTree.vue deleted file mode 100644 index 7429691..0000000 --- a/packages/legacy-ui/src/ui/skillTree.vue +++ /dev/null @@ -1,449 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/start.vue b/packages/legacy-ui/src/ui/start.vue deleted file mode 100644 index 5028177..0000000 --- a/packages/legacy-ui/src/ui/start.vue +++ /dev/null @@ -1,670 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/ui/tips.vue b/packages/legacy-ui/src/ui/tips.vue deleted file mode 100644 index 4ad3e6c..0000000 --- a/packages/legacy-ui/src/ui/tips.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - - - diff --git a/packages/legacy-ui/src/uiUtils.ts b/packages/legacy-ui/src/uiUtils.ts index dd94220..73ad75b 100644 --- a/packages/legacy-ui/src/uiUtils.ts +++ b/packages/legacy-ui/src/uiUtils.ts @@ -1,6 +1,6 @@ import { KeyCode } from '@motajs/client-base'; import { KeyboardEmits, Keyboard, isAssist } from '@motajs/system-action'; -import { mainUi, fixedUi } from './preset/uiIns'; +import { mainUi } from './preset/uiIns'; /** * 唤起虚拟键盘,并获取到一次按键操作 @@ -39,9 +39,3 @@ export function getVitualKeyOnce( }); }); } - -export function openDanmakuPoster() { - if (!fixedUi.hasName('danmakuEditor')) { - fixedUi.open('danmakuEditor'); - } -} diff --git a/public/project/floors/empty.js b/public/project/floors/empty.js index ae6e75b..9cbe420 100644 --- a/public/project/floors/empty.js +++ b/public/project/floors/empty.js @@ -11,7 +11,7 @@ main.floors.empty= "images": [], "ratio": 1, "defaultGround": "ground", - "bgm": "bgm.mp3", + "bgm": "bgm.opus", "firstArrive": [], "eachArrive": [], "parallelDo": "", diff --git a/public/project/floors/sample0.js b/public/project/floors/sample0.js index 1c9f095..3ed3c80 100644 --- a/public/project/floors/sample0.js +++ b/public/project/floors/sample0.js @@ -8,7 +8,7 @@ main.floors.sample0= "canUseQuickShop": true, "defaultGround": "ground", "images": [], - "bgm": "bgm.mp3", + "bgm": "bgm.opus", "ratio": 1, "map": [ [ 0, 0,220, 0, 0, 20, 87, 3, 58, 59, 60, 61, 64],