mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-19 12:49:25 +08:00
重构设置模块
This commit is contained in:
parent
b7f0d6f4d8
commit
4d4aeed3cd
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -7,7 +7,9 @@ export {}
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
AButton: typeof import('ant-design-vue/es')['Button']
|
||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
||||
AProgress: typeof import('ant-design-vue/es')['Progress']
|
||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||
|
@ -415,10 +415,7 @@ main.prototype.loadAsync = async function (mode, callback) {
|
||||
|
||||
// 自动放缩最大化
|
||||
let auto = core.getLocalStorage('autoScale');
|
||||
if (auto == null) {
|
||||
core.setLocalStorage('autoScale', true);
|
||||
auto = true;
|
||||
}
|
||||
|
||||
if (auto && !core.domStyle.isVertical) {
|
||||
try {
|
||||
core.plugin.utils.maxGameScale();
|
||||
|
@ -51,11 +51,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
||||
else core.showStatusBar();
|
||||
if (main.mode === 'play' && !main.replayChecking) {
|
||||
ancTe.plugin.fly.splitArea();
|
||||
ancTe.plugin.setting.resetFlagSettings();
|
||||
ancTe.game.hook.emit('reset');
|
||||
} else {
|
||||
flags.autoSkill ??= true;
|
||||
flags.itemDetail ??= true;
|
||||
flags.autoLocate ??= true;
|
||||
}
|
||||
},
|
||||
win: function (reason, norank, noexit) {
|
||||
|
@ -18,7 +18,6 @@ import { uiStack } from './plugin/uiController';
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { BgmController } from './audio/bgm';
|
||||
import { SoundController } from './audio/sound';
|
||||
import { EventEmitter } from './common/eventEmitter';
|
||||
import { loading, readyAllResource } from './loader/load';
|
||||
import { ResourceStore, ResourceType } from './loader/resource';
|
||||
import { GameEvent } from './main/game';
|
||||
import { resolvePlugin } from './plugin';
|
||||
|
||||
interface AncTePlugin {
|
||||
@ -38,6 +40,9 @@ export interface AncTe {
|
||||
zipResource: ResourceStore<'zip'>;
|
||||
bgm: BgmController;
|
||||
plugin: AncTePlugin;
|
||||
game: {
|
||||
hook: EventEmitter<GameEvent>;
|
||||
};
|
||||
}
|
||||
|
||||
function ready() {
|
||||
|
9
src/core/main/game.ts
Normal file
9
src/core/main/game.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
|
||||
|
||||
export interface GameEvent extends EmitableEvent {
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
export const hook = new EventEmitter<GameEvent>();
|
||||
|
||||
ancTe.game.hook = hook;
|
@ -1,12 +1,17 @@
|
||||
import { reactive } from 'vue';
|
||||
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
|
||||
import { transition } from '../../plugin/uiController';
|
||||
import { loading } from '../loader/load';
|
||||
import { hook } from './game';
|
||||
|
||||
type MotaSettingType = boolean | number | MotaSetting;
|
||||
|
||||
interface MotaSettingItem<T extends MotaSettingType = MotaSettingType> {
|
||||
export interface MotaSettingItem<T extends MotaSettingType = MotaSettingType> {
|
||||
name: string;
|
||||
key: string;
|
||||
value: T;
|
||||
defaults?: boolean | number;
|
||||
step?: number;
|
||||
step?: [number, number, number];
|
||||
display?: (value: T) => string;
|
||||
special?: string;
|
||||
}
|
||||
@ -19,8 +24,28 @@ interface SettingEvent extends EmitableEvent {
|
||||
) => void;
|
||||
}
|
||||
|
||||
class MotaSetting extends EventEmitter<SettingEvent> {
|
||||
private list: Record<string, MotaSettingItem> = {};
|
||||
export type SettingText = {
|
||||
[key: string]: string[] | SettingText;
|
||||
};
|
||||
|
||||
export interface SettingDisplayInfo {
|
||||
item: MotaSettingItem | null;
|
||||
list: Record<string, MotaSettingItem>;
|
||||
text: string[];
|
||||
}
|
||||
|
||||
export class MotaSetting extends EventEmitter<SettingEvent> {
|
||||
readonly list: Record<string, MotaSettingItem> = {};
|
||||
|
||||
/**
|
||||
* 重设设置
|
||||
* @param setting 设置信息
|
||||
*/
|
||||
reset(setting: Record<string, boolean | number>) {
|
||||
for (const [key, value] of Object.entries(setting)) {
|
||||
this.setValue(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记为特殊的设置项
|
||||
@ -36,7 +61,12 @@ class MotaSetting extends EventEmitter<SettingEvent> {
|
||||
* @param key 设置的键名
|
||||
* @param value 设置的值
|
||||
*/
|
||||
register(key: string, name: string, value: number, step?: number): this;
|
||||
register(
|
||||
key: string,
|
||||
name: string,
|
||||
value: number,
|
||||
step?: [number, number, number]
|
||||
): this;
|
||||
/**
|
||||
* 注册一个非数字型设置
|
||||
* @param key 设置的键名
|
||||
@ -47,11 +77,12 @@ class MotaSetting extends EventEmitter<SettingEvent> {
|
||||
key: string,
|
||||
name: string,
|
||||
value: MotaSettingType,
|
||||
step: number = 1
|
||||
step: [number, number, number] = [0, 100, 1]
|
||||
) {
|
||||
const setting: MotaSettingItem = {
|
||||
name,
|
||||
value
|
||||
value,
|
||||
key
|
||||
};
|
||||
if (!(value instanceof MotaSetting)) setting.defaults = value;
|
||||
if (typeof value === 'number') setting.step = step;
|
||||
@ -83,7 +114,7 @@ class MotaSetting extends EventEmitter<SettingEvent> {
|
||||
}
|
||||
const old = setting.value as boolean | number;
|
||||
setting.value = value;
|
||||
this.emit('valueChange', key, old, value);
|
||||
this.emit('valueChange', key, value, old);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,13 +143,14 @@ class MotaSetting extends EventEmitter<SettingEvent> {
|
||||
setDisplayFunc(key: string, func: (value: MotaSettingType) => string) {
|
||||
const setting = this.getSettingBy(key.split('.'));
|
||||
setting.display = func;
|
||||
return this;
|
||||
}
|
||||
|
||||
private getSettingBy(list: string[]) {
|
||||
let now: MotaSetting = this;
|
||||
|
||||
for (let i = 0; i < list.length - 1; i++) {
|
||||
const item = now.list[list[i]];
|
||||
const item = now.list[list[i]].value;
|
||||
if (!(item instanceof MotaSetting)) {
|
||||
throw new Error(
|
||||
`Cannot get setting. The parent isn't a MotaSetting instance.` +
|
||||
@ -132,8 +164,203 @@ class MotaSetting extends EventEmitter<SettingEvent> {
|
||||
}
|
||||
}
|
||||
|
||||
interface SettingDisplayerEvent extends EmitableEvent {
|
||||
update: (stack: string[], display: SettingDisplayInfo[]) => void;
|
||||
}
|
||||
|
||||
export class SettingDisplayer extends EventEmitter<SettingDisplayerEvent> {
|
||||
setting: MotaSetting;
|
||||
textInfo: SettingText;
|
||||
/** 选项选中栈 */
|
||||
selectStack: string[] = [];
|
||||
displayInfo: SettingDisplayInfo[] = reactive([]);
|
||||
|
||||
constructor(setting: MotaSetting, textInfo: SettingText) {
|
||||
super();
|
||||
this.setting = setting;
|
||||
this.textInfo = textInfo;
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加选择项
|
||||
* @param key 下一个选择项
|
||||
*/
|
||||
add(key: string) {
|
||||
this.selectStack.push(...key.split('.'));
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 剪切后面的选择项
|
||||
* @param index 从哪开始剪切
|
||||
*/
|
||||
cut(index: number, noUpdate: boolean = false) {
|
||||
this.selectStack.splice(index, Infinity);
|
||||
if (!noUpdate) this.update();
|
||||
}
|
||||
|
||||
update() {
|
||||
const list = this.selectStack;
|
||||
let now = this.setting;
|
||||
let nowText: string[] | SettingText = this.textInfo;
|
||||
this.displayInfo = [];
|
||||
|
||||
for (let i = 0; i < list.length - 1; i++) {
|
||||
const item = now.list[list[i]].value;
|
||||
if (!(item instanceof MotaSetting)) {
|
||||
throw new Error(
|
||||
`Cannot get setting. The parent isn't a MotaSetting instance.` +
|
||||
`Key: '${list.join('.')}'. Reading: '${list[i + 1]}'`
|
||||
);
|
||||
}
|
||||
|
||||
this.displayInfo.push({
|
||||
item: now.list[list[i]],
|
||||
text: [],
|
||||
list: now.list
|
||||
});
|
||||
|
||||
now = item;
|
||||
if (nowText && !(nowText instanceof Array))
|
||||
nowText = nowText[list[i]];
|
||||
}
|
||||
if (nowText && !(nowText instanceof Array))
|
||||
nowText = nowText[list.at(-1)!];
|
||||
|
||||
const last = now.list[list.at(-1)!];
|
||||
if (last) {
|
||||
this.displayInfo.push({
|
||||
item: last,
|
||||
text: nowText instanceof Array ? nowText : ['请选择设置'],
|
||||
list: now.list
|
||||
});
|
||||
if (last.value instanceof MotaSetting) {
|
||||
this.displayInfo.push({
|
||||
item: null,
|
||||
text: ['请选择设置'],
|
||||
list: (last.value as MotaSetting).list
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.displayInfo.push({
|
||||
item: null,
|
||||
text: ['请选择设置'],
|
||||
list: this.setting.list
|
||||
});
|
||||
}
|
||||
this.emit('update', this.selectStack, this.displayInfo);
|
||||
}
|
||||
}
|
||||
|
||||
export const mainSetting = new MotaSetting();
|
||||
|
||||
// ----- 监听设置修改
|
||||
mainSetting.on('valueChange', (key, n, o) => {
|
||||
const [root, setting] = key.split('.');
|
||||
if (root === 'screen') {
|
||||
handleScreenSetting(setting, n, o);
|
||||
} else if (root === 'action') {
|
||||
handleActionSetting(setting, n, o);
|
||||
} else if (root === 'utils') {
|
||||
handleUtilsSetting(setting, n, o);
|
||||
}
|
||||
});
|
||||
|
||||
export async function triggerFullscreen(full: boolean) {
|
||||
const { maxGameScale } = core.plugin.utils;
|
||||
if (!!document.fullscreenElement && !full) {
|
||||
await document.exitFullscreen();
|
||||
requestAnimationFrame(() => {
|
||||
maxGameScale(1);
|
||||
});
|
||||
}
|
||||
if (full && !document.fullscreenElement) {
|
||||
await document.body.requestFullscreen();
|
||||
requestAnimationFrame(() => {
|
||||
maxGameScale();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const root = document.getElementById('root') as HTMLDivElement;
|
||||
const root2 = document.getElementById('root2') as HTMLDivElement;
|
||||
|
||||
function handleScreenSetting<T extends number | boolean>(
|
||||
key: string,
|
||||
n: T,
|
||||
o: T
|
||||
) {
|
||||
if (n === o) return;
|
||||
|
||||
if (key === 'fullscreen') {
|
||||
// 全屏
|
||||
triggerFullscreen(n as boolean);
|
||||
} else if (key === 'halo') {
|
||||
// 光环
|
||||
core.setLocalStorage('showHalo', n);
|
||||
} else if (key === 'frag') {
|
||||
// 打怪特效
|
||||
core.setLocalStorage('frag', n);
|
||||
} else if (key === 'itemDetail') {
|
||||
// 宝石血瓶显伤
|
||||
core.setLocalStorage('itemDetail', n);
|
||||
} else if (key === 'transition') {
|
||||
// 界面动画
|
||||
core.setLocalStorage('transition', n);
|
||||
transition.value = n as boolean;
|
||||
} else if (key === 'antiAlias') {
|
||||
// 抗锯齿
|
||||
core.setLocalStorage('antiAlias', n);
|
||||
for (const canvas of core.dom.gameCanvas) {
|
||||
if (core.domStyle.hdCanvas.includes(canvas.id)) continue;
|
||||
if (n) {
|
||||
canvas.classList.remove('no-anti-aliasing');
|
||||
} else {
|
||||
canvas.classList.add('no-anti-aliasing');
|
||||
}
|
||||
}
|
||||
} else if (key === 'autoScale') {
|
||||
// 自动放缩
|
||||
core.setLocalStorage('autoScale', n);
|
||||
} else if (key === 'fontSize') {
|
||||
// 字体大小
|
||||
core.setLocalStorage('fontSize', n);
|
||||
root.style.fontSize = root2.style.fontSize = `${n}px`;
|
||||
}
|
||||
}
|
||||
|
||||
function handleActionSetting<T extends number | boolean>(
|
||||
key: string,
|
||||
n: T,
|
||||
o: T
|
||||
) {
|
||||
if (n === o) return;
|
||||
|
||||
if (key === 'autoSkill') {
|
||||
// 自动切换技能
|
||||
flags.autoSkill = n;
|
||||
}
|
||||
|
||||
if (key === 'fixed') {
|
||||
// 定点查看
|
||||
core.setLocalStorage('fixed', n);
|
||||
}
|
||||
}
|
||||
|
||||
function handleUtilsSetting<T extends number | boolean>(
|
||||
key: string,
|
||||
n: T,
|
||||
o: T
|
||||
) {
|
||||
if (n === o) return;
|
||||
|
||||
if (key === 'betterLoad') {
|
||||
// 加载优化
|
||||
core.setLocalStorage('betterLoad', n);
|
||||
}
|
||||
}
|
||||
|
||||
// ----- 游戏的所有设置项
|
||||
mainSetting
|
||||
.register(
|
||||
@ -147,7 +374,7 @@ mainSetting
|
||||
.register('transition', '界面动画', false)
|
||||
.register('antiAlias', '抗锯齿', false)
|
||||
.register('autoScale', '自动放缩', true)
|
||||
.register('fontSize', '字体大小', 16, 1)
|
||||
.register('fontSize', '字体大小', 16, [8, 28, 1])
|
||||
)
|
||||
.register(
|
||||
'action',
|
||||
@ -157,9 +384,31 @@ mainSetting
|
||||
.register('fixed', '定点查看', true)
|
||||
.register('hotkey', '快捷键', false)
|
||||
.markSpecial('hotkey', 'hotkey')
|
||||
.setDisplayFunc('hotkey', () => '')
|
||||
)
|
||||
.register(
|
||||
'utils',
|
||||
'功能设置',
|
||||
new MotaSetting().register('betterLoad', '优化加载', true)
|
||||
);
|
||||
|
||||
loading.once('coreInit', () => {
|
||||
mainSetting.reset({
|
||||
'screen.fullscreen': false,
|
||||
'screen.halo': !!core.getLocalStorage('showHalo', true),
|
||||
'screen.frag': !!core.getLocalStorage('frag', true),
|
||||
'screen.itemDetail': !!core.getLocalStorage('itemDetail', true),
|
||||
'screen.transition': !!core.getLocalStorage('transition', false),
|
||||
'screen.antiAlias': !!core.getLocalStorage('antiAlias', false),
|
||||
'screen.autoScale': !!core.getLocalStorage('autoScale', true),
|
||||
'screen.fontSize': core.getLocalStorage('fontSize', 16),
|
||||
'action.fixed': !!core.getLocalStorage('fixed', true),
|
||||
'utils.betterLoad': !!core.getLocalStorage('betterLoad', true)
|
||||
});
|
||||
});
|
||||
|
||||
hook.once('reset', () => {
|
||||
mainSetting.reset({
|
||||
'action.autoSkill': flags.autoSkill ?? true
|
||||
});
|
||||
});
|
||||
|
@ -1,32 +1,20 @@
|
||||
{
|
||||
"fullscreen": {
|
||||
"text": "全屏游戏",
|
||||
"desc": [
|
||||
"screen": {
|
||||
"fullscreen": [
|
||||
"是否全屏进行游戏,全屏后按ESC退出全屏,不能开启系统设置菜单,请按下方的按钮打开。",
|
||||
"进入或退出全屏后请存读档一下,以解决一部分绘制问题。"
|
||||
]
|
||||
},
|
||||
"transition": {
|
||||
"text": "界面动画",
|
||||
"desc": [
|
||||
],
|
||||
"halo": ["开启后,会在地图上显示范围光环。"],
|
||||
"frag": ["开启后,在打败怪物后会触发怪物碎裂特效。"],
|
||||
"itemDetail": ["是否在地图上显示宝石血瓶装备等增加的属性值"],
|
||||
"transition": [
|
||||
"是否展示当一个ui界面,如怪物手册等的打开与关闭时的动画。当此项开启时,",
|
||||
"所有界面被打开或关闭时都会展示动画,否则会直接展示出来"
|
||||
]
|
||||
},
|
||||
"itemDetail": {
|
||||
"text": "宝石血瓶显伤",
|
||||
"desc": ["是否在地图上显示宝石血瓶装备等增加的属性值"]
|
||||
},
|
||||
"autoSkill": {
|
||||
"text": "自动切换技能",
|
||||
"desc": [
|
||||
"开启后,打怪物的时候会自动选择伤害最低的技能。同时显伤也会显示此状态下的伤害,",
|
||||
"临界也会考虑技能在内"
|
||||
]
|
||||
},
|
||||
"autoScale": {
|
||||
"text": "自动放缩",
|
||||
"desc": [
|
||||
],
|
||||
"antiAlias": [
|
||||
"是否开启抗锯齿。开启后,画面会变得不那么锐利,观感更加舒适;关闭后,可以更好地展现出像素感,同时部分像素错误也不会出现。"
|
||||
],
|
||||
"autoScale": [
|
||||
"开启后,每次进入游戏时会自动缩放游戏画面至合适值。该项只对电脑端有效。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
@ -35,46 +23,26 @@
|
||||
"1. 首先尝试缩放至最大缩放比例",
|
||||
"<br>",
|
||||
"2. 如果缩放后游戏画面高度高于页面高度的95%,那么缩小一个缩放比例,否则保持最大比例"
|
||||
]
|
||||
],
|
||||
"fontSize": ["在各种 ui 界面中显示的文字大小,范围为 8 - 28"]
|
||||
},
|
||||
"showHalo": {
|
||||
"text": "展示范围光环",
|
||||
"desc": ["开启后,会在地图上显示范围光环。"]
|
||||
},
|
||||
"useFixed": {
|
||||
"text": "移动鼠标显示怪物信息",
|
||||
"desc": [
|
||||
"action": {
|
||||
"autoSkill": [
|
||||
"开启后,打怪物的时候会自动选择伤害最低的技能。同时显伤也会显示此状态下的伤害,",
|
||||
"临界也会考虑技能在内"
|
||||
],
|
||||
"fixed": [
|
||||
"开启后,当鼠标移动到怪物上时,会以盒子的形式展示该点的怪物信息。手机端此功能无效。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"注:当鼠标移动到怪物上时,经过200毫秒才会显示信息,防止误操作。"
|
||||
]
|
||||
],
|
||||
"hotkey": ["设置游戏中会用到的一些快捷键"]
|
||||
},
|
||||
"autoLocate": {
|
||||
"text": "自动勇士定位",
|
||||
"desc": [
|
||||
"此项会在进入第二章后会起作用。开启后,当勇士处于不同位置打同一个怪物伤害不同时,在地图上使用绿色箭头标出伤害最低的位置,",
|
||||
"其余方向,伤害越高,箭头颜色越红,同时在自动寻路中选择可以到达的伤害最低的位置。",
|
||||
"utils": {
|
||||
"betterLoad": [
|
||||
"<span style=\"color: yellow; font-weight: 700\">试验性功能</span>",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"注:如果出现明显卡顿现象可以考虑关闭本设置或自动切换技能设置。"
|
||||
]
|
||||
},
|
||||
"antiAliasing": {
|
||||
"text": "抗锯齿",
|
||||
"desc": [
|
||||
"是否开启抗锯齿。开启后,画面会变得不那么锐利,观感更加舒适;关闭后,可以更好地展现出像素感,同时部分像素错误也不会出现。"
|
||||
]
|
||||
},
|
||||
"showStudied": {
|
||||
"text": "展示已学习技能",
|
||||
"desc": [
|
||||
"开启后,会在画面内以类似状态栏的盒子的形式显示当前已学习的怪物技能。"
|
||||
]
|
||||
},
|
||||
"betterLoad": {
|
||||
"text": "优化加载",
|
||||
"desc": [
|
||||
"开启后游戏将对加载进行优化,缩短进入游戏时的加载时长,而在游戏中对资源进行部分性按需加载,从而对加载进行优化。",
|
||||
"该设置不会影响你的正常游戏,但如果网络环境较差,可能会导致楼层转换时间明显变长。",
|
||||
"<br>",
|
||||
|
@ -169,7 +169,7 @@ core.events.afterBattle = function (
|
||||
else core.clearContinueAutomaticRoute();
|
||||
|
||||
// 打怪特效
|
||||
if (has(x) && has(y)) {
|
||||
if (core.getLocalStorage('frag') && has(x) && has(y)) {
|
||||
const frame = core.status.globalAnimateStatus % 2;
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 32;
|
||||
|
@ -31,7 +31,7 @@ core.control.updateDamage = function (floorId = core.status.floorId, ctx) {
|
||||
|
||||
// 获取宝石信息 并绘制
|
||||
function getItemDetail(floorId: FloorIds, onMap: boolean) {
|
||||
if (!core.getFlag('itemDetail')) return;
|
||||
if (!core.getLocalStorage('itemDetail')) return;
|
||||
floorId ??= core.status.thisMap.floorId;
|
||||
let diff: Record<string | symbol, number | undefined> = {};
|
||||
const before = core.status.hero;
|
||||
|
@ -21,8 +21,16 @@ export let isMobile = matchMedia('(max-width: 600px)').matches;
|
||||
window.addEventListener('resize', () => {
|
||||
requestAnimationFrame(() => {
|
||||
isMobile = matchMedia('(max-width: 600px)').matches;
|
||||
checkMobile();
|
||||
});
|
||||
});
|
||||
checkMobile();
|
||||
|
||||
function checkMobile() {
|
||||
if (isMobile) {
|
||||
alert('手机端建议使用自带的浏览器进行游玩,并在进入游戏后开启全屏游玩');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一个元素添加拖拽事件
|
||||
|
@ -12,6 +12,11 @@
|
||||
transition: all 0.6s linear;
|
||||
opacity: 0;
|
||||
background-color: #000d;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#root2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.antdv-message {
|
||||
|
@ -1,171 +1,307 @@
|
||||
<template>
|
||||
<Column :width="60" :height="60" @close="exit"
|
||||
><template #left
|
||||
><div id="setting-list">
|
||||
<div class="setting-main">
|
||||
<div id="tools">
|
||||
<span class="button-text" @click="exit"
|
||||
><left-outlined /> 返回游戏</span
|
||||
>
|
||||
</div>
|
||||
<div class="setting-container">
|
||||
<div class="setting-select">
|
||||
<TransitionGroup name="list">
|
||||
<div
|
||||
v-for="(info, i) of display"
|
||||
:key="i"
|
||||
class="setting-display"
|
||||
>
|
||||
<Scroll class="setting-scroll">
|
||||
<div class="setting-list">
|
||||
<div
|
||||
v-for="item of info.list"
|
||||
class="setting-item selectable"
|
||||
:selected="item === info.item"
|
||||
@click="click(item.key, i, item)"
|
||||
>
|
||||
<span>{{ item.name }}</span>
|
||||
<span
|
||||
class="selectable"
|
||||
:selected="selected === 'fullscreen'"
|
||||
@click="click('fullscreen')"
|
||||
>全屏游戏: {{
|
||||
fullscreen ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
:selected="item === info.item"
|
||||
class="setting-cascade"
|
||||
v-if="isCascade(item)"
|
||||
>
|
||||
<RightOutlined />
|
||||
</span>
|
||||
<span v-else class="setting-value">
|
||||
{{ getItemValue(item) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Scroll>
|
||||
<a-divider
|
||||
class="display-divider"
|
||||
type="vertical"
|
||||
dashed
|
||||
></a-divider>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
<div class="setting-info">
|
||||
<div
|
||||
class="info-text"
|
||||
v-html="splitText(display.at(-1)?.text ?? ['请选择设置'])"
|
||||
></div>
|
||||
<a-divider class="info-divider" dashed></a-divider>
|
||||
<div class="info-editor" v-if="!!selectedItem">
|
||||
<div v-if="!!selectedItem.special"></div>
|
||||
<div
|
||||
class="editor-number"
|
||||
v-else-if="typeof selectedItem.value === 'number'"
|
||||
>
|
||||
<span>修改设置:</span>
|
||||
<a-input-number
|
||||
class="number-input"
|
||||
size="large"
|
||||
:min="selectedItem.step?.[0] ?? 0"
|
||||
:max="selectedItem.step?.[1] ?? 100"
|
||||
:step="selectedItem.step?.[2] ?? 1"
|
||||
:keyboard="true"
|
||||
:value="selectedItem.value"
|
||||
@change="changeValue"
|
||||
></a-input-number>
|
||||
</div>
|
||||
<div
|
||||
class="editor-boolean"
|
||||
v-else-if="typeof selectedItem.value === 'boolean'"
|
||||
>
|
||||
<span
|
||||
class="selectable"
|
||||
:selected="selected === 'transition'"
|
||||
@click="click('transition')"
|
||||
>界面动画: {{
|
||||
transition ? 'ON' : 'OFF'
|
||||
>当前{{
|
||||
selectedItem.value ? '开启' : '关闭'
|
||||
}}</span
|
||||
>
|
||||
<span
|
||||
class="selectable"
|
||||
:selected="selected === 'itemDetail'"
|
||||
@click="click('itemDetail')"
|
||||
>宝石血瓶显伤: {{
|
||||
itemDetail ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
<a-button
|
||||
class="boolean-button"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="changeValue(!selectedItem.value)"
|
||||
>
|
||||
<span
|
||||
class="selectable"
|
||||
:selected="selected === 'autoSkill'"
|
||||
@click="click('autoSkill')"
|
||||
>自动切换技能: {{
|
||||
autoSkill ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
>
|
||||
<span
|
||||
class="selectable"
|
||||
:selected="selected === 'autoScale'"
|
||||
@click="click('autoScale')"
|
||||
>自动放缩: {{
|
||||
autoScale ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
>
|
||||
<span
|
||||
class="selectable"
|
||||
:selected="selected === 'showHalo'"
|
||||
@click="click('showHalo')"
|
||||
>展示范围光环: {{
|
||||
showHalo ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
>
|
||||
<span
|
||||
class="selectable"
|
||||
:selected="selected === 'useFixed'"
|
||||
@click="click('useFixed')"
|
||||
>移动鼠标显示怪物信息: {{
|
||||
useFixed ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
>
|
||||
<!-- <span
|
||||
class="selectable"
|
||||
:selected="selected === 'autoLocate'"
|
||||
@click="click('autoLocate')"
|
||||
>勇士自动定位: {{
|
||||
autoLocate ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
> -->
|
||||
<span
|
||||
class="selectable"
|
||||
:selected="selected === 'antiAliasing'"
|
||||
@click="click('antiAliasing')"
|
||||
>抗锯齿: {{
|
||||
antiAliasing ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
>
|
||||
<!-- <span
|
||||
class="selectable"
|
||||
:selected="selected === 'showStudied'"
|
||||
v-if="core.plugin.skillTree.getSkillLevel(11) > 0"
|
||||
@click="click('showStudied')"
|
||||
>展示已学习技能: {{
|
||||
showStudied ? 'ON' : 'OFF'
|
||||
}}</span
|
||||
> -->
|
||||
</div></template
|
||||
>
|
||||
<template #right><span v-html="descText"></span></template
|
||||
></Column>
|
||||
{{ selectedItem.value ? '关闭' : '开启' }}设置
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed, shallowRef } from 'vue';
|
||||
import {
|
||||
transition,
|
||||
itemDetail,
|
||||
autoSkill,
|
||||
autoScale,
|
||||
showStudied,
|
||||
showHalo,
|
||||
useFixed,
|
||||
autoLocate,
|
||||
antiAliasing,
|
||||
fullscreen,
|
||||
triggerFullscreen
|
||||
} from '../plugin/settings';
|
||||
import settingInfo from '../data/settings.json';
|
||||
import { has, splitText } from '../plugin/utils';
|
||||
import Column from '../components/colomn.vue';
|
||||
mainSetting,
|
||||
MotaSetting,
|
||||
MotaSettingItem,
|
||||
SettingDisplayer,
|
||||
SettingDisplayInfo,
|
||||
SettingText
|
||||
} from '../core/main/setting';
|
||||
import settingText from '../data/settings.json';
|
||||
import { RightOutlined, LeftOutlined } from '@ant-design/icons-vue';
|
||||
import { splitText } from '../plugin/utils';
|
||||
import Scroll from '../components/scroll.vue';
|
||||
import { settingsOpened } from '../plugin/uiController';
|
||||
|
||||
type Settings = typeof settingInfo;
|
||||
const props = defineProps<{
|
||||
info?: MotaSetting;
|
||||
text?: SettingText;
|
||||
}>();
|
||||
|
||||
const core = window.core;
|
||||
const setting = props.info ?? mainSetting;
|
||||
const text = props.text ?? (settingText as SettingText);
|
||||
const display = shallowRef<SettingDisplayInfo[]>([]);
|
||||
const selectedItem = computed(() => display.value.at(-1)?.item);
|
||||
|
||||
const selected = ref<keyof Settings>('fullscreen');
|
||||
|
||||
fullscreen.value = !!document.fullscreenElement;
|
||||
|
||||
const descText = computed(() => {
|
||||
return splitText(settingInfo[selected.value].desc);
|
||||
const displayer = new SettingDisplayer(setting, text);
|
||||
displayer.on('update', (stack, dis) => {
|
||||
display.value = dis;
|
||||
});
|
||||
display.value = displayer.displayInfo;
|
||||
|
||||
const settings: Record<keyof Settings, Ref<boolean>> = {
|
||||
transition,
|
||||
itemDetail,
|
||||
autoSkill,
|
||||
autoScale,
|
||||
showHalo,
|
||||
showStudied,
|
||||
useFixed,
|
||||
autoLocate,
|
||||
antiAliasing,
|
||||
fullscreen,
|
||||
betterLoad: ref(false)
|
||||
};
|
||||
|
||||
const ignore: (keyof Settings)[] = ['fullscreen'];
|
||||
|
||||
function exit() {
|
||||
ancTe.plugin.ui.settingsOpened.value = false;
|
||||
function getItemValue(item: MotaSettingItem) {
|
||||
if (item.value instanceof MotaSetting) {
|
||||
return '';
|
||||
} else {
|
||||
if (item.display) {
|
||||
return item.display(item.value);
|
||||
} else {
|
||||
if (typeof item.value === 'number') {
|
||||
return item.value.toString();
|
||||
} else {
|
||||
return item.value ? 'ON' : 'OFF';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function click(id: keyof Settings) {
|
||||
if (selected.value !== id) {
|
||||
selected.value = id;
|
||||
return;
|
||||
function isCascade(item: MotaSettingItem) {
|
||||
return item.value instanceof MotaSetting;
|
||||
}
|
||||
|
||||
function click(key: string, index: number, item: MotaSettingItem) {
|
||||
if (item.value instanceof MotaSetting) {
|
||||
if (index === display.value.length - 1) {
|
||||
displayer.add(key);
|
||||
} else {
|
||||
if (displayer.selectStack.includes(key)) {
|
||||
displayer.cut(index);
|
||||
} else {
|
||||
displayer.cut(index, true);
|
||||
displayer.add(key);
|
||||
}
|
||||
if (!ignore.includes(id)) {
|
||||
settings[id].value = !settings[id].value;
|
||||
if (id === 'autoSkill') {
|
||||
core.status.route.push(`set:autoSkill:${settings.autoSkill.value}`);
|
||||
}
|
||||
} else {
|
||||
if (id === 'fullscreen') {
|
||||
triggerFullscreen();
|
||||
displayer.cut(index, true);
|
||||
displayer.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
function changeValue(value: number | boolean) {
|
||||
setting.setValue(displayer.selectStack.join('.'), value);
|
||||
displayer.update();
|
||||
}
|
||||
|
||||
function exit() {
|
||||
settingsOpened.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#setting-list {
|
||||
#tools {
|
||||
width: 100%;
|
||||
font-family: 'normal';
|
||||
font-size: 3.2vh;
|
||||
height: 5vh;
|
||||
position: fixed;
|
||||
left: 10vw;
|
||||
top: 10vh;
|
||||
}
|
||||
|
||||
.setting-main {
|
||||
user-select: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
font-family: normal;
|
||||
font-size: 150%;
|
||||
|
||||
.setting-container {
|
||||
height: 60%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.setting-select {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.list-move,
|
||||
.list-enter-active,
|
||||
.list-leave-active {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.list-enter-from,
|
||||
.list-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-50px);
|
||||
}
|
||||
|
||||
.list-leave-active {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.setting-display {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
|
||||
.setting-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.display-divider {
|
||||
border-color: #fff4;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.setting-item {
|
||||
width: 100%;
|
||||
padding: 1% 3% 1% 3%;
|
||||
padding: 2%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.setting-cascade {
|
||||
font-size: 75%;
|
||||
margin-right: 40px;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.setting-cascade[selected='true'] {
|
||||
font-size: 90%;
|
||||
margin-right: 10px;
|
||||
color: cyan;
|
||||
}
|
||||
|
||||
.setting-value {
|
||||
margin-right: 10px;
|
||||
color: rgb(242, 255, 101);
|
||||
}
|
||||
}
|
||||
|
||||
.setting-scroll {
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.setting-info {
|
||||
width: 400px;
|
||||
|
||||
.info-divider {
|
||||
border-color: #fff4;
|
||||
margin: 2% 0;
|
||||
}
|
||||
|
||||
.editor-boolean {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
padding: 0 10% 0 5%;
|
||||
|
||||
.boolean-button {
|
||||
font-size: 75%;
|
||||
}
|
||||
}
|
||||
|
||||
.info-text {
|
||||
font-size: 85%;
|
||||
min-height: 30%;
|
||||
}
|
||||
|
||||
.editor-number {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
padding: 0 10% 0 5%;
|
||||
|
||||
.number-input {
|
||||
font-size: 80%;
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -68,7 +68,7 @@ import { Matrix4 } from '../plugin/webgl/matrix';
|
||||
import { doByInterval, keycode } from '../plugin/utils';
|
||||
import { KeyCode } from '../plugin/keyCodes';
|
||||
import { achievementOpened } from '../plugin/uiController';
|
||||
import { triggerFullscreen } from '../plugin/settings';
|
||||
import { triggerFullscreen } from '../core/main/setting';
|
||||
import { loading } from '../core/loader/load';
|
||||
|
||||
let startdiv: HTMLDivElement;
|
||||
@ -203,7 +203,7 @@ function bgm() {
|
||||
|
||||
async function setFullscreen() {
|
||||
const index = toshow.length - toshow.indexOf(selected.value) - 1;
|
||||
await triggerFullscreen();
|
||||
await triggerFullscreen(!fullscreen.value);
|
||||
requestAnimationFrame(() => {
|
||||
fullscreen.value = !!document.fullscreenElement;
|
||||
setCursor(buttons[index], index);
|
||||
|
Loading…
Reference in New Issue
Block a user