mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-02-28 17:37:07 +08:00
feat: 跟进 2.A 的更改
This commit is contained in:
parent
0dfb7e4b99
commit
86e6e76286
@ -9,3 +9,4 @@ public/_server/**/*.js
|
|||||||
script/**/*.js
|
script/**/*.js
|
||||||
public/editor.html
|
public/editor.html
|
||||||
keyCodes.ts
|
keyCodes.ts
|
||||||
|
src/core/main/setting.ts
|
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -10,7 +10,6 @@ declare module '@vue/runtime-core' {
|
|||||||
AButton: typeof import('ant-design-vue/es')['Button']
|
AButton: typeof import('ant-design-vue/es')['Button']
|
||||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||||
AInput: typeof import('ant-design-vue/es')['Input']
|
AInput: typeof import('ant-design-vue/es')['Input']
|
||||||
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
|
||||||
AProgress: typeof import('ant-design-vue/es')['Progress']
|
AProgress: typeof import('ant-design-vue/es')['Progress']
|
||||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||||
@ -18,7 +17,6 @@ declare module '@vue/runtime-core' {
|
|||||||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
||||||
Box: typeof import('./src/components/box.vue')['default']
|
Box: typeof import('./src/components/box.vue')['default']
|
||||||
BoxAnimate: typeof import('./src/components/boxAnimate.vue')['default']
|
BoxAnimate: typeof import('./src/components/boxAnimate.vue')['default']
|
||||||
Changable: typeof import('./src/components/changable.vue')['default']
|
|
||||||
Colomn: typeof import('./src/components/colomn.vue')['default']
|
Colomn: typeof import('./src/components/colomn.vue')['default']
|
||||||
EnemyOne: typeof import('./src/components/enemyOne.vue')['default']
|
EnemyOne: typeof import('./src/components/enemyOne.vue')['default']
|
||||||
Scroll: typeof import('./src/components/scroll.vue')['default']
|
Scroll: typeof import('./src/components/scroll.vue')['default']
|
||||||
|
@ -602,6 +602,7 @@ core.prototype._afterLoadResources = function (callback) {
|
|||||||
|
|
||||||
// if (core.plugin._afterLoadResources) core.plugin._afterLoadResources();
|
// if (core.plugin._afterLoadResources) core.plugin._afterLoadResources();
|
||||||
core.showStartAnimate();
|
core.showStartAnimate();
|
||||||
|
Mota.require('var', 'hook').emit('load');
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4421,24 +4421,31 @@ events.prototype._checkLvUp_check = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
////// 尝试使用道具 //////
|
////// 尝试使用道具 //////
|
||||||
events.prototype.tryUseItem = function (itemId) {
|
events.prototype.tryUseItem = function (itemId, noRoute, callback) {
|
||||||
if (itemId == 'book') {
|
if (itemId == 'book') {
|
||||||
core.ui.closePanel();
|
core.ui.closePanel();
|
||||||
return core.openBook(false);
|
core.openBook(false);
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (itemId == 'fly') {
|
if (itemId == 'fly') {
|
||||||
core.ui.closePanel();
|
core.ui.closePanel();
|
||||||
return core.useFly(false);
|
core.useFly(false);
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (itemId == 'centerFly') {
|
if (itemId == 'centerFly') {
|
||||||
core.ui.closePanel();
|
core.ui.closePanel();
|
||||||
return core.ui._drawCenterFly();
|
core.ui._drawCenterFly();
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (core.canUseItem(itemId)) {
|
if (core.canUseItem(itemId)) {
|
||||||
core.ui.closePanel();
|
core.ui.closePanel();
|
||||||
core.useItem(itemId);
|
core.useItem(itemId, noRoute, callback);
|
||||||
} else {
|
} else {
|
||||||
core.playSound('操作失败');
|
core.playSound('操作失败');
|
||||||
core.drawTip('当前无法使用' + core.material.items[itemId].name, itemId);
|
core.drawTip('当前无法使用' + core.material.items[itemId].name, itemId);
|
||||||
}
|
}
|
||||||
|
callback();
|
||||||
};
|
};
|
||||||
|
@ -48,6 +48,7 @@ function show(index: number) {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
display: block;
|
display: block;
|
||||||
|
font-size: 80%;
|
||||||
font-family: 'normal';
|
font-family: 'normal';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +62,6 @@ function show(index: number) {
|
|||||||
top: 0;
|
top: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
background-color: #000b;
|
background-color: #000b;
|
||||||
backdrop-filter: blur(5px);
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, onUpdated, ref, useSlots, watch } from 'vue';
|
import { onMounted, onUnmounted, onUpdated, ref, watch } from 'vue';
|
||||||
import { DragOutlined } from '@ant-design/icons-vue';
|
import { DragOutlined } from '@ant-design/icons-vue';
|
||||||
import { isMobile, useDrag, cancelGlobalDrag } from '../plugin/use';
|
import { isMobile, useDrag, cancelGlobalDrag } from '../plugin/use';
|
||||||
import { has } from '../plugin/utils';
|
import { has } from '../plugin/utils';
|
||||||
@ -231,7 +231,6 @@ onUnmounted(() => {
|
|||||||
top: 50px;
|
top: 50px;
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
font-family: 'normal';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-main {
|
.box-main {
|
||||||
|
@ -19,11 +19,14 @@
|
|||||||
class="special-text"
|
class="special-text"
|
||||||
v-if="has(enemy.special) && enemy.special.length > 0"
|
v-if="has(enemy.special) && enemy.special.length > 0"
|
||||||
>
|
>
|
||||||
<span
|
<template v-for="(text, i) in enemy.showSpecial">
|
||||||
v-for="(text, i) in enemy.showSpecial"
|
<span
|
||||||
:style="{ color: text[2] }"
|
v-if="i < (isMobile ? 1 : 2)"
|
||||||
> {{ text[0] }} </span
|
:style="{ color: text[2] }"
|
||||||
>
|
> {{ text[0] }} </span
|
||||||
|
>
|
||||||
|
<span v-if="i === (isMobile ? 1 : 2)">...</span>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="special-text" v-else>无属性</div>
|
<div class="special-text" v-else>无属性</div>
|
||||||
</div>
|
</div>
|
||||||
@ -220,12 +223,12 @@ function enter() {
|
|||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
.rightbar {
|
.rightbar {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
font-size: 85%;
|
font-size: 110%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.leftbar {
|
.leftbar {
|
||||||
width: 20%;
|
width: 20%;
|
||||||
font-size: 80%;
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.enemy-container {
|
.enemy-container {
|
||||||
|
@ -80,8 +80,8 @@ export class BgmController
|
|||||||
|
|
||||||
this.playing = true;
|
this.playing = true;
|
||||||
if (!this.disable) {
|
if (!this.disable) {
|
||||||
this.setTransitionAnimate(id, 1);
|
this.setTransitionAnimate(id, 1, when);
|
||||||
if (this.now) this.setTransitionAnimate(this.now, 0, when);
|
if (this.now) this.setTransitionAnimate(this.now, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!noStack) {
|
if (!noStack) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { has } from '@/plugin/utils';
|
import { has } from '@/plugin/utils';
|
||||||
import { AudioParamOf, AudioPlayer } from './audio';
|
import { AudioParamOf, AudioPlayer } from './audio';
|
||||||
import resource from '@/data/resource.json';
|
|
||||||
import { ResourceController } from '../loader/controller';
|
import { ResourceController } from '../loader/controller';
|
||||||
|
|
||||||
// todo: 立体声,可设置音源位置
|
// todo: 立体声,可设置音源位置
|
||||||
@ -24,7 +23,6 @@ export class SoundEffect extends AudioPlayer {
|
|||||||
|
|
||||||
gain: GainNode = AudioPlayer.ac.createGain();
|
gain: GainNode = AudioPlayer.ac.createGain();
|
||||||
panner: PannerNode | null = null;
|
panner: PannerNode | null = null;
|
||||||
merger: ChannelMergerNode | null = null;
|
|
||||||
|
|
||||||
set volumn(value: number) {
|
set volumn(value: number) {
|
||||||
this.gain.gain.value = value * SoundEffect.volume;
|
this.gain.gain.value = value * SoundEffect.volume;
|
||||||
@ -63,9 +61,7 @@ export class SoundEffect extends AudioPlayer {
|
|||||||
* 设置音频路由线路
|
* 设置音频路由线路
|
||||||
* ```txt
|
* ```txt
|
||||||
* 不启用立体声:source -> gain -> destination
|
* 不启用立体声:source -> gain -> destination
|
||||||
* 启用立体声:source -> panner -> gain --> destination
|
* 启用立体声:source -> panner -> gain -> destination
|
||||||
* 单声道立体声:source -> merger -> panner -> gain -> destination
|
|
||||||
* 单声道立体声指音源为单声道,合成为双声道后模拟为立体声
|
|
||||||
* ```
|
* ```
|
||||||
* @param stereo 是否启用立体声
|
* @param stereo 是否启用立体声
|
||||||
*/
|
*/
|
||||||
@ -74,20 +70,10 @@ export class SoundEffect extends AudioPlayer {
|
|||||||
const ac = AudioPlayer.ac;
|
const ac = AudioPlayer.ac;
|
||||||
if (!channel) return;
|
if (!channel) return;
|
||||||
this.panner = null;
|
this.panner = null;
|
||||||
this.merger = null;
|
|
||||||
if (stereo) {
|
if (stereo) {
|
||||||
this.panner = ac.createPanner();
|
this.panner = ac.createPanner();
|
||||||
this.panner.connect(this.gain);
|
this.panner.connect(this.gain);
|
||||||
if (channel === 1) {
|
this.baseNode = [{ node: this.panner }];
|
||||||
this.merger = ac.createChannelMerger();
|
|
||||||
this.merger.connect(this.panner);
|
|
||||||
this.baseNode = [
|
|
||||||
{ node: this.merger, channel: 0 },
|
|
||||||
{ node: this.merger, channel: 1 }
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
this.baseNode = [{ node: this.panner }];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.baseNode = [{ node: this.gain }];
|
this.baseNode = [{ node: this.gain }];
|
||||||
}
|
}
|
||||||
@ -136,15 +122,18 @@ export class SoundEffect extends AudioPlayer {
|
|||||||
* @param source 立体声声源位置与朝向
|
* @param source 立体声声源位置与朝向
|
||||||
* @param listener 听者的位置、头顶方向、面朝方向
|
* @param listener 听者的位置、头顶方向、面朝方向
|
||||||
*/
|
*/
|
||||||
setPanner(source: Partial<Panner>, listener: Partial<Listener>) {
|
setPanner(source?: Partial<Panner>, listener?: Partial<Listener>) {
|
||||||
if (!this.panner) return;
|
if (!this.panner) return;
|
||||||
console.log(2);
|
if (source) {
|
||||||
for (const [key, value] of Object.entries(source)) {
|
for (const [key, value] of Object.entries(source)) {
|
||||||
this.panner[key as keyof Panner].value = value;
|
this.panner[key as keyof Panner].value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const l = AudioPlayer.ac.listener;
|
if (listener) {
|
||||||
for (const [key, value] of Object.entries(listener)) {
|
const l = AudioPlayer.ac.listener;
|
||||||
l[key as keyof Listener].value = value;
|
for (const [key, value] of Object.entries(listener)) {
|
||||||
|
l[key as keyof Listener].value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,7 +150,6 @@ export class SoundController extends ResourceController<
|
|||||||
* @param data 音频的ArrayBuffer信息,会被解析为AudioBuffer
|
* @param data 音频的ArrayBuffer信息,会被解析为AudioBuffer
|
||||||
*/
|
*/
|
||||||
add(uri: string, data: ArrayBuffer) {
|
add(uri: string, data: ArrayBuffer) {
|
||||||
const stereo = resource.stereoSE.includes(uri);
|
|
||||||
const se = new SoundEffect(data, true);
|
const se = new SoundEffect(data, true);
|
||||||
if (this.list[uri]) {
|
if (this.list[uri]) {
|
||||||
console.warn(`Repeated sound effect: '${uri}'.`);
|
console.warn(`Repeated sound effect: '${uri}'.`);
|
||||||
@ -176,6 +164,7 @@ export class SoundController extends ResourceController<
|
|||||||
*/
|
*/
|
||||||
play(sound: SoundIds, end?: () => void): number {
|
play(sound: SoundIds, end?: () => void): number {
|
||||||
const se = this.get(sound);
|
const se = this.get(sound);
|
||||||
|
if (!se) return -1;
|
||||||
const index = se.playSE();
|
const index = se.playSE();
|
||||||
if (!has(index)) return -1;
|
if (!has(index)) return -1;
|
||||||
this.seIndex[index] = se;
|
this.seIndex[index] = se;
|
||||||
|
@ -1,13 +1,5 @@
|
|||||||
import { BgmController, bgm } from './audio/bgm';
|
import { BgmController, bgm } from './audio/bgm';
|
||||||
import { SoundController, SoundEffect, sound } from './audio/sound';
|
import { SoundController, SoundEffect, sound } from './audio/sound';
|
||||||
import { readyAllResource } from './loader/load';
|
|
||||||
import {
|
|
||||||
Resource,
|
|
||||||
ResourceStore,
|
|
||||||
ZippedResource,
|
|
||||||
resource,
|
|
||||||
zipResource
|
|
||||||
} from './loader/resource';
|
|
||||||
import { Focus, GameUi, UiController } from './main/custom/ui';
|
import { Focus, GameUi, UiController } from './main/custom/ui';
|
||||||
import { GameStorage } from './main/storage';
|
import { GameStorage } from './main/storage';
|
||||||
import './main/init/';
|
import './main/init/';
|
||||||
@ -20,19 +12,51 @@ import {
|
|||||||
mainSetting,
|
mainSetting,
|
||||||
settingStorage
|
settingStorage
|
||||||
} from './main/setting';
|
} from './main/setting';
|
||||||
import { KeyCode } from '@/plugin/keyCodes';
|
import { KeyCode, ScanCode } from '@/plugin/keyCodes';
|
||||||
import { status } from '@/plugin/ui/statusBar';
|
import { status } from '@/plugin/ui/statusBar';
|
||||||
import './plugin';
|
import './plugin';
|
||||||
import './package';
|
import './package';
|
||||||
import { AudioPlayer } from './audio/audio';
|
import { AudioPlayer } from './audio/audio';
|
||||||
import { CustomToolbar } from './main/custom/toolbar';
|
import { CustomToolbar } from './main/custom/toolbar';
|
||||||
import { Hotkey } from './main/custom/hotkey';
|
import {
|
||||||
import { Keyboard } from './main/custom/keyboard';
|
Hotkey,
|
||||||
|
checkAssist,
|
||||||
|
isAssist,
|
||||||
|
unwarpBinary
|
||||||
|
} from './main/custom/hotkey';
|
||||||
|
import { Keyboard, generateKeyboardEvent } from './main/custom/keyboard';
|
||||||
import './main/layout';
|
import './main/layout';
|
||||||
|
import { MComponent, m } from './main/layout';
|
||||||
function ready() {
|
import { createSettingComponents } from './main/init/settings';
|
||||||
readyAllResource();
|
import {
|
||||||
}
|
createToolbarComponents,
|
||||||
|
createToolbarEditorComponents
|
||||||
|
} from './main/init/toolbar';
|
||||||
|
import { VirtualKey } from './main/init/misc';
|
||||||
|
import * as utils from '@/plugin/utils';
|
||||||
|
import * as use from '@/plugin/use';
|
||||||
|
import * as mark from '@/plugin/mark';
|
||||||
|
import * as keyCodes from '@/plugin/keyCodes';
|
||||||
|
import { addAnimate, removeAnimate } from '@/plugin/animateController';
|
||||||
|
import * as bookTools from '@/plugin/ui/book';
|
||||||
|
import * as commonTools from '@/plugin/ui/common';
|
||||||
|
import * as equipboxTools from '@/plugin/ui/equipbox';
|
||||||
|
import * as fixedTools from '@/plugin/ui/fixed';
|
||||||
|
import * as flyTools from '@/plugin/ui/fly';
|
||||||
|
import * as statusBarTools from '@/plugin/ui/statusBar';
|
||||||
|
import * as toolboxTools from '@/plugin/ui/toolbox';
|
||||||
|
import * as UI from '@ui/index';
|
||||||
|
import Box from '@/components/box.vue';
|
||||||
|
import BoxAnimate from '@/components/boxAnimate.vue';
|
||||||
|
import Colomn from '@/components/colomn.vue';
|
||||||
|
import EnemyOne from '@/components/enemyOne.vue';
|
||||||
|
import Scroll from '@/components/scroll.vue';
|
||||||
|
import EnemyCritical from '@/panel/enemyCritical.vue';
|
||||||
|
import EnemySpecial from '@/panel/enemySpecial.vue';
|
||||||
|
import EnemyTarget from '@/panel/enemyTarget.vue';
|
||||||
|
import KeyboardPanel from '@/panel/keyboard.vue';
|
||||||
|
import { MCGenerator } from './main/layout';
|
||||||
|
import { ResourceController } from './loader/controller';
|
||||||
|
|
||||||
// ----- 类注册
|
// ----- 类注册
|
||||||
Mota.register('class', 'AudioPlayer', AudioPlayer);
|
Mota.register('class', 'AudioPlayer', AudioPlayer);
|
||||||
@ -44,15 +68,20 @@ Mota.register('class', 'GameUi', GameUi);
|
|||||||
Mota.register('class', 'Hotkey', Hotkey);
|
Mota.register('class', 'Hotkey', Hotkey);
|
||||||
Mota.register('class', 'Keyboard', Keyboard);
|
Mota.register('class', 'Keyboard', Keyboard);
|
||||||
Mota.register('class', 'MotaSetting', MotaSetting);
|
Mota.register('class', 'MotaSetting', MotaSetting);
|
||||||
Mota.register('class', 'Resource', Resource);
|
|
||||||
Mota.register('class', 'ResourceStore', ResourceStore);
|
|
||||||
Mota.register('class', 'SettingDisplayer', SettingDisplayer);
|
Mota.register('class', 'SettingDisplayer', SettingDisplayer);
|
||||||
Mota.register('class', 'SoundController', SoundController);
|
Mota.register('class', 'SoundController', SoundController);
|
||||||
Mota.register('class', 'SoundEffect', SoundEffect);
|
Mota.register('class', 'SoundEffect', SoundEffect);
|
||||||
Mota.register('class', 'UiController', UiController);
|
Mota.register('class', 'UiController', UiController);
|
||||||
Mota.register('class', 'ZippedResource', ZippedResource);
|
Mota.register('class', 'MComponent', MComponent);
|
||||||
|
Mota.register('class', 'ResourceController', ResourceController);
|
||||||
// ----- 函数注册
|
// ----- 函数注册
|
||||||
|
Mota.register('fn', 'm', m);
|
||||||
|
Mota.register('fn', 'unwrapBinary', unwarpBinary);
|
||||||
|
Mota.register('fn', 'checkAssist', checkAssist);
|
||||||
|
Mota.register('fn', 'isAssist', isAssist);
|
||||||
|
Mota.register('fn', 'generateKeyboardEvent', generateKeyboardEvent);
|
||||||
|
Mota.register('fn', 'addAnimate', addAnimate);
|
||||||
|
Mota.register('fn', 'removeAnimate', removeAnimate);
|
||||||
// ----- 变量注册
|
// ----- 变量注册
|
||||||
Mota.register('var', 'mainUi', mainUi);
|
Mota.register('var', 'mainUi', mainUi);
|
||||||
Mota.register('var', 'fixedUi', fixedUi);
|
Mota.register('var', 'fixedUi', fixedUi);
|
||||||
@ -61,11 +90,43 @@ Mota.register('var', 'sound', sound);
|
|||||||
Mota.register('var', 'gameKey', gameKey);
|
Mota.register('var', 'gameKey', gameKey);
|
||||||
Mota.register('var', 'mainSetting', mainSetting);
|
Mota.register('var', 'mainSetting', mainSetting);
|
||||||
Mota.register('var', 'KeyCode', KeyCode);
|
Mota.register('var', 'KeyCode', KeyCode);
|
||||||
Mota.register('var', 'resource', resource);
|
|
||||||
Mota.register('var', 'zipResource', zipResource);
|
|
||||||
Mota.register('var', 'settingStorage', settingStorage);
|
Mota.register('var', 'settingStorage', settingStorage);
|
||||||
Mota.register('var', 'status', status);
|
Mota.register('var', 'status', status);
|
||||||
|
|
||||||
// ----- 模块注册
|
// ----- 模块注册
|
||||||
|
Mota.register('module', 'CustomComponents', {
|
||||||
|
createSettingComponents,
|
||||||
|
createToolbarComponents,
|
||||||
|
createToolbarEditorComponents
|
||||||
|
});
|
||||||
|
Mota.register('module', 'MiscComponents', {
|
||||||
|
VirtualKey
|
||||||
|
});
|
||||||
|
Mota.register('module', 'RenderUtils', utils);
|
||||||
|
Mota.register('module', 'Use', use);
|
||||||
|
Mota.register('module', 'Mark', mark);
|
||||||
|
Mota.register('module', 'KeyCodes', keyCodes);
|
||||||
|
Mota.register('module', 'UITools', {
|
||||||
|
book: bookTools,
|
||||||
|
common: commonTools,
|
||||||
|
equipbox: equipboxTools,
|
||||||
|
fixed: fixedTools,
|
||||||
|
fly: flyTools,
|
||||||
|
statusBar: statusBarTools,
|
||||||
|
toolbox: toolboxTools
|
||||||
|
});
|
||||||
|
Mota.register('module', 'UI', UI);
|
||||||
|
Mota.register('module', 'UIComponents', {
|
||||||
|
Box,
|
||||||
|
BoxAnimate,
|
||||||
|
Colomn,
|
||||||
|
EnemyOne,
|
||||||
|
Scroll,
|
||||||
|
EnemyCritical,
|
||||||
|
EnemySpecial,
|
||||||
|
EnemyTarget,
|
||||||
|
Keyboard: KeyboardPanel
|
||||||
|
});
|
||||||
|
Mota.register('module', 'MCGenerator', MCGenerator);
|
||||||
|
|
||||||
ready();
|
main.renderLoaded = true;
|
||||||
|
Mota.require('var', 'hook').emit('renderLoaded');
|
||||||
|
@ -137,7 +137,7 @@ export class Hotkey extends EventEmitter<HotkeyEvent> {
|
|||||||
* 释放一个作用域,释放后作用域将退回至删除的作用域的上一级
|
* 释放一个作用域,释放后作用域将退回至删除的作用域的上一级
|
||||||
* @param symbol 要释放的作用域的symbol
|
* @param symbol 要释放的作用域的symbol
|
||||||
*/
|
*/
|
||||||
dispose(symbol: symbol) {
|
dispose(symbol: symbol = this.scopeStack.at(-1) ?? Symbol()) {
|
||||||
for (const key of Object.values(this.data)) {
|
for (const key of Object.values(this.data)) {
|
||||||
key.func.delete(symbol);
|
key.func.delete(symbol);
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,14 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
constructor(id: string) {
|
constructor(id: string) {
|
||||||
super();
|
super();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
// 按比例设置初始大小
|
||||||
|
const setting = Mota.require('var', 'mainSetting');
|
||||||
|
const scale = setting.getValue('ui.toolbarScale', 100) / 100;
|
||||||
|
this.width *= scale;
|
||||||
|
this.height *= scale;
|
||||||
|
this.x *= scale;
|
||||||
|
this.y *= scale;
|
||||||
|
|
||||||
this.show();
|
this.show();
|
||||||
CustomToolbar.list.push(this);
|
CustomToolbar.list.push(this);
|
||||||
}
|
}
|
||||||
@ -188,22 +196,31 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
/**
|
/**
|
||||||
* 强制刷新这个自定义工具栏的所有显示
|
* 强制刷新这个自定义工具栏的所有显示
|
||||||
*/
|
*/
|
||||||
refresh() {
|
refresh(reopen: boolean = false) {
|
||||||
const items = this.items.splice(0);
|
if (reopen && this.showIds.length > 0) {
|
||||||
nextTick(() => {
|
this.closeAll();
|
||||||
this.items.push(...items);
|
nextTick(() => {
|
||||||
});
|
this.show();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const items = this.items.splice(0);
|
||||||
|
nextTick(() => {
|
||||||
|
this.items.push(...items);
|
||||||
|
});
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
setPos(x?: number, y?: number) {
|
setPos(x?: number, y?: number) {
|
||||||
has(x) && (this.x = x);
|
has(x) && (this.x = x);
|
||||||
has(y) && (this.y = y);
|
has(y) && (this.y = y);
|
||||||
|
this.emit('posChange', this);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSize(width?: number, height?: number) {
|
setSize(width?: number, height?: number) {
|
||||||
has(width) && (this.width = width);
|
has(width) && (this.width = width);
|
||||||
has(height) && (this.height = height);
|
has(height) && (this.height = height);
|
||||||
|
this.emit('posChange', this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -269,12 +286,14 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
|
|
||||||
static save() {
|
static save() {
|
||||||
toolbarStorage.clear();
|
toolbarStorage.clear();
|
||||||
|
const setting = Mota.require('var', 'mainSetting');
|
||||||
|
const scale = setting.getValue('ui.toolbarScale', 100) / 100;
|
||||||
this.list.forEach(v => {
|
this.list.forEach(v => {
|
||||||
const toSave: ToolbarSaveData = {
|
const toSave: ToolbarSaveData = {
|
||||||
x: v.x,
|
x: v.x,
|
||||||
y: v.y,
|
y: v.y,
|
||||||
w: v.width,
|
w: v.width / scale,
|
||||||
h: v.height,
|
h: v.height / scale,
|
||||||
items: []
|
items: []
|
||||||
};
|
};
|
||||||
v.items.forEach(v => {
|
v.items.forEach(v => {
|
||||||
@ -288,7 +307,7 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
static load() {
|
static load() {
|
||||||
toolbarStorage.read();
|
toolbarStorage.read();
|
||||||
for (const [key, value] of Object.entries(toolbarStorage.data)) {
|
for (const [key, value] of Object.entries(toolbarStorage.data)) {
|
||||||
const bar = new CustomToolbar(key);
|
const bar = this.get(key) ?? new CustomToolbar(key);
|
||||||
bar.x = value.x;
|
bar.x = value.x;
|
||||||
bar.y = value.y;
|
bar.y = value.y;
|
||||||
bar.width = value.w;
|
bar.width = value.w;
|
||||||
@ -299,6 +318,10 @@ export class CustomToolbar extends EventEmitter<CustomToolbarEvent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static refreshAll(reopen: boolean = false): void {
|
||||||
|
CustomToolbar.list.forEach(v => v.refresh(reopen));
|
||||||
|
}
|
||||||
|
|
||||||
static showAll(): number[] {
|
static showAll(): number[] {
|
||||||
return CustomToolbar.list.map(v => v.show());
|
return CustomToolbar.list.map(v => v.show());
|
||||||
}
|
}
|
||||||
@ -376,16 +399,16 @@ CustomToolbar.register(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
window.addEventListener('beforeunload', () => {
|
|
||||||
CustomToolbar.save();
|
|
||||||
});
|
|
||||||
window.addEventListener('blur', () => {
|
|
||||||
CustomToolbar.save();
|
|
||||||
});
|
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('coreInit', () => {
|
Mota.require('var', 'loading').once('coreInit', () => {
|
||||||
CustomToolbar.load();
|
CustomToolbar.load();
|
||||||
CustomToolbar.closeAll();
|
CustomToolbar.closeAll();
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', e => {
|
||||||
|
CustomToolbar.save();
|
||||||
|
});
|
||||||
|
window.addEventListener('blur', () => {
|
||||||
|
CustomToolbar.save();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Mota.require('var', 'hook').on('reset', () => {
|
Mota.require('var', 'hook').on('reset', () => {
|
||||||
CustomToolbar.showAll();
|
CustomToolbar.showAll();
|
||||||
|
@ -9,8 +9,6 @@ interface FocusEvent<T> extends EmitableEvent {
|
|||||||
unfocus: (before: T | null) => void;
|
unfocus: (before: T | null) => void;
|
||||||
add: (item: T) => void;
|
add: (item: T) => void;
|
||||||
pop: (item: T | null) => void;
|
pop: (item: T | null) => void;
|
||||||
register: (item: T[]) => void;
|
|
||||||
unregister: (item: T[]) => void;
|
|
||||||
splice: (spliced: T[]) => void;
|
splice: (spliced: T[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +161,7 @@ interface IndexedGameUi extends ShowableGameUi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface HoldOnController {
|
interface HoldOnController {
|
||||||
end(): void;
|
end(noClosePanel?: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UiController extends Focus<IndexedGameUi> {
|
export class UiController extends Focus<IndexedGameUi> {
|
||||||
@ -182,7 +180,7 @@ export class UiController extends Focus<IndexedGameUi> {
|
|||||||
v.ui.emit('close');
|
v.ui.emit('close');
|
||||||
});
|
});
|
||||||
if (this.stack.length === 0) {
|
if (this.stack.length === 0) {
|
||||||
if (!this.hold) this.emit('end');
|
if (!this.hold) this.emit('end', false);
|
||||||
this.hold = false;
|
this.hold = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -227,8 +225,8 @@ export class UiController extends Focus<IndexedGameUi> {
|
|||||||
this.hold = true;
|
this.hold = true;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
end: () => {
|
end: (noClosePanel: boolean = false) => {
|
||||||
this.emit('end');
|
this.emit('end', noClosePanel);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@ interface Components {
|
|||||||
Number: SettingComponent;
|
Number: SettingComponent;
|
||||||
HotkeySetting: SettingComponent;
|
HotkeySetting: SettingComponent;
|
||||||
ToolbarEditor: SettingComponent;
|
ToolbarEditor: SettingComponent;
|
||||||
RadioSetting: (items: string[]) => SettingComponent;
|
Radio: (items: string[]) => SettingComponent;
|
||||||
|
Performance: SettingComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { Components as SettingDisplayComponents };
|
export type { Components as SettingDisplayComponents };
|
||||||
@ -21,7 +22,8 @@ export function createSettingComponents() {
|
|||||||
Number: NumberSetting,
|
Number: NumberSetting,
|
||||||
HotkeySetting,
|
HotkeySetting,
|
||||||
ToolbarEditor,
|
ToolbarEditor,
|
||||||
RadioSetting
|
Radio: RadioSetting,
|
||||||
|
Performance: PerformanceSetting
|
||||||
};
|
};
|
||||||
return com;
|
return com;
|
||||||
}
|
}
|
||||||
@ -63,7 +65,7 @@ function NumberSetting(props: SettingComponentProps) {
|
|||||||
if (value < (item.step?.[0] ?? 0) || value > (item.step?.[1] ?? 100)) {
|
if (value < (item.step?.[0] ?? 0) || value > (item.step?.[1] ?? 100)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setting.setValue(displayer.selectStack.join('.'), value);
|
setting.setValue(displayer.selectStack.join('.'), Math.round(value));
|
||||||
displayer.update();
|
displayer.update();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -180,3 +182,18 @@ function ToolbarEditor(props: SettingComponentProps) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function PerformanceSetting(props: SettingComponentProps) {
|
||||||
|
return (
|
||||||
|
<div style="display: flex; justify-content: center">
|
||||||
|
<Button
|
||||||
|
style="font-size: 75%"
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
onClick={() => showSpecialSetting('performance')}
|
||||||
|
>
|
||||||
|
打开性能界面
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@ import { checkAssist } from '../custom/hotkey';
|
|||||||
import { getVitualKeyOnce } from '@/plugin/utils';
|
import { getVitualKeyOnce } from '@/plugin/utils';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
import { Select, SelectOption } from 'ant-design-vue';
|
import { Select, SelectOption } from 'ant-design-vue';
|
||||||
|
import { mainSetting } from '../setting';
|
||||||
|
|
||||||
// todo: 新增更改设置的ToolItem
|
// todo: 新增更改设置的ToolItem
|
||||||
|
|
||||||
@ -53,15 +54,18 @@ function KeyTool(props: CustomToolbarProps<'hotkey'>) {
|
|||||||
|
|
||||||
function ItemTool(props: CustomToolbarProps<'item'>) {
|
function ItemTool(props: CustomToolbarProps<'item'>) {
|
||||||
const { item, toolbar } = props;
|
const { item, toolbar } = props;
|
||||||
|
const scale = mainSetting.getValue('ui.toolbarScale', 100) / 100;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style="display: flex; justify-content: center; width: 50px"
|
style={`display: flex; justify-content: center; width: ${
|
||||||
|
50 * scale
|
||||||
|
}px`}
|
||||||
onClick={() => toolbar.emitTool(item.id)}
|
onClick={() => toolbar.emitTool(item.id)}
|
||||||
>
|
>
|
||||||
<BoxAnimate
|
<BoxAnimate
|
||||||
noborder={true}
|
noborder={true}
|
||||||
width={50}
|
width={50 * scale}
|
||||||
height={50}
|
height={50 * scale}
|
||||||
id={item.item}
|
id={item.item}
|
||||||
></BoxAnimate>
|
></BoxAnimate>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as UI from '@ui/.';
|
import * as UI from '@ui/.';
|
||||||
import * as MiscUI from './misc';
|
import * as MiscUI from './misc';
|
||||||
import { GameUi, UiController } from '../custom/ui';
|
import { GameUi, UiController } from '../custom/ui';
|
||||||
|
import { mainSetting } from '../setting';
|
||||||
|
|
||||||
export const mainUi = new UiController();
|
export const mainUi = new UiController();
|
||||||
mainUi.register(
|
mainUi.register(
|
||||||
@ -35,20 +36,34 @@ fixedUi.register(
|
|||||||
);
|
);
|
||||||
fixedUi.showAll();
|
fixedUi.showAll();
|
||||||
|
|
||||||
|
let loaded = false;
|
||||||
|
let mounted = false;
|
||||||
|
|
||||||
const hook = Mota.require('var', 'hook');
|
const hook = Mota.require('var', 'hook');
|
||||||
hook.once('mounted', () => {
|
hook.once('mounted', () => {
|
||||||
const ui = document.getElementById('ui-main')!;
|
const ui = document.getElementById('ui-main')!;
|
||||||
const fixed = document.getElementById('ui-fixed')!;
|
const fixed = document.getElementById('ui-fixed')!;
|
||||||
|
|
||||||
|
const blur = mainSetting.getSetting('screen.blur');
|
||||||
|
|
||||||
mainUi.on('start', () => {
|
mainUi.on('start', () => {
|
||||||
ui.style.display = 'flex';
|
ui.style.display = 'flex';
|
||||||
|
if (blur?.value) {
|
||||||
|
ui.style.backdropFilter = 'blur(5px)';
|
||||||
|
ui.style.backgroundColor = 'rgba(0,0,0,0.7333)';
|
||||||
|
} else {
|
||||||
|
ui.style.backdropFilter = 'none';
|
||||||
|
ui.style.backgroundColor = 'rgba(0,0,0,0.85)';
|
||||||
|
}
|
||||||
core.lockControl();
|
core.lockControl();
|
||||||
});
|
});
|
||||||
mainUi.on('end', () => {
|
mainUi.on('end', noClosePanel => {
|
||||||
ui.style.display = 'none';
|
ui.style.display = 'none';
|
||||||
try {
|
if (!noClosePanel) {
|
||||||
core.closePanel();
|
try {
|
||||||
} catch {}
|
core.closePanel();
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
fixedUi.on('start', () => {
|
fixedUi.on('start', () => {
|
||||||
fixed.style.display = 'block';
|
fixed.style.display = 'block';
|
||||||
@ -57,6 +72,15 @@ hook.once('mounted', () => {
|
|||||||
fixed.style.display = 'none';
|
fixed.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
// todo: 暂时先这么搞,之后重写加载界面,需要改成先显示加载界面,加载完毕后再打开这个界面
|
if (loaded && !mounted) {
|
||||||
fixedUi.open('start');
|
fixedUi.open('start');
|
||||||
|
}
|
||||||
|
mounted = true;
|
||||||
|
});
|
||||||
|
hook.once('load', () => {
|
||||||
|
if (mounted) {
|
||||||
|
// todo: 暂时先这么搞,之后重写加载界面,需要改成先显示加载界面,加载完毕后再打开这个界面
|
||||||
|
fixedUi.open('start');
|
||||||
|
}
|
||||||
|
loaded = true;
|
||||||
});
|
});
|
||||||
|
@ -5,10 +5,12 @@ import {
|
|||||||
VNode,
|
VNode,
|
||||||
VNodeChild,
|
VNodeChild,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
h,
|
h as hVue,
|
||||||
|
isVNode,
|
||||||
onMounted
|
onMounted
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import BoxAnimate from '@/components/boxAnimate.vue';
|
import BoxAnimate from '@/components/boxAnimate.vue';
|
||||||
|
import { ensureArray } from '@/plugin/utils';
|
||||||
|
|
||||||
interface VForRenderer {
|
interface VForRenderer {
|
||||||
type: '@v-for';
|
type: '@v-for';
|
||||||
@ -18,7 +20,7 @@ interface VForRenderer {
|
|||||||
|
|
||||||
interface MotaComponent extends MotaComponentConfig {
|
interface MotaComponent extends MotaComponentConfig {
|
||||||
type: string;
|
type: string;
|
||||||
children: MComponent[] | MComponent;
|
children: (MComponent | MotaComponent | VNode)[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MotaComponentConfig {
|
interface MotaComponentConfig {
|
||||||
@ -32,7 +34,7 @@ interface MotaComponentConfig {
|
|||||||
velse?: boolean;
|
velse?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type OnSetupFunction = (props: Record<string, any>) => void;
|
type OnSetupFunction = (props: Record<string, any>, ctx: SetupContext) => void;
|
||||||
type SetupFunction = (
|
type SetupFunction = (
|
||||||
props: Record<string, any>,
|
props: Record<string, any>,
|
||||||
ctx: SetupContext
|
ctx: SetupContext
|
||||||
@ -43,6 +45,7 @@ type RetFunction = (
|
|||||||
) => VNodeChild | VNodeChild[];
|
) => VNodeChild | VNodeChild[];
|
||||||
type OnMountedFunction = (
|
type OnMountedFunction = (
|
||||||
props: Record<string, any>,
|
props: Record<string, any>,
|
||||||
|
ctx: SetupContext,
|
||||||
canvas: HTMLCanvasElement[]
|
canvas: HTMLCanvasElement[]
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
@ -51,6 +54,12 @@ type NonComponentConfig = Omit<
|
|||||||
'innerText' | 'component' | 'slots' | 'dComponent'
|
'innerText' | 'component' | 'slots' | 'dComponent'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
type MComponentChildren =
|
||||||
|
| (MComponent | MotaComponent | VNode)[]
|
||||||
|
| MComponent
|
||||||
|
| MotaComponent
|
||||||
|
| VNode;
|
||||||
|
|
||||||
export class MComponent {
|
export class MComponent {
|
||||||
static mountNum: number = 0;
|
static mountNum: number = 0;
|
||||||
|
|
||||||
@ -88,7 +97,7 @@ export class MComponent {
|
|||||||
* @param children 渲染内容的子内容
|
* @param children 渲染内容的子内容
|
||||||
* @param config 渲染内容的配置信息,参考 {@link MComponent.h}
|
* @param config 渲染内容的配置信息,参考 {@link MComponent.h}
|
||||||
*/
|
*/
|
||||||
div(children?: MComponent[] | MComponent, config?: NonComponentConfig) {
|
div(children?: MComponentChildren, config?: NonComponentConfig) {
|
||||||
return this.h('div', children, config);
|
return this.h('div', children, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +106,7 @@ export class MComponent {
|
|||||||
* @param children 渲染内容的子内容
|
* @param children 渲染内容的子内容
|
||||||
* @param config 渲染内容的配置信息,参考 {@link MComponent.h}
|
* @param config 渲染内容的配置信息,参考 {@link MComponent.h}
|
||||||
*/
|
*/
|
||||||
span(children?: MComponent[] | MComponent, config?: NonComponentConfig) {
|
span(children?: MComponentChildren, config?: NonComponentConfig) {
|
||||||
return this.h('span', children, config);
|
return this.h('span', children, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +133,7 @@ export class MComponent {
|
|||||||
*/
|
*/
|
||||||
com(
|
com(
|
||||||
component: Component | MComponent,
|
component: Component | MComponent,
|
||||||
config: Omit<MotaComponentConfig, 'innerText' | 'component'>
|
config?: Omit<MotaComponentConfig, 'innerText' | 'component'>
|
||||||
) {
|
) {
|
||||||
return this.h(component, [], config);
|
return this.h(component, [], config);
|
||||||
}
|
}
|
||||||
@ -136,11 +145,7 @@ export class MComponent {
|
|||||||
* 或者MComponent.vNode函数生成。
|
* 或者MComponent.vNode函数生成。
|
||||||
*/
|
*/
|
||||||
vfor<T>(items: T[] | (() => T[]), map: (value: T, index: number) => VNode) {
|
vfor<T>(items: T[] | (() => T[]), map: (value: T, index: number) => VNode) {
|
||||||
this.content.push({
|
this.content.push(MCGenerator.vfor(items, map));
|
||||||
type: '@v-for',
|
|
||||||
items,
|
|
||||||
map
|
|
||||||
});
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,32 +185,10 @@ export class MComponent {
|
|||||||
*/
|
*/
|
||||||
h(
|
h(
|
||||||
type: string | Component | MComponent,
|
type: string | Component | MComponent,
|
||||||
children?: MComponent[] | MComponent,
|
children?: MComponentChildren,
|
||||||
config: MotaComponentConfig = {}
|
config: MotaComponentConfig = {}
|
||||||
): this {
|
): this {
|
||||||
if (typeof type === 'string') {
|
this.content.push(MCGenerator.h(type, children, config));
|
||||||
this.content.push({
|
|
||||||
type,
|
|
||||||
children: children ?? [],
|
|
||||||
props: config.props,
|
|
||||||
innerText: config.innerText,
|
|
||||||
slots: config.slots,
|
|
||||||
vif: config.vif,
|
|
||||||
velse: config.velse,
|
|
||||||
component: config.component
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.content.push({
|
|
||||||
type: 'component',
|
|
||||||
children: children ?? [],
|
|
||||||
props: config.props,
|
|
||||||
innerText: config.innerText,
|
|
||||||
slots: config.slots,
|
|
||||||
vif: config.vif,
|
|
||||||
velse: config.velse,
|
|
||||||
component: type
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,11 +236,12 @@ export class MComponent {
|
|||||||
return defineComponent(
|
return defineComponent(
|
||||||
(props, ctx) => {
|
(props, ctx) => {
|
||||||
const mountNum = MComponent.mountNum++;
|
const mountNum = MComponent.mountNum++;
|
||||||
this.onSetupFn?.(props);
|
this.onSetupFn?.(props, ctx);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
this.onMountedFn?.(
|
this.onMountedFn?.(
|
||||||
props,
|
props,
|
||||||
|
ctx,
|
||||||
Array.from(
|
Array.from(
|
||||||
document.getElementsByClassName(
|
document.getElementsByClassName(
|
||||||
`--mota-component-canvas-${mountNum}`
|
`--mota-component-canvas-${mountNum}`
|
||||||
@ -269,8 +253,6 @@ export class MComponent {
|
|||||||
if (this.retFn) return () => this.retFn!(props, ctx);
|
if (this.retFn) return () => this.retFn!(props, ctx);
|
||||||
else {
|
else {
|
||||||
return () => {
|
return () => {
|
||||||
console.log(ctx.slots.default);
|
|
||||||
|
|
||||||
const vNodes = MComponent.vNode(
|
const vNodes = MComponent.vNode(
|
||||||
this.content,
|
this.content,
|
||||||
mountNum
|
mountNum
|
||||||
@ -312,12 +294,19 @@ export class MComponent {
|
|||||||
* @param children 要生成VNode的内容列表
|
* @param children 要生成VNode的内容列表
|
||||||
* @param mount 组件生成时的挂载id,一般不需要填,用于画布获取
|
* @param mount 组件生成时的挂载id,一般不需要填,用于画布获取
|
||||||
*/
|
*/
|
||||||
static vNode(children: (MotaComponent | VForRenderer)[], mount?: number) {
|
static vNode(
|
||||||
|
children: (MotaComponent | VForRenderer | VNode)[],
|
||||||
|
mount?: number
|
||||||
|
) {
|
||||||
const mountNum = mount ?? this.mountNum++;
|
const mountNum = mount ?? this.mountNum++;
|
||||||
|
|
||||||
const res: VNode[] = [];
|
const res: VNode[] = [];
|
||||||
const vifRes: Map<number, boolean> = new Map();
|
const vifRes: Map<number, boolean> = new Map();
|
||||||
children.forEach((v, i) => {
|
children.forEach((v, i) => {
|
||||||
|
if (isVNode(v)) {
|
||||||
|
res.push(v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (v.type === '@v-for') {
|
if (v.type === '@v-for') {
|
||||||
const node = v as VForRenderer;
|
const node = v as VForRenderer;
|
||||||
const items =
|
const items =
|
||||||
@ -346,7 +335,7 @@ export class MComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (v.dComponent) {
|
if (v.dComponent) {
|
||||||
res.push(h(v.dComponent(), props, v.slots));
|
res.push(hVue(v.dComponent(), props, v.slots));
|
||||||
} else {
|
} else {
|
||||||
if (v.component instanceof MComponent) {
|
if (v.component instanceof MComponent) {
|
||||||
res.push(
|
res.push(
|
||||||
@ -356,12 +345,12 @@ export class MComponent {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
res.push(h(v.component!, props, v.slots));
|
res.push(hVue(v.component!, props, v.slots));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (v.type === 'text') {
|
} else if (v.type === 'text') {
|
||||||
res.push(
|
res.push(
|
||||||
h(
|
hVue(
|
||||||
'span',
|
'span',
|
||||||
typeof v.innerText === 'function'
|
typeof v.innerText === 'function'
|
||||||
? v.innerText()
|
? v.innerText()
|
||||||
@ -372,15 +361,17 @@ export class MComponent {
|
|||||||
const cls = `--mota-component-canvas-${mountNum}`;
|
const cls = `--mota-component-canvas-${mountNum}`;
|
||||||
const mix = !!props.class ? cls + ' ' + props.class : cls;
|
const mix = !!props.class ? cls + ' ' + props.class : cls;
|
||||||
props.class = mix;
|
props.class = mix;
|
||||||
res.push(h('canvas', props, node.slots));
|
res.push(hVue('canvas', props, node.slots));
|
||||||
} else {
|
} else {
|
||||||
// 这个时候不可能会有插槽,只会有子内容,因此直接渲染子内容
|
// 这个时候不可能会有插槽,只会有子内容,因此直接渲染子内容
|
||||||
const content = [node.children].flat(2);
|
const content = node.children;
|
||||||
const vn = this.vNode(
|
const vn = this.vNode(
|
||||||
content.map(v => v.content).flat(),
|
content
|
||||||
|
.map(v => (v instanceof MComponent ? v.content : v))
|
||||||
|
.flat(),
|
||||||
mountNum
|
mountNum
|
||||||
);
|
);
|
||||||
res.push(h(v.type, props, vn));
|
res.push(hVue(v.type, props, vn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -406,7 +397,7 @@ export class MComponent {
|
|||||||
* @param props 要传递的props
|
* @param props 要传递的props
|
||||||
*/
|
*/
|
||||||
static prop(component: Component, props: Record<string, any>) {
|
static prop(component: Component, props: Record<string, any>) {
|
||||||
return h(component, props);
|
return hVue(component, props);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,18 +409,101 @@ export function m() {
|
|||||||
return new MComponent();
|
return new MComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export namespace MCGenerator {
|
||||||
* 生成一个图标的VNode
|
export function h(
|
||||||
* @param id 图标的id
|
type: string | Component | MComponent,
|
||||||
* @param width 显示宽度,单位像素
|
children?: MComponentChildren,
|
||||||
* @param height 显示高度,单位像素
|
config: MotaComponentConfig = {}
|
||||||
* @param noBoarder 显示的时候是否没有边框和背景
|
): MotaComponent {
|
||||||
*/
|
if (typeof type === 'string') {
|
||||||
export function icon(
|
return {
|
||||||
id: AllIds,
|
type,
|
||||||
width?: number,
|
children: ensureArray(children ?? []),
|
||||||
height?: number,
|
props: config.props,
|
||||||
noBoarder?: number
|
innerText: config.innerText,
|
||||||
) {
|
slots: config.slots,
|
||||||
return h(BoxAnimate, { id, width, height, noBoarder });
|
vif: config.vif,
|
||||||
|
velse: config.velse,
|
||||||
|
component: config.component
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
type: 'component',
|
||||||
|
children: ensureArray(children ?? []),
|
||||||
|
props: config.props,
|
||||||
|
innerText: config.innerText,
|
||||||
|
slots: config.slots,
|
||||||
|
vif: config.vif,
|
||||||
|
velse: config.velse,
|
||||||
|
component: type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function div(
|
||||||
|
children?: MComponentChildren,
|
||||||
|
config?: NonComponentConfig
|
||||||
|
): MotaComponent {
|
||||||
|
return h('div', children, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function span(
|
||||||
|
children?: MComponentChildren,
|
||||||
|
config?: NonComponentConfig
|
||||||
|
): MotaComponent {
|
||||||
|
return h('span', children, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canvas(config?: NonComponentConfig): MotaComponent {
|
||||||
|
return h('canvas', [], config);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function text(
|
||||||
|
text: string | (() => string),
|
||||||
|
config: NonComponentConfig = {}
|
||||||
|
): MotaComponent {
|
||||||
|
return h('text', [], { ...config, innerText: text });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function com(
|
||||||
|
component: Component | MComponent,
|
||||||
|
config: Omit<MotaComponentConfig, 'innerText' | 'component'>
|
||||||
|
): MotaComponent {
|
||||||
|
return h(component, [], config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成一个图标的VNode
|
||||||
|
* @param id 图标的id
|
||||||
|
* @param width 显示宽度,单位像素
|
||||||
|
* @param height 显示高度,单位像素
|
||||||
|
* @param noBoarder 显示的时候是否没有边框和背景
|
||||||
|
*/
|
||||||
|
export function icon(
|
||||||
|
id: AllIds,
|
||||||
|
width?: number,
|
||||||
|
height?: number,
|
||||||
|
noBoarder?: number
|
||||||
|
): VNode {
|
||||||
|
return hVue(BoxAnimate, { id, width, height, noBoarder });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function vfor<T>(
|
||||||
|
items: T[] | (() => T[]),
|
||||||
|
map: (value: T, index: number) => VNode
|
||||||
|
): VForRenderer {
|
||||||
|
return {
|
||||||
|
type: '@v-for',
|
||||||
|
items,
|
||||||
|
map
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为一个常量创建为一个函数
|
||||||
|
* @param value 要创建成函数的值
|
||||||
|
*/
|
||||||
|
export function f<T>(value: T): () => T {
|
||||||
|
return () => value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import { bgm } from '../audio/bgm';
|
|||||||
import { SoundEffect } from '../audio/sound';
|
import { SoundEffect } from '../audio/sound';
|
||||||
import settingsText from '@/data/settings.json';
|
import settingsText from '@/data/settings.json';
|
||||||
import { isMobile } from '@/plugin/use';
|
import { isMobile } from '@/plugin/use';
|
||||||
|
import { fontSize } from '@/plugin/ui/statusBar';
|
||||||
|
import { CustomToolbar } from './custom/toolbar';
|
||||||
|
|
||||||
export interface SettingComponentProps {
|
export interface SettingComponentProps {
|
||||||
item: MotaSettingItem;
|
item: MotaSettingItem;
|
||||||
@ -334,6 +336,8 @@ mainSetting.on('valueChange', (key, n, o) => {
|
|||||||
handleActionSetting(setting, n, o);
|
handleActionSetting(setting, n, o);
|
||||||
} else if (root === 'audio') {
|
} else if (root === 'audio') {
|
||||||
handleAudioSetting(setting, n, o);
|
handleAudioSetting(setting, n, o);
|
||||||
|
} else if (root === 'ui') {
|
||||||
|
handleUiSetting(setting, n, o);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -363,6 +367,11 @@ function handleScreenSetting<T extends number | boolean>(
|
|||||||
} else if (key === 'fontSize') {
|
} else if (key === 'fontSize') {
|
||||||
// 字体大小
|
// 字体大小
|
||||||
root.style.fontSize = `${n}px`;
|
root.style.fontSize = `${n}px`;
|
||||||
|
const absoluteSize = (n as number) * devicePixelRatio;
|
||||||
|
storage.setValue('@@absoluteFontSize', absoluteSize);
|
||||||
|
storage.write();
|
||||||
|
} else if (key === 'fontSizeStatus') {
|
||||||
|
fontSize.value = n as number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,6 +403,16 @@ function handleAudioSetting<T extends number | boolean>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleUiSetting<T extends number | boolean>(key: string, n: T, o: T) {
|
||||||
|
if (key === 'toolbarScale') {
|
||||||
|
const scale = (n as number) / (o as number);
|
||||||
|
CustomToolbar.list.forEach(v => {
|
||||||
|
v.setSize(v.width * scale, v.height * scale);
|
||||||
|
});
|
||||||
|
CustomToolbar.refreshAll(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----- 游戏的所有设置项
|
// ----- 游戏的所有设置项
|
||||||
// todo: 虚拟键盘缩放,小地图楼传缩放
|
// todo: 虚拟键盘缩放,小地图楼传缩放
|
||||||
mainSetting
|
mainSetting
|
||||||
@ -407,11 +426,13 @@ mainSetting
|
|||||||
.register('heroDetail', '勇士显伤', false, COM.Boolean)
|
.register('heroDetail', '勇士显伤', false, COM.Boolean)
|
||||||
.register('transition', '界面动画', false, COM.Boolean)
|
.register('transition', '界面动画', false, COM.Boolean)
|
||||||
.register('antiAlias', '抗锯齿', false, COM.Boolean)
|
.register('antiAlias', '抗锯齿', false, COM.Boolean)
|
||||||
.register('fontSize', '字体大小', 16, COM.Number, [8, 28, 1])
|
.register('fontSize', '字体大小', 16, COM.Number, [2, 48, 1])
|
||||||
|
.register('fontSizeStatus', '状态栏字体', 16, COM.Number, [2, 48, 1])
|
||||||
.register('smoothView', '平滑镜头', true, COM.Boolean)
|
.register('smoothView', '平滑镜头', true, COM.Boolean)
|
||||||
.register('criticalGem', '临界显示方式', false, COM.Boolean)
|
.register('criticalGem', '临界显示方式', false, COM.Boolean)
|
||||||
.setDisplayFunc('criticalGem', value => (value ? '宝石数' : '攻击'))
|
.setDisplayFunc('criticalGem', value => (value ? '宝石数' : '攻击'))
|
||||||
.register('keyScale', '虚拟键盘缩放', 100, COM.Number, [25, 5, 500])
|
.register('keyScale', '虚拟键盘缩放', 100, COM.Number, [25, 5, 500])
|
||||||
|
.register('blur', '背景虚化', !isMobile, COM.Boolean)
|
||||||
)
|
)
|
||||||
.register(
|
.register(
|
||||||
'action',
|
'action',
|
||||||
@ -450,13 +471,13 @@ mainSetting
|
|||||||
.register(
|
.register(
|
||||||
'ui',
|
'ui',
|
||||||
'ui设置',
|
'ui设置',
|
||||||
new MotaSetting().register(
|
new MotaSetting()
|
||||||
'mapScale',
|
.register('mapScale', '小地图缩放', 100, COM.Number, [50, 1000, 50])
|
||||||
'小地图楼传缩放',
|
.setDisplayFunc('mapScale', value => `${value}%`)
|
||||||
100,
|
.register('toolbarScale', '工具栏缩放', 100, COM.Number, [10, 500, 10])
|
||||||
COM.Number,
|
.setDisplayFunc('toolbarScale', value => `${value}%`)
|
||||||
[50, 1000, 50]
|
.register('bookScale', '怪物手册缩放', 100, COM.Number, [10, 500, 10])
|
||||||
)
|
.setDisplayFunc('bookScale', value => `${value}%`)
|
||||||
);
|
);
|
||||||
|
|
||||||
const loading = Mota.require('var', 'loading');
|
const loading = Mota.require('var', 'loading');
|
||||||
@ -471,6 +492,7 @@ loading.once('coreInit', () => {
|
|||||||
'screen.fontSize': storage.getValue('screen.fontSize', 16),
|
'screen.fontSize': storage.getValue('screen.fontSize', 16),
|
||||||
'screen.smoothView': !!storage.getValue('screen.smoothView', true),
|
'screen.smoothView': !!storage.getValue('screen.smoothView', true),
|
||||||
'screen.criticalGem': !!storage.getValue('screen.criticalGem', false),
|
'screen.criticalGem': !!storage.getValue('screen.criticalGem', false),
|
||||||
|
'screen.fontSizeStatus': storage.getValue('screen.fontSizeStatus', 100),
|
||||||
'action.fixed': !!storage.getValue('action.fixed', true),
|
'action.fixed': !!storage.getValue('action.fixed', true),
|
||||||
'audio.bgmEnabled': !!storage.getValue('audio.bgmEnabled', true),
|
'audio.bgmEnabled': !!storage.getValue('audio.bgmEnabled', true),
|
||||||
'audio.bgmVolume': storage.getValue('audio.bgmVolume', 80),
|
'audio.bgmVolume': storage.getValue('audio.bgmVolume', 80),
|
||||||
@ -483,7 +505,12 @@ loading.once('coreInit', () => {
|
|||||||
'ui.mapScale': storage.getValue(
|
'ui.mapScale': storage.getValue(
|
||||||
'ui.mapScale',
|
'ui.mapScale',
|
||||||
isMobile ? 300 : Math.floor(window.innerWidth / 600) * 50
|
isMobile ? 300 : Math.floor(window.innerWidth / 600) * 50
|
||||||
)
|
),
|
||||||
|
'ui.toolbarScale': storage.getValue(
|
||||||
|
'ui.toolbarScale',
|
||||||
|
isMobile ? 50 : Math.floor((window.innerWidth / 1700) * 10) * 10
|
||||||
|
),
|
||||||
|
'ui.bookScale': storage.getValue('ui.bookScale', isMobile ? 100 : 80),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -515,4 +542,22 @@ mainSetting
|
|||||||
.setDescription('audio.bgmVolume', `背景音乐的音量`)
|
.setDescription('audio.bgmVolume', `背景音乐的音量`)
|
||||||
.setDescription('audio.soundEnabled', `是否开启音效`)
|
.setDescription('audio.soundEnabled', `是否开启音效`)
|
||||||
.setDescription('audio.soundVolume', `音效的音量`)
|
.setDescription('audio.soundVolume', `音效的音量`)
|
||||||
.setDescription('ui.mapScale', `楼传小地图的缩放,百分比格式`);
|
.setDescription('ui.mapScale', `楼传小地图的缩放,百分比格式`)
|
||||||
|
.setDescription('ui.toolbarScale', `自定义工具栏的缩放比例`)
|
||||||
|
.setDescription('ui.bookScale', `怪物手册界面中每个怪物框体的高度缩放,最小值限定为 20% 屏幕高度`)
|
||||||
|
.setDescription('screen.fontSizeStatus', `修改状态栏的字体大小`)
|
||||||
|
.setDescription('screen.blur', '打开任意ui界面时是否有背景虚化效果,移动端打开后可能会有掉帧或者发热现象。关闭ui后生效');
|
||||||
|
|
||||||
|
function setFontSize() {
|
||||||
|
const absoluteSize = storage.getValue(
|
||||||
|
'@@absoluteFontSize',
|
||||||
|
16 * devicePixelRatio
|
||||||
|
);
|
||||||
|
const size = Math.round(absoluteSize / devicePixelRatio);
|
||||||
|
mainSetting.setValue('screen.fontSize', size);
|
||||||
|
}
|
||||||
|
setFontSize();
|
||||||
|
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
setFontSize();
|
||||||
|
});
|
@ -4,6 +4,7 @@ import { loading } from '../game';
|
|||||||
|
|
||||||
export interface CurrentEnemy {
|
export interface CurrentEnemy {
|
||||||
enemy: DamageEnemy;
|
enemy: DamageEnemy;
|
||||||
|
// 这个是干啥的?
|
||||||
onMapEnemy: DamageEnemy[];
|
onMapEnemy: DamageEnemy[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,155 +17,64 @@ export function getEnemy(
|
|||||||
return v.x === x && v.y === y;
|
return v.x === x && v.y === y;
|
||||||
});
|
});
|
||||||
if (!enemy) {
|
if (!enemy) {
|
||||||
throw new Error(
|
return null;
|
||||||
`Get null when getting enemy on '${x},${y}' in '${floorId}'`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return enemy;
|
return enemy;
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
core.enemys.canBattle = function canBattle(
|
core.enemys.canBattle = function canBattle(
|
||||||
x: number,
|
x: number | DamageEnemy,
|
||||||
y: number,
|
y: number,
|
||||||
floorId: FloorIds = core.status.floorId
|
floorId: FloorIds = core.status.floorId
|
||||||
) {
|
) {
|
||||||
const enemy = getEnemy(x, y, floorId);
|
const enemy = typeof x === 'number' ? getEnemy(x, y, floorId) : x;
|
||||||
|
if (!enemy) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot get enemy on x:${x}, y:${y}, floor: ${floorId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
const { damage } = enemy.calDamage();
|
const { damage } = enemy.calDamage();
|
||||||
|
|
||||||
return damage < core.status.hero.hp;
|
return damage < core.status.hero.hp;
|
||||||
};
|
};
|
||||||
|
|
||||||
core.events.battle = function battle(
|
core.events.battle = function battle(
|
||||||
x: number,
|
x: number | DamageEnemy,
|
||||||
y: number,
|
y: number,
|
||||||
force: boolean = false,
|
force: boolean = false,
|
||||||
callback?: () => void
|
callback?: () => void
|
||||||
) {
|
) {
|
||||||
core.saveAndStopAutomaticRoute();
|
core.saveAndStopAutomaticRoute();
|
||||||
const enemy = getEnemy(x, y);
|
const isLoc = typeof x === 'number';
|
||||||
|
const enemy = isLoc ? getEnemy(x, y) : x;
|
||||||
|
if (!enemy) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot battle with enemy since no enemy on ${x},${y}`
|
||||||
|
);
|
||||||
|
}
|
||||||
// 非强制战斗
|
// 非强制战斗
|
||||||
|
// @ts-ignore
|
||||||
if (!core.canBattle(x, y) && !force && !core.status.event.id) {
|
if (!core.canBattle(x, y) && !force && !core.status.event.id) {
|
||||||
core.stopSound();
|
core.stopSound();
|
||||||
core.playSound('操作失败');
|
core.playSound('操作失败');
|
||||||
core.drawTip('你打不过此怪物!', enemy.id);
|
core.drawTip('你打不过此怪物!', enemy!.id);
|
||||||
return core.clearContinueAutomaticRoute(callback);
|
return core.clearContinueAutomaticRoute(callback);
|
||||||
}
|
}
|
||||||
// 自动存档
|
// 自动存档
|
||||||
if (!core.status.event.id) core.autosave(true);
|
if (!core.status.event.id) core.autosave(true);
|
||||||
// 战前事件
|
// 战前事件
|
||||||
// 战后事件
|
// 战后事件
|
||||||
core.afterBattle(enemy, x, y);
|
core.afterBattle(enemy, isLoc ? x : enemy.x, y);
|
||||||
callback?.();
|
callback?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
core.events.afterBattle = function afterBattle(
|
const getFacedId = (enemy: DamageEnemy) => {
|
||||||
enemy: DamageEnemy,
|
const e = enemy.enemy;
|
||||||
x?: number,
|
|
||||||
y?: number
|
|
||||||
) {
|
|
||||||
const floorId = core.status.floorId;
|
|
||||||
const special = enemy.info.special;
|
|
||||||
|
|
||||||
// 播放战斗动画
|
if (e.displayIdInBook) return e.displayIdInBook;
|
||||||
let animate: AnimationIds = 'hand';
|
if (e.faceIds) return e.faceIds.down;
|
||||||
// 检查当前装备是否存在攻击动画
|
return e.id;
|
||||||
const equipId = core.getEquip(0);
|
|
||||||
if (equipId && (core.material.items[equipId].equip || {}).animate)
|
|
||||||
animate = core.material.items[equipId].equip.animate;
|
|
||||||
|
|
||||||
// 检查该动画是否存在SE,如果不存在则使用默认音效
|
|
||||||
if (!core.material.animates[animate]?.se) core.playSound('attack.mp3');
|
|
||||||
|
|
||||||
// 战斗伤害
|
|
||||||
const info = enemy.calDamage(core.status.hero);
|
|
||||||
const damage = info.damage;
|
|
||||||
// 判定是否致死
|
|
||||||
if (damage >= core.status.hero.hp) {
|
|
||||||
core.status.hero.hp = 0;
|
|
||||||
core.updateStatusBar(false, true);
|
|
||||||
core.events.lose('战斗失败');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 扣减体力值并记录统计数据
|
|
||||||
core.status.hero.hp -= damage;
|
|
||||||
core.status.hero.statistics.battleDamage += damage;
|
|
||||||
core.status.hero.statistics.battle++;
|
|
||||||
|
|
||||||
// 智慧之源
|
|
||||||
if (special.includes(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.includes(22)) {
|
|
||||||
flags[`night_${floorId}`] ??= 0;
|
|
||||||
flags[`night_${floorId}`] -= enemy.enemy.night!;
|
|
||||||
}
|
|
||||||
if (special.includes(23)) {
|
|
||||||
flags[`night_${floorId}`] ??= 0;
|
|
||||||
flags[`night_${floorId}`] += enemy.enemy.day;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (core.plugin.skillTree.getSkillLevel(11) > 0) {
|
|
||||||
// core.plugin.study.declineStudiedSkill();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 如果是融化怪,需要特殊标记一下
|
|
||||||
if (special.includes(25) && has(x) && has(y)) {
|
|
||||||
flags[`melt_${floorId}`] ??= {};
|
|
||||||
flags[`melt_${floorId}`][`${x},${y}`] = enemy.enemy.melt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获得金币
|
|
||||||
const money = enemy.enemy.money;
|
|
||||||
core.status.hero.money += money;
|
|
||||||
core.status.hero.statistics.money += money;
|
|
||||||
|
|
||||||
// 获得经验
|
|
||||||
const exp = enemy.enemy.exp;
|
|
||||||
core.status.hero.exp += exp;
|
|
||||||
core.status.hero.statistics.exp += exp;
|
|
||||||
|
|
||||||
const hint =
|
|
||||||
'打败 ' + enemy.enemy.name + ',金币+' + money + ',经验+' + exp;
|
|
||||||
core.drawTip(hint, enemy.id);
|
|
||||||
|
|
||||||
if (core.getFlag('bladeOn') && core.getFlag('blade')) {
|
|
||||||
core.setFlag('blade', false);
|
|
||||||
}
|
|
||||||
if (core.getFlag('shieldOn') && core.getFlag('shield')) {
|
|
||||||
core.setFlag('shield', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 事件的处理
|
|
||||||
const todo: MotaEvent = [];
|
|
||||||
|
|
||||||
// 战后事件
|
|
||||||
if (has(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 (has(x) && has(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.enemys.getCurrentEnemys = function getCurrentEnemys(
|
core.enemys.getCurrentEnemys = function getCurrentEnemys(
|
||||||
@ -176,7 +86,8 @@ function init() {
|
|||||||
ensureFloorDamage(floorId);
|
ensureFloorDamage(floorId);
|
||||||
const floor = core.status.maps[floorId];
|
const floor = core.status.maps[floorId];
|
||||||
floor.enemy.list.forEach(v => {
|
floor.enemy.list.forEach(v => {
|
||||||
if (!(v.id in used)) {
|
const id = getFacedId(v);
|
||||||
|
if (!(id in used)) {
|
||||||
const e = new DamageEnemy(v.enemy);
|
const e = new DamageEnemy(v.enemy);
|
||||||
e.calAttribute();
|
e.calAttribute();
|
||||||
e.getRealInfo();
|
e.getRealInfo();
|
||||||
@ -186,9 +97,9 @@ function init() {
|
|||||||
onMapEnemy: [v]
|
onMapEnemy: [v]
|
||||||
};
|
};
|
||||||
enemys.push(curr);
|
enemys.push(curr);
|
||||||
used[v.id] = curr.onMapEnemy;
|
used[id] = curr.onMapEnemy;
|
||||||
} else {
|
} else {
|
||||||
used[v.id].push(v);
|
used[id].push(v);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -207,7 +118,7 @@ function init() {
|
|||||||
const enemy = getEnemy(data.x, data.y);
|
const enemy = getEnemy(data.x, data.y);
|
||||||
|
|
||||||
beforeBattle.push(...(floor.beforeBattle[loc] ?? []));
|
beforeBattle.push(...(floor.beforeBattle[loc] ?? []));
|
||||||
beforeBattle.push(...(enemy.enemy.beforeBattle ?? []));
|
beforeBattle.push(...(enemy!.enemy.beforeBattle ?? []));
|
||||||
|
|
||||||
if (beforeBattle.length > 0) {
|
if (beforeBattle.length > 0) {
|
||||||
beforeBattle.push({ type: 'battle', x: data.x, y: data.y });
|
beforeBattle.push({ type: 'battle', x: data.x, y: data.y });
|
||||||
@ -251,5 +162,22 @@ loading.once('coreInit', init);
|
|||||||
declare global {
|
declare global {
|
||||||
interface Enemys {
|
interface Enemys {
|
||||||
getCurrentEnemys(floorId: FloorIds): CurrentEnemy[];
|
getCurrentEnemys(floorId: FloorIds): CurrentEnemy[];
|
||||||
|
canBattle(enemy: DamageEnemy, _?: number, floorId?: FloorIds): boolean;
|
||||||
|
canBattle(x: number, y: number, floorId?: FloorIds): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Events {
|
||||||
|
battle(
|
||||||
|
enemy: DamageEnemy,
|
||||||
|
_?: number,
|
||||||
|
force?: boolean,
|
||||||
|
callback?: () => void
|
||||||
|
): void;
|
||||||
|
battle(
|
||||||
|
x: number,
|
||||||
|
y?: number,
|
||||||
|
force?: boolean,
|
||||||
|
callback?: () => void
|
||||||
|
): void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,15 +16,15 @@ interface HaloType {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EnemyInfo {
|
interface EnemyInfo extends Partial<Enemy> {
|
||||||
atk: number;
|
atk: number;
|
||||||
def: number;
|
def: number;
|
||||||
hp: number;
|
hp: number;
|
||||||
special: number[];
|
special: number[];
|
||||||
damageDecline: number;
|
damageDecline: number;
|
||||||
atkBuff: number;
|
atkBuff_: number;
|
||||||
defBuff: number;
|
defBuff_: number;
|
||||||
hpBuff: number;
|
hpBuff_: number;
|
||||||
enemy: Enemy;
|
enemy: Enemy;
|
||||||
x?: number;
|
x?: number;
|
||||||
y?: number;
|
y?: number;
|
||||||
@ -65,7 +65,7 @@ interface CriticalDamageDelta extends Omit<DamageDelta, 'info'> {
|
|||||||
type HaloFn = (info: EnemyInfo, enemy: Enemy) => void;
|
type HaloFn = (info: EnemyInfo, enemy: Enemy) => void;
|
||||||
|
|
||||||
/** 光环属性 */
|
/** 光环属性 */
|
||||||
export const haloSpecials: number[] = [8, 21, 25, 26, 27];
|
export const haloSpecials: Set<number> = new Set([8, 21, 25, 26, 27]);
|
||||||
|
|
||||||
export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
export class EnemyCollection implements RangeCollection<DamageEnemy> {
|
||||||
floorId: FloorIds;
|
floorId: FloorIds;
|
||||||
@ -302,7 +302,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
info!: EnemyInfo;
|
info!: EnemyInfo;
|
||||||
|
|
||||||
/** 向其他怪提供过的光环 */
|
/** 向其他怪提供过的光环 */
|
||||||
providedHalo: number[] = [];
|
providedHalo: Set<number> = new Set();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 伤害计算进度,0 -> 预平衡光环 -> 1 -> 计算没有光环的属性 -> 2 -> provide inject 光环
|
* 伤害计算进度,0 -> 预平衡光环 -> 1 -> 计算没有光环的属性 -> 2 -> provide inject 光环
|
||||||
@ -334,16 +334,23 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
def: enemy.def,
|
def: enemy.def,
|
||||||
special: enemy.special.slice(),
|
special: enemy.special.slice(),
|
||||||
damageDecline: 0,
|
damageDecline: 0,
|
||||||
atkBuff: 0,
|
atkBuff_: 0,
|
||||||
defBuff: 0,
|
defBuff_: 0,
|
||||||
hpBuff: 0,
|
hpBuff_: 0,
|
||||||
enemy: this.enemy,
|
enemy: this.enemy,
|
||||||
x: this.x,
|
x: this.x,
|
||||||
y: this.y,
|
y: this.y,
|
||||||
floorId: this.floorId
|
floorId: this.floorId
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(enemy)) {
|
||||||
|
if (!(key in this.info) && has(value)) {
|
||||||
|
// @ts-ignore
|
||||||
|
this.info[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.progress = 0;
|
this.progress = 0;
|
||||||
this.providedHalo = [];
|
this.providedHalo.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -370,8 +377,8 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
for (const [loc, per] of Object.entries(flags[`melt_${floorId}`])) {
|
for (const [loc, per] of Object.entries(flags[`melt_${floorId}`])) {
|
||||||
const [mx, my] = loc.split(',').map(v => parseInt(v));
|
const [mx, my] = loc.split(',').map(v => parseInt(v));
|
||||||
if (Math.abs(mx - this.x) <= 1 && Math.abs(my - this.y) <= 1) {
|
if (Math.abs(mx - this.x) <= 1 && Math.abs(my - this.y) <= 1) {
|
||||||
info.atkBuff += per as number;
|
info.atkBuff_ += per as number;
|
||||||
info.defBuff += per as number;
|
info.defBuff_ += per as number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,9 +399,9 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
// 此时已经inject光环,因此直接计算真实属性
|
// 此时已经inject光环,因此直接计算真实属性
|
||||||
const info = this.info;
|
const info = this.info;
|
||||||
|
|
||||||
info.atk = Math.floor(info.atk * (info.atkBuff / 100 + 1));
|
info.atk = Math.floor(info.atk * (info.atkBuff_ / 100 + 1));
|
||||||
info.def = Math.floor(info.def * (info.defBuff / 100 + 1));
|
info.def = Math.floor(info.def * (info.defBuff_ / 100 + 1));
|
||||||
info.hp = Math.floor(info.hp * (info.hpBuff / 100 + 1));
|
info.hp = Math.floor(info.hp * (info.hpBuff_ / 100 + 1));
|
||||||
|
|
||||||
return this.info;
|
return this.info;
|
||||||
}
|
}
|
||||||
@ -404,7 +411,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
if (!has(this.x) || !has(this.y)) return [];
|
if (!has(this.x) || !has(this.y)) return [];
|
||||||
const special = this.info.special ?? this.enemy.special;
|
const special = this.info.special ?? this.enemy.special;
|
||||||
const filter = special.filter(v => {
|
const filter = special.filter(v => {
|
||||||
return haloSpecials.includes(v) && !this.providedHalo.includes(v);
|
return haloSpecials.has(v) && !this.providedHalo.has(v);
|
||||||
});
|
});
|
||||||
if (filter.length === 0) return [];
|
if (filter.length === 0) return [];
|
||||||
const collection = this.col ?? core.status.maps[this.floorId].enemy;
|
const collection = this.col ?? core.status.maps[this.floorId].enemy;
|
||||||
@ -448,11 +455,11 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
e.special.includes(8) &&
|
e.special.includes(8) &&
|
||||||
(e.x !== this.x || this.y !== e.y)
|
(e.x !== this.x || this.y !== e.y)
|
||||||
) {
|
) {
|
||||||
e.atkBuff += enemy.together ?? 0;
|
e.atkBuff_ += enemy.together ?? 0;
|
||||||
e.defBuff += enemy.together ?? 0;
|
e.defBuff_ += enemy.together ?? 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.providedHalo.push(8);
|
this.providedHalo.add(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 冰封光环
|
// 冰封光环
|
||||||
@ -460,7 +467,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
square7.push(e => {
|
square7.push(e => {
|
||||||
e.damageDecline += this.enemy.iceHalo ?? 0;
|
e.damageDecline += this.enemy.iceHalo ?? 0;
|
||||||
});
|
});
|
||||||
this.providedHalo.push(21);
|
this.providedHalo.add(21);
|
||||||
col.haloList.push({
|
col.haloList.push({
|
||||||
type: 'square',
|
type: 'square',
|
||||||
data: { x: this.x, y: this.y, d: 7 },
|
data: { x: this.x, y: this.y, d: 7 },
|
||||||
@ -472,9 +479,9 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
// 冰封之核
|
// 冰封之核
|
||||||
if (special.includes(26)) {
|
if (special.includes(26)) {
|
||||||
square5.push(e => {
|
square5.push(e => {
|
||||||
e.defBuff += this.enemy.iceCore ?? 0;
|
e.defBuff_ += this.enemy.iceCore ?? 0;
|
||||||
});
|
});
|
||||||
this.providedHalo.push(26);
|
this.providedHalo.add(26);
|
||||||
col.haloList.push({
|
col.haloList.push({
|
||||||
type: 'square',
|
type: 'square',
|
||||||
data: { x: this.x, y: this.y, d: 5 },
|
data: { x: this.x, y: this.y, d: 5 },
|
||||||
@ -486,9 +493,9 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
// 火焰之核
|
// 火焰之核
|
||||||
if (special.includes(27)) {
|
if (special.includes(27)) {
|
||||||
square5.push(e => {
|
square5.push(e => {
|
||||||
e.atkBuff += this.enemy.fireCore ?? 0;
|
e.atkBuff_ += this.enemy.fireCore ?? 0;
|
||||||
});
|
});
|
||||||
this.providedHalo.push(27);
|
this.providedHalo.add(27);
|
||||||
col.haloList.push({
|
col.haloList.push({
|
||||||
type: 'square',
|
type: 'square',
|
||||||
data: { x: this.x, y: this.y, d: 5 },
|
data: { x: this.x, y: this.y, d: 5 },
|
||||||
@ -617,7 +624,7 @@ export class DamageEnemy<T extends EnemyIds = EnemyIds> {
|
|||||||
) {
|
) {
|
||||||
damage[loc] ??= { damage: 0, type: new Set() };
|
damage[loc] ??= { damage: 0, type: new Set() };
|
||||||
damage[loc].damage += dam;
|
damage[loc].damage += dam;
|
||||||
damage[loc].type.add(type);
|
if (type) damage[loc].type.add(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private calEnemyDamageOf(hero: Partial<HeroStatus>, enemy: EnemyInfo) {
|
private calEnemyDamageOf(hero: Partial<HeroStatus>, enemy: EnemyInfo) {
|
||||||
@ -830,6 +837,9 @@ const skills: [unlock: string, condition: string][] = [
|
|||||||
['shieldOn', 'shield']
|
['shieldOn', 'shield']
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const haloValue: Map<number, SelectKey<Enemy, number | undefined>[]> =
|
||||||
|
new Map();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算怪物伤害
|
* 计算怪物伤害
|
||||||
* @param info 怪物信息
|
* @param info 怪物信息
|
||||||
@ -946,13 +956,6 @@ export function getSingleEnemy(id: EnemyIds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface PluginDeclaration {
|
|
||||||
damage: {
|
|
||||||
Enemy: typeof DamageEnemy;
|
|
||||||
Collection: typeof EnemyCollection;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Floor {
|
interface Floor {
|
||||||
enemy: EnemyCollection;
|
enemy: EnemyCollection;
|
||||||
}
|
}
|
||||||
|
@ -84,14 +84,16 @@ export interface GameEvent extends EmitableEvent {
|
|||||||
mounted: () => void;
|
mounted: () => void;
|
||||||
/** Emitted in plugin/ui.js */
|
/** Emitted in plugin/ui.js */
|
||||||
statusBarUpdate: () => void;
|
statusBarUpdate: () => void;
|
||||||
/** Emitted in libs/events.js */
|
/** Emitted in core/index.ts */
|
||||||
afterGetItem: (
|
renderLoaded: () => void;
|
||||||
itemId: AllIdsOf<'items'>,
|
// /** Emitted in libs/events.js */
|
||||||
x: number,
|
// afterGetItem: (
|
||||||
y: number,
|
// itemId: AllIdsOf<'items'>,
|
||||||
isGentleClick: boolean
|
// x: number,
|
||||||
) => void;
|
// y: number,
|
||||||
afterOpenDoor: (doorId: AllIdsOf<'animates'>, x: number, y: number) => void;
|
// isGentleClick: boolean
|
||||||
|
// ) => void;
|
||||||
|
// afterOpenDoor: (doorId: AllIdsOf<'animates'>, x: number, y: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hook = new EventEmitter<GameEvent>();
|
export const hook = new EventEmitter<GameEvent>();
|
||||||
@ -112,7 +114,7 @@ class GameListener extends EventEmitter<ListenerEvent> {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
if (main.replayChecking) return;
|
||||||
if (!!window.core) {
|
if (!!window.core) {
|
||||||
this.init();
|
this.init();
|
||||||
} else {
|
} else {
|
||||||
@ -131,14 +133,19 @@ class GameListener extends EventEmitter<ListenerEvent> {
|
|||||||
|
|
||||||
const getBlockLoc = (px: number, py: number, size: number) => {
|
const getBlockLoc = (px: number, py: number, size: number) => {
|
||||||
return [
|
return [
|
||||||
Math.floor(((px * 32) / size - core.bigmap.offsetX) / 32),
|
Math.floor(((px * 32) / size + core.bigmap.offsetX) / 32),
|
||||||
Math.floor(((py * 32) / size - core.bigmap.offsetY) / 32)
|
Math.floor(((py * 32) / size + core.bigmap.offsetY) / 32)
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
// hover & leave & mouseMove
|
// hover & leave & mouseMove
|
||||||
data.addEventListener('mousemove', e => {
|
data.addEventListener('mousemove', e => {
|
||||||
if (core.status.lockControl || !core.isPlaying()) return;
|
if (
|
||||||
|
core.status.lockControl ||
|
||||||
|
!core.isPlaying() ||
|
||||||
|
!core.status.floorId
|
||||||
|
)
|
||||||
|
return;
|
||||||
this.emit('mouseMove', e);
|
this.emit('mouseMove', e);
|
||||||
const {
|
const {
|
||||||
x: px,
|
x: px,
|
||||||
@ -164,7 +171,12 @@ class GameListener extends EventEmitter<ListenerEvent> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
data.addEventListener('mouseleave', e => {
|
data.addEventListener('mouseleave', e => {
|
||||||
if (core.status.lockControl || !core.isPlaying()) return;
|
if (
|
||||||
|
core.status.lockControl ||
|
||||||
|
!core.isPlaying() ||
|
||||||
|
!core.status.floorId
|
||||||
|
)
|
||||||
|
return;
|
||||||
const blocks = core.getMapBlocksObj();
|
const blocks = core.getMapBlocksObj();
|
||||||
const lastBlock = blocks[`${lastHoverX},${lastHoverY}`];
|
const lastBlock = blocks[`${lastHoverX},${lastHoverY}`];
|
||||||
if (!!lastBlock) {
|
if (!!lastBlock) {
|
||||||
@ -175,7 +187,12 @@ class GameListener extends EventEmitter<ListenerEvent> {
|
|||||||
});
|
});
|
||||||
// click
|
// click
|
||||||
data.addEventListener('click', e => {
|
data.addEventListener('click', e => {
|
||||||
if (core.status.lockControl || !core.isPlaying()) return;
|
if (
|
||||||
|
core.status.lockControl ||
|
||||||
|
!core.isPlaying() ||
|
||||||
|
!core.status.floorId
|
||||||
|
)
|
||||||
|
return;
|
||||||
const {
|
const {
|
||||||
x: px,
|
x: px,
|
||||||
y: py,
|
y: py,
|
||||||
|
@ -18,11 +18,7 @@ import type { Keyboard } from '@/core/main/custom/keyboard';
|
|||||||
import type { CustomToolbar } from '@/core/main/custom/toolbar';
|
import type { CustomToolbar } from '@/core/main/custom/toolbar';
|
||||||
import type { Focus, GameUi, UiController } from '@/core/main/custom/ui';
|
import type { Focus, GameUi, UiController } from '@/core/main/custom/ui';
|
||||||
import type { gameListener, hook } from './game';
|
import type { gameListener, hook } from './game';
|
||||||
import type {
|
import type { MotaSetting, SettingDisplayer } from '@/core/main/setting';
|
||||||
MotaSetting,
|
|
||||||
SettingDisplayer,
|
|
||||||
SettingStorage
|
|
||||||
} from '@/core/main/setting';
|
|
||||||
import type { GameStorage } from '@/core/main/storage';
|
import type { GameStorage } from '@/core/main/storage';
|
||||||
import type { DamageEnemy, EnemyCollection } from './enemy/damage';
|
import type { DamageEnemy, EnemyCollection } from './enemy/damage';
|
||||||
import type { specials } from './enemy/special';
|
import type { specials } from './enemy/special';
|
||||||
@ -87,7 +83,7 @@ interface VariableInterface {
|
|||||||
sound: SoundController;
|
sound: SoundController;
|
||||||
resource: ResourceStore<Exclude<ResourceType, 'zip'>>;
|
resource: ResourceStore<Exclude<ResourceType, 'zip'>>;
|
||||||
zipResource: ResourceStore<'zip'>;
|
zipResource: ResourceStore<'zip'>;
|
||||||
settingStorage: GameStorage<SettingStorage>;
|
settingStorage: GameStorage;
|
||||||
status: Ref<boolean>;
|
status: Ref<boolean>;
|
||||||
// 定义于游戏进程,渲染进程依然可用
|
// 定义于游戏进程,渲染进程依然可用
|
||||||
haloSpecials: number[];
|
haloSpecials: number[];
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Inspired somewhat from https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
* Inspired somewhat from https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
||||||
* But these are "more general", as they should work across browsers & OS`s.
|
* But these are "more general", as they should work across browsers & OS`s.
|
||||||
*/
|
*/
|
||||||
export enum KeyCode {
|
export enum KeyCode {
|
||||||
DependsOnKbLayout = -1,
|
DependsOnKbLayout = -1,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
export const status = ref(false);
|
export const status = ref(false);
|
||||||
|
export const fontSize = ref(100);
|
||||||
|
5
src/types/enemy.d.ts
vendored
5
src/types/enemy.d.ts
vendored
@ -71,6 +71,11 @@ type Enemy<I extends EnemyIds = EnemyIds> = {
|
|||||||
*/
|
*/
|
||||||
displayIdInBook: EnemyIds;
|
displayIdInBook: EnemyIds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行走图朝向。在勇士撞上图块时,或图块在移动时,会自动选择最合适的朝向图块(如果存在定义)来进行绘制。
|
||||||
|
*/
|
||||||
|
faceIds: Record<Dir, EnemyIds>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 战前事件
|
* 战前事件
|
||||||
*/
|
*/
|
||||||
|
26
src/types/event.d.ts
vendored
26
src/types/event.d.ts
vendored
@ -99,22 +99,6 @@ interface Events extends EventData {
|
|||||||
*/
|
*/
|
||||||
trigger(x: number, y: number, callback?: () => void): void;
|
trigger(x: number, y: number, callback?: () => void): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* 战斗,如果填写了坐标就会删除该点的敌人并触发战后事件
|
|
||||||
* @example core.battle('greenSlime'); // 和从天而降的绿头怪战斗(如果打得过)
|
|
||||||
* @param id 敌人id,必填
|
|
||||||
* @param x 敌人的横坐标
|
|
||||||
* @param y 敌人的纵坐标
|
|
||||||
* @param force true表示强制战斗
|
|
||||||
* @param callback 回调函数
|
|
||||||
*/
|
|
||||||
battle(
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
force: boolean = false,
|
|
||||||
callback?: () => void
|
|
||||||
): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开门(包括三种基础墙)
|
* 开门(包括三种基础墙)
|
||||||
* @example core.openDoor(0, 0, true, core.jumpHero); // 打开左上角的门,需要钥匙,然后主角原地跳跃半秒
|
* @example core.openDoor(0, 0, true, core.jumpHero); // 打开左上角的门,需要钥匙,然后主角原地跳跃半秒
|
||||||
@ -428,6 +412,7 @@ interface Events extends EventData {
|
|||||||
): void;
|
): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated 已失效(大概
|
||||||
* 设置一项敌人属性并计入存档
|
* 设置一项敌人属性并计入存档
|
||||||
* @example core.setEnemy('greenSlime', 'def', 0); // 把绿头怪的防御设为0
|
* @example core.setEnemy('greenSlime', 'def', 0); // 把绿头怪的防御设为0
|
||||||
* @param id 敌人id
|
* @param id 敌人id
|
||||||
@ -447,6 +432,7 @@ interface Events extends EventData {
|
|||||||
): void;
|
): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated 已失效(大概
|
||||||
* 设置某个点的敌人属性
|
* 设置某个点的敌人属性
|
||||||
* @param x 横坐标
|
* @param x 横坐标
|
||||||
* @param y 纵坐标
|
* @param y 纵坐标
|
||||||
@ -469,6 +455,7 @@ interface Events extends EventData {
|
|||||||
): void;
|
): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated 已失效(大概
|
||||||
* 重置某个点的敌人属性
|
* 重置某个点的敌人属性
|
||||||
* @param x 横坐标
|
* @param x 横坐标
|
||||||
* @param y 纵坐标
|
* @param y 纵坐标
|
||||||
@ -483,6 +470,7 @@ interface Events extends EventData {
|
|||||||
): void;
|
): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated 已失效(大概
|
||||||
* 将某个点已经设置的敌人属性移动到其他点
|
* 将某个点已经设置的敌人属性移动到其他点
|
||||||
* @param fromX 起始横坐标
|
* @param fromX 起始横坐标
|
||||||
* @param fromY 起始纵坐标
|
* @param fromY 起始纵坐标
|
||||||
@ -756,7 +744,11 @@ interface Events extends EventData {
|
|||||||
* @example core.tryUseItem('pickaxe'); // 尝试使用破墙镐
|
* @example core.tryUseItem('pickaxe'); // 尝试使用破墙镐
|
||||||
* @param itemId 道具id,其中敌人手册、传送器和飞行器会被特殊处理
|
* @param itemId 道具id,其中敌人手册、传送器和飞行器会被特殊处理
|
||||||
*/
|
*/
|
||||||
tryUseItem(itemId: ItemIdOf<'tools' | 'constants'>): void;
|
tryUseItem(
|
||||||
|
itemId: ItemIdOf<'tools' | 'constants'>,
|
||||||
|
noRoute?: boolean,
|
||||||
|
callback?: () => void
|
||||||
|
): void;
|
||||||
|
|
||||||
_sys_battle(data: Block, callback?: () => void): void;
|
_sys_battle(data: Block, callback?: () => void): void;
|
||||||
|
|
||||||
|
@ -50,6 +50,8 @@ import { getDetailedEnemy } from '../plugin/ui/fixed';
|
|||||||
import { GameUi } from '@/core/main/custom/ui';
|
import { GameUi } from '@/core/main/custom/ui';
|
||||||
import { gameKey } from '@/core/main/init/hotkey';
|
import { gameKey } from '@/core/main/init/hotkey';
|
||||||
import { mainUi } from '@/core/main/init/ui';
|
import { mainUi } from '@/core/main/init/ui';
|
||||||
|
import { mainSetting } from '@/core/main/setting';
|
||||||
|
import { isMobile } from '@/plugin/use';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
num: number;
|
num: number;
|
||||||
@ -70,6 +72,14 @@ const drag = ref(false);
|
|||||||
const detail = ref(false);
|
const detail = ref(false);
|
||||||
const selected = ref(0);
|
const selected = ref(0);
|
||||||
|
|
||||||
|
const settingScale = mainSetting.getValue('ui.bookScale', 100) / 100;
|
||||||
|
const scale = isMobile
|
||||||
|
? Math.max(settingScale * 15, 20)
|
||||||
|
: Math.max(
|
||||||
|
(window.innerWidth / window.innerHeight) * 15 * settingScale,
|
||||||
|
20
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选择怪物,展示详细信息
|
* 选择怪物,展示详细信息
|
||||||
* @param enemy 选择的怪物
|
* @param enemy 选择的怪物
|
||||||
@ -121,11 +131,13 @@ async function exit() {
|
|||||||
const hold = mainUi.holdOn();
|
const hold = mainUi.holdOn();
|
||||||
mainUi.close(props.num);
|
mainUi.close(props.num);
|
||||||
if (core.events.recoverEvents(core.status.event.interval)) {
|
if (core.events.recoverEvents(core.status.event.interval)) {
|
||||||
|
hold.end(true);
|
||||||
return;
|
return;
|
||||||
} else if (has(core.status.event.ui)) {
|
} else if (has(core.status.event.ui)) {
|
||||||
core.status.boxAnimateObjs = [];
|
core.status.boxAnimateObjs = [];
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
core.ui._drawViewMaps(core.status.event.ui);
|
core.ui._drawViewMaps(core.status.event.ui);
|
||||||
|
hold.end(true);
|
||||||
} else hold.end();
|
} else hold.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,42 +153,44 @@ function checkScroll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 按键控制
|
// 按键控制
|
||||||
gameKey.use(props.ui.symbol);
|
setTimeout(() => {
|
||||||
gameKey
|
gameKey.use(props.ui.symbol);
|
||||||
.realize('@book_up', () => {
|
gameKey
|
||||||
if (selected.value > 0) {
|
.realize('@book_up', () => {
|
||||||
selected.value--;
|
if (selected.value > 0) {
|
||||||
}
|
selected.value--;
|
||||||
checkScroll();
|
}
|
||||||
})
|
checkScroll();
|
||||||
.realize('@book_down', () => {
|
})
|
||||||
if (selected.value < enemy.length - 1) {
|
.realize('@book_down', () => {
|
||||||
selected.value++;
|
if (selected.value < enemy.length - 1) {
|
||||||
}
|
selected.value++;
|
||||||
checkScroll();
|
}
|
||||||
})
|
checkScroll();
|
||||||
.realize('@book_pageDown', () => {
|
})
|
||||||
if (selected.value <= 4) {
|
.realize('@book_pageDown', () => {
|
||||||
selected.value = 0;
|
if (selected.value <= 4) {
|
||||||
} else {
|
selected.value = 0;
|
||||||
selected.value -= 5;
|
} else {
|
||||||
}
|
selected.value -= 5;
|
||||||
checkScroll();
|
}
|
||||||
})
|
checkScroll();
|
||||||
.realize('@book_pageUp', () => {
|
})
|
||||||
if (selected.value >= enemy.length - 5) {
|
.realize('@book_pageUp', () => {
|
||||||
selected.value = enemy.length - 1;
|
if (selected.value >= enemy.length - 5) {
|
||||||
} else {
|
selected.value = enemy.length - 1;
|
||||||
selected.value += 5;
|
} else {
|
||||||
}
|
selected.value += 5;
|
||||||
checkScroll();
|
}
|
||||||
})
|
checkScroll();
|
||||||
.realize('exit', () => {
|
})
|
||||||
exit();
|
.realize('exit', () => {
|
||||||
})
|
exit();
|
||||||
.realize('confirm', () => {
|
})
|
||||||
select(toShow[selected.value], selected.value);
|
.realize('confirm', () => {
|
||||||
});
|
select(toShow[selected.value], selected.value);
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
gameKey.dispose(props.ui.symbol);
|
gameKey.dispose(props.ui.symbol);
|
||||||
@ -188,7 +202,6 @@ onUnmounted(() => {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-family: 'normal';
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: opacity 0.6s linear;
|
transition: opacity 0.6s linear;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -208,25 +221,28 @@ onUnmounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-family: 'normal';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.enemy {
|
.enemy {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 20vh;
|
height: v-bind('scale + "vh"');
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 1% 0 1%;
|
padding: 0 1% 0 1%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
|
#tools {
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
#book {
|
#book {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 5%;
|
padding: 5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.enemy {
|
.enemy {
|
||||||
height: 15vh;
|
height: v-bind('scale * 2 / 3 + "vh"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
<!-- 怪物详细信息 -->
|
<!-- 怪物详细信息 -->
|
||||||
<template>
|
<template>
|
||||||
<div id="detail">
|
<div id="detail">
|
||||||
|
<div id="tools">
|
||||||
|
<span id="back" class="button-text tools" @click="close"
|
||||||
|
><left-outlined />返回</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<div id="info" :style="{ top: `${top}px` }">
|
<div id="info" :style="{ top: `${top}px` }">
|
||||||
<EnemyOne :enemy="enemy!"></EnemyOne>
|
<EnemyOne :enemy="enemy!"></EnemyOne>
|
||||||
<a-divider
|
<a-divider
|
||||||
@ -172,7 +177,7 @@ onUnmounted(() => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 72%;
|
width: 72%;
|
||||||
height: 90%;
|
height: 100%;
|
||||||
transition: all 0.6s ease;
|
transition: all 0.6s ease;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
@ -208,6 +213,15 @@ onUnmounted(() => {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tools {
|
||||||
|
position: fixed;
|
||||||
|
height: 6%;
|
||||||
|
font-size: 3.2vh;
|
||||||
|
width: 100%;
|
||||||
|
left: 5%;
|
||||||
|
top: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
#detail {
|
#detail {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -220,7 +234,11 @@ onUnmounted(() => {
|
|||||||
font-size: 4vw;
|
font-size: 4vw;
|
||||||
bottom: 5%;
|
bottom: 5%;
|
||||||
left: 5vw;
|
left: 5vw;
|
||||||
width: 90vw;
|
width: 80vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
#info {
|
||||||
|
transform: translateY(10%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -701,14 +701,9 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
#equipbox {
|
|
||||||
padding: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#equipbox-main {
|
#equipbox-main {
|
||||||
height: 90vh;
|
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
font-size: 100%;
|
font-size: 225%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#equip-now-div {
|
#equip-now-div {
|
||||||
@ -721,7 +716,11 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#equip-list {
|
#equip-list {
|
||||||
flex-basis: 50%;
|
flex-basis: 45%;
|
||||||
|
|
||||||
|
#filter #sort-type {
|
||||||
|
font-size: 150%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.divider {
|
.divider {
|
||||||
|
@ -56,15 +56,15 @@
|
|||||||
:type="isMobile ? 'horizontal' : 'vertical'"
|
:type="isMobile ? 'horizontal' : 'vertical'"
|
||||||
></a-divider>
|
></a-divider>
|
||||||
<div id="fly-right">
|
<div id="fly-right">
|
||||||
<canvas id="fly-thumbnail" @click="fly"></canvas>
|
<canvas id="fly-thumbnail" @click="fly" @wheel="wheel"></canvas>
|
||||||
<div id="fly-tools">
|
<div id="fly-tools">
|
||||||
<double-left-outlined
|
<double-left-outlined
|
||||||
@click="changeFloorByDelta(-10)"
|
@click="changeFloorByDelta(-10)"
|
||||||
class="button-text"
|
class="button-text fly-button"
|
||||||
/>
|
/>
|
||||||
<left-outlined
|
<left-outlined
|
||||||
@click="changeFloorByDelta(-1)"
|
@click="changeFloorByDelta(-1)"
|
||||||
class="button-text"
|
class="button-text fly-button"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="changable"
|
class="changable"
|
||||||
@ -74,11 +74,11 @@
|
|||||||
>
|
>
|
||||||
<right-outlined
|
<right-outlined
|
||||||
@click="changeFloorByDelta(1)"
|
@click="changeFloorByDelta(1)"
|
||||||
class="button-text"
|
class="button-text fly-button"
|
||||||
/>
|
/>
|
||||||
<double-right-outlined
|
<double-right-outlined
|
||||||
@click="changeFloorByDelta(10)"
|
@click="changeFloorByDelta(10)"
|
||||||
class="button-text"
|
class="button-text fly-button"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -472,6 +472,10 @@ function click(e: MouseEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wheel(ev: WheelEvent) {
|
||||||
|
changeFloorByDelta(-Math.sign(ev.deltaY));
|
||||||
|
}
|
||||||
|
|
||||||
function changeAreaByFloor(id: FloorIds) {
|
function changeAreaByFloor(id: FloorIds) {
|
||||||
nowArea.value = Object.keys(area).find(v => area[v].includes(id))!;
|
nowArea.value = Object.keys(area).find(v => area[v].includes(id))!;
|
||||||
}
|
}
|
||||||
@ -725,6 +729,7 @@ onUnmounted(() => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#fly-tools {
|
#fly-tools {
|
||||||
@ -734,11 +739,17 @@ onUnmounted(() => {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #0004;
|
||||||
}
|
}
|
||||||
|
|
||||||
#fly-thumbnail {
|
#fly-thumbnail {
|
||||||
width: 35vw;
|
width: 35vw;
|
||||||
height: 35vw;
|
height: 35vw;
|
||||||
|
max-height: 75vh;
|
||||||
|
max-width: 75vh;
|
||||||
border: 0.1vw solid #ddd4;
|
border: 0.1vw solid #ddd4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,10 +777,27 @@ onUnmounted(() => {
|
|||||||
background-color: #ddd4;
|
background-color: #ddd4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fly-button {
|
||||||
|
padding: 3%;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.301);
|
||||||
|
border: 1px dashed #ddda;
|
||||||
|
filter: drop-shadow(0px 0px 16px black);
|
||||||
|
}
|
||||||
|
|
||||||
|
#fly-now {
|
||||||
|
text-wrap: nowrap;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 50%;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
text-shadow: 1px 1px 1px black, 1px -1px 1px black, -1px 1px 1px black,
|
||||||
|
-1px -1px 1px black;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
#fly {
|
#fly {
|
||||||
padding: 5%;
|
font-size: 225%;
|
||||||
font-size: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#fly-main {
|
#fly-main {
|
||||||
|
@ -242,7 +242,7 @@ onUnmounted(() => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
text-overflow: clip;
|
text-overflow: clip;
|
||||||
align-items: end;
|
align-items: flex-end;
|
||||||
text-align: end;
|
text-align: end;
|
||||||
|
|
||||||
.hotkey-one-set-item {
|
.hotkey-one-set-item {
|
||||||
|
@ -108,7 +108,7 @@ function update() {
|
|||||||
info.damage = enemy.enemy.calDamage().damage;
|
info.damage = enemy.enemy.calDamage().damage;
|
||||||
const critical = enemy.enemy.calCritical()[0];
|
const critical = enemy.enemy.calCritical()[0];
|
||||||
info.critical = critical?.atkDelta ?? 0;
|
info.critical = critical?.atkDelta ?? 0;
|
||||||
info.criticalDam = critical.delta ?? 0;
|
info.criticalDam = critical?.delta ?? 0;
|
||||||
info.defDamage = enemy.enemy.calDefDamage(ratio).delta;
|
info.defDamage = enemy.enemy.calDefDamage(ratio).delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,15 +46,19 @@
|
|||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-info">
|
<div class="setting-info">
|
||||||
<div
|
<Scroll class="info-text-scroll">
|
||||||
class="info-text"
|
<div
|
||||||
v-html="splitText(display.at(-1)?.text ?? ['请选择设置'])"
|
class="info-text"
|
||||||
></div>
|
v-html="
|
||||||
|
splitText(display.at(-1)?.text ?? ['请选择设置'])
|
||||||
|
"
|
||||||
|
></div>
|
||||||
|
</Scroll>
|
||||||
<a-divider class="info-divider" dashed></a-divider>
|
<a-divider class="info-divider" dashed></a-divider>
|
||||||
<div class="info-editor" v-if="!!selectedItem">
|
<div class="info-editor" v-if="!!selectedItem">
|
||||||
<div class="editor-custom">
|
<div class="editor-custom">
|
||||||
<component
|
<component
|
||||||
:is="selectedItem.controller"
|
:is="(selectedItem.controller as any)"
|
||||||
:item="selectedItem"
|
:item="selectedItem"
|
||||||
:displayer="displayer"
|
:displayer="displayer"
|
||||||
:setting="setting"
|
:setting="setting"
|
||||||
@ -68,16 +72,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, onUnmounted, ref, shallowRef } from 'vue';
|
import { computed, onUnmounted, ref, shallowRef } from 'vue';
|
||||||
import {
|
import {
|
||||||
mainSetting,
|
mainSetting,
|
||||||
MotaSetting,
|
MotaSetting,
|
||||||
MotaSettingItem,
|
MotaSettingItem,
|
||||||
SettingDisplayer,
|
SettingDisplayer,
|
||||||
SettingDisplayInfo,
|
SettingDisplayInfo
|
||||||
SettingText
|
|
||||||
} from '../core/main/setting';
|
} from '../core/main/setting';
|
||||||
import settingText from '../data/settings.json';
|
|
||||||
import { RightOutlined, LeftOutlined } from '@ant-design/icons-vue';
|
import { RightOutlined, LeftOutlined } from '@ant-design/icons-vue';
|
||||||
import { splitText } from '../plugin/utils';
|
import { splitText } from '../plugin/utils';
|
||||||
import Scroll from '../components/scroll.vue';
|
import Scroll from '../components/scroll.vue';
|
||||||
@ -88,13 +90,11 @@ import { mainUi } from '@/core/main/init/ui';
|
|||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
info?: MotaSetting;
|
info?: MotaSetting;
|
||||||
text?: SettingText;
|
|
||||||
num: number;
|
num: number;
|
||||||
ui: GameUi;
|
ui: GameUi;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const setting = props.info ?? mainSetting;
|
const setting = props.info ?? mainSetting;
|
||||||
const text = props.text ?? (settingText as SettingText);
|
|
||||||
const display = shallowRef<SettingDisplayInfo[]>([]);
|
const display = shallowRef<SettingDisplayInfo[]>([]);
|
||||||
const selectedItem = computed(() => display.value.at(-1)?.item);
|
const selectedItem = computed(() => display.value.at(-1)?.item);
|
||||||
const update = ref(false);
|
const update = ref(false);
|
||||||
@ -312,6 +312,11 @@ onUnmounted(() => {
|
|||||||
.info-text {
|
.info-text {
|
||||||
font-size: 85%;
|
font-size: 85%;
|
||||||
min-height: 30%;
|
min-height: 30%;
|
||||||
|
max-height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-text-scroll {
|
||||||
|
max-height: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +326,7 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.setting-main {
|
.setting-main {
|
||||||
font-size: 120%;
|
font-size: 225%;
|
||||||
|
|
||||||
.setting-container {
|
.setting-container {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -460,7 +460,7 @@ onUnmounted(() => {
|
|||||||
#shop {
|
#shop {
|
||||||
width: 90vw;
|
width: 90vw;
|
||||||
padding-top: 5vh;
|
padding-top: 5vh;
|
||||||
font-size: 100%;
|
font-size: 225%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#item-list {
|
#item-list {
|
||||||
|
@ -130,13 +130,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, shallowReactive, watch } from 'vue';
|
import { onMounted, onUnmounted, ref, shallowReactive, watch } from 'vue';
|
||||||
import Box from '../components/box.vue';
|
import Box from '../components/box.vue';
|
||||||
import Scroll from '../components/scroll.vue';
|
import Scroll from '../components/scroll.vue';
|
||||||
import { status } from '../plugin/ui/statusBar';
|
import { status } from '../plugin/ui/statusBar';
|
||||||
import { isMobile } from '../plugin/use';
|
import { isMobile } from '../plugin/use';
|
||||||
import { has } from '../plugin/utils';
|
import { fontSize } from '../plugin/ui/statusBar';
|
||||||
|
import { has } from '@/plugin/utils';
|
||||||
|
|
||||||
|
let main: HTMLDivElement;
|
||||||
|
|
||||||
|
const items = core.flags.statusBarItems;
|
||||||
|
const icons = core.statusBar.icons;
|
||||||
const skillTree = Mota.Plugin.require('skillTree_g');
|
const skillTree = Mota.Plugin.require('skillTree_g');
|
||||||
|
|
||||||
const width = ref(
|
const width = ref(
|
||||||
@ -148,6 +153,7 @@ const format = core.formatBigNumber;
|
|||||||
|
|
||||||
watch(width, n => (updateStatus.value = !updateStatus.value));
|
watch(width, n => (updateStatus.value = !updateStatus.value));
|
||||||
watch(height, n => (updateStatus.value = !updateStatus.value));
|
watch(height, n => (updateStatus.value = !updateStatus.value));
|
||||||
|
watch(fontSize, n => (main.style.fontSize = `${isMobile ? n * 1.5 : n}%`));
|
||||||
|
|
||||||
const hero = shallowReactive<Partial<HeroStatus>>({});
|
const hero = shallowReactive<Partial<HeroStatus>>({});
|
||||||
const keys = shallowReactive<number[]>([]);
|
const keys = shallowReactive<number[]>([]);
|
||||||
@ -230,8 +236,24 @@ function viewMap() {
|
|||||||
|
|
||||||
function openStudy() {}
|
function openStudy() {}
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
main.style.fontSize = `${
|
||||||
|
isMobile ? fontSize.value * 1.5 : fontSize.value
|
||||||
|
}%`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
update();
|
update();
|
||||||
|
main = document.getElementById('status-main') as HTMLDivElement;
|
||||||
|
|
||||||
|
window.addEventListener('resize', resize);
|
||||||
|
resize();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('resize', resize);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -241,14 +263,16 @@ onMounted(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 1vh 0;
|
padding: 1vh 0;
|
||||||
|
font-size: v-bind(fontSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-item {
|
.status-item {
|
||||||
position: relative;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
max-width: 17.5vw;
|
max-width: 17.5vw;
|
||||||
font-size: 200%;
|
font-size: 200%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 1vh;
|
margin-bottom: 14px;
|
||||||
text-shadow: 3px 2px 3px #000, 0px 0px 3px #111;
|
text-shadow: 3px 2px 3px #000, 0px 0px 3px #111;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -266,6 +290,10 @@ onMounted(() => {
|
|||||||
margin-left: 10%;
|
margin-left: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status-value {
|
||||||
|
transform: translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
#status-header {
|
#status-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -3,41 +3,64 @@
|
|||||||
<span class="button-text" @click="exit"><left-outlined /> 返回</span>
|
<span class="button-text" @click="exit"><left-outlined /> 返回</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="tool-editor">
|
<div id="tool-editor">
|
||||||
<Scroll class="tool-list-scroll">
|
<div id="tool-left">
|
||||||
<div id="tool-list">
|
<Scroll class="tool-list-scroll">
|
||||||
<div
|
<div id="tool-list">
|
||||||
v-for="(item, i) of list"
|
|
||||||
class="tool-list-item selectable"
|
|
||||||
:selected="i === selected"
|
|
||||||
@click="selected = i"
|
|
||||||
>
|
|
||||||
<span>{{ item.id }}</span>
|
|
||||||
<a-button
|
|
||||||
type="danger"
|
|
||||||
class="tool-list-delete"
|
|
||||||
@click.stop="deleteTool(item.id)"
|
|
||||||
>删除</a-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div id="tool-list-add">
|
|
||||||
<div
|
<div
|
||||||
id="tool-add-div"
|
v-for="(item, i) of list"
|
||||||
@click="addingTool = true"
|
class="tool-list-item selectable"
|
||||||
v-if="!addingTool"
|
:selected="i === selected"
|
||||||
|
@click="selected = i"
|
||||||
>
|
>
|
||||||
<PlusOutlined></PlusOutlined>
|
<span>{{ item.id }}</span>
|
||||||
<span>新增工具栏</span>
|
<a-button
|
||||||
|
type="danger"
|
||||||
|
class="tool-list-delete"
|
||||||
|
@click.stop="deleteTool(item.id)"
|
||||||
|
>删除</a-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div id="tool-list-add">
|
||||||
<a-input
|
<div
|
||||||
style="height: 100%; font-size: 80%; width: 100%"
|
id="tool-add-div"
|
||||||
v-model:value="addingToolId"
|
@click="addingTool = true"
|
||||||
@blur="addTool"
|
v-if="!addingTool"
|
||||||
></a-input>
|
>
|
||||||
|
<PlusOutlined></PlusOutlined>
|
||||||
|
<span>新增工具栏</span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<a-input
|
||||||
|
style="
|
||||||
|
height: 100%;
|
||||||
|
font-size: 80%;
|
||||||
|
width: 100%;
|
||||||
|
"
|
||||||
|
v-model:value="addingToolId"
|
||||||
|
@blur="addTool"
|
||||||
|
></a-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Scroll>
|
||||||
|
<a-divider
|
||||||
|
type="vertical"
|
||||||
|
dashed
|
||||||
|
v-if="isMobile"
|
||||||
|
style="height: 100%; border-color: #ddd4"
|
||||||
|
></a-divider>
|
||||||
|
<div id="tool-preview" v-if="!!bar && isMobile">
|
||||||
|
<div id="tool-preview-container">
|
||||||
|
<div class="tool-preview-item" v-for="item of bar.items">
|
||||||
|
<component
|
||||||
|
:is="(CustomToolbar.info[item.type].show as any)"
|
||||||
|
:item="item"
|
||||||
|
:toolbar="bar"
|
||||||
|
></component>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Scroll>
|
</div>
|
||||||
<a-divider
|
<a-divider
|
||||||
class="divider"
|
class="divider"
|
||||||
dashed
|
dashed
|
||||||
@ -151,8 +174,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</Scroll>
|
</Scroll>
|
||||||
</div>
|
</div>
|
||||||
<a-divider dashed></a-divider>
|
<a-divider dashed v-if="!isMobile"></a-divider>
|
||||||
<div id="tool-preview" v-if="!!bar">
|
<div id="tool-preview" v-if="!!bar && !isMobile">
|
||||||
<div id="tool-preview-container">
|
<div id="tool-preview-container">
|
||||||
<div class="tool-preview-item" v-for="item of bar.items">
|
<div class="tool-preview-item" v-for="item of bar.items">
|
||||||
<component
|
<component
|
||||||
@ -181,12 +204,15 @@ import { isMobile } from '@/plugin/use';
|
|||||||
import Scroll from '@/components/scroll.vue';
|
import Scroll from '@/components/scroll.vue';
|
||||||
import { deleteWith, tip } from '@/plugin/utils';
|
import { deleteWith, tip } from '@/plugin/utils';
|
||||||
import { Modal } from 'ant-design-vue';
|
import { Modal } from 'ant-design-vue';
|
||||||
|
import { mainSetting } from '@/core/main/setting';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
ui: GameUi;
|
ui: GameUi;
|
||||||
num: number;
|
num: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const scale = mainSetting.getValue('ui.toolbarScale', 100) / 100;
|
||||||
|
|
||||||
const list = CustomToolbar.list;
|
const list = CustomToolbar.list;
|
||||||
|
|
||||||
const selected = ref(0);
|
const selected = ref(0);
|
||||||
@ -331,7 +357,13 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.tool-list-scroll {
|
.tool-list-scroll {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 30%;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-left {
|
||||||
|
flex-basis: 30%;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tool-list {
|
#tool-list {
|
||||||
@ -478,7 +510,7 @@ onUnmounted(() => {
|
|||||||
height: 40%;
|
height: 40%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: start;
|
align-items: flex-start;
|
||||||
|
|
||||||
#tool-preview-container {
|
#tool-preview-container {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
@ -491,9 +523,9 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.tool-preview-item {
|
.tool-preview-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 5px;
|
margin: v-bind('5 * scale + "px"');
|
||||||
min-width: 50px;
|
min-width: v-bind('50 * scale + "px"');
|
||||||
height: 50px;
|
height: v-bind('50 * scale + "px"');
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
border: 1.5px solid #ddd8;
|
border: 1.5px solid #ddd8;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -509,4 +541,45 @@ onUnmounted(() => {
|
|||||||
.divider {
|
.divider {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
#tool-editor {
|
||||||
|
padding-top: 15%;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-left {
|
||||||
|
width: 100%;
|
||||||
|
flex-basis: 40%;
|
||||||
|
max-height: 40vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.tool-list-scroll {
|
||||||
|
height: 100%;
|
||||||
|
flex-basis: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-preview {
|
||||||
|
flex-basis: 50%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#tool-info {
|
||||||
|
width: 100%;
|
||||||
|
flex-basis: 60%;
|
||||||
|
|
||||||
|
#tool-detail {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
import Box from '@/components/box.vue';
|
import Box from '@/components/box.vue';
|
||||||
import { CustomToolbar } from '@/core/main/custom/toolbar';
|
import { CustomToolbar } from '@/core/main/custom/toolbar';
|
||||||
import { GameUi } from '@/core/main/custom/ui';
|
import { GameUi } from '@/core/main/custom/ui';
|
||||||
|
import { mainSetting } from '@/core/main/setting';
|
||||||
import { onUnmounted, reactive, watch } from 'vue';
|
import { onUnmounted, reactive, watch } from 'vue';
|
||||||
|
|
||||||
interface BoxData {
|
interface BoxData {
|
||||||
@ -44,6 +45,7 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const bar = props.bar;
|
const bar = props.bar;
|
||||||
|
const scale = mainSetting.getValue('ui.toolbarScale', 100) / 100;
|
||||||
|
|
||||||
const box = reactive<BoxData>({
|
const box = reactive<BoxData>({
|
||||||
x: bar.x,
|
x: bar.x,
|
||||||
@ -80,7 +82,7 @@ onUnmounted(() => {
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.toolbar-container {
|
.toolbar-container {
|
||||||
background-color: #0009;
|
background-color: #0009;
|
||||||
padding: 5px;
|
padding: v-bind('scale * 5 + "px"');
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
@ -93,9 +95,9 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.toolbar-item {
|
.toolbar-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 5px;
|
margin: v-bind('scale * 5 + "px"');
|
||||||
min-width: 50px;
|
min-width: v-bind('scale * 50 + "px"');
|
||||||
height: 50px;
|
height: v-bind('scale * 50 + "px"');
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
border: 1.5px solid #ddd8;
|
border: 1.5px solid #ddd8;
|
||||||
@ -106,7 +108,7 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.toolbar-item::v-deep(> *) {
|
.toolbar-item::v-deep(> *) {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-width: 50px;
|
min-width: v-bind('scale * 50 + "px"');
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -182,9 +182,9 @@ function use(id: ShowItemIds) {
|
|||||||
const hold = mainUi.holdOn();
|
const hold = mainUi.holdOn();
|
||||||
exit();
|
exit();
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
core.useItem(id, false, () => {
|
core.tryUseItem(id, false, () => {
|
||||||
if (mainUi.stack.length === 0) {
|
if (mainUi.stack.length === 0) {
|
||||||
hold.end();
|
hold.end(core.status.event.id !== 'toolbox');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -377,31 +377,23 @@ onUnmounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
flex-basis: 50%;
|
||||||
|
|
||||||
#desc-text {
|
#desc-text {
|
||||||
margin-top: 2vh;
|
margin-top: 2vh;
|
||||||
margin-left: 0.5vw;
|
margin-left: 0.5vw;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
#toolbox {
|
|
||||||
padding: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tools {
|
|
||||||
span {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#toolbox-main {
|
#toolbox-main {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
height: 100%;
|
height: 90%;
|
||||||
font-size: 100%;
|
font-size: 225%;
|
||||||
|
margin-top: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-list {
|
.item-list {
|
||||||
@ -418,5 +410,16 @@ onUnmounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#detail {
|
||||||
|
flex-basis: 30%;
|
||||||
|
|
||||||
|
#desc {
|
||||||
|
#desc-text {
|
||||||
|
max-height: 10vh;
|
||||||
|
height: 10vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user