mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-10-08 11:21:47 +08:00
327 lines
11 KiB
TypeScript
327 lines
11 KiB
TypeScript
import { GameStorage } from '@motajs/legacy-system';
|
||
import { createSettingComponents } from './settings';
|
||
import { isMobile } from '../use';
|
||
import { MotaSetting } from '../setting';
|
||
import { triggerFullscreen } from '../utils';
|
||
import settingsText from '../data/settings.json';
|
||
import { fixedUi, mainUi } from './uiIns';
|
||
import { mainSetting } from './settingIns';
|
||
|
||
//#region legacy-ui
|
||
|
||
export function createUI() {
|
||
const { hook } = Mota.require('@user/data-base');
|
||
hook.once('mounted', () => {
|
||
const ui = document.getElementById('ui-main')!;
|
||
const fixed = document.getElementById('ui-fixed')!;
|
||
|
||
const blur = mainSetting.getSetting('screen.blur');
|
||
|
||
mainUi.on('start', () => {
|
||
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();
|
||
});
|
||
mainUi.on('end', noClosePanel => {
|
||
ui.style.display = 'none';
|
||
if (!noClosePanel) {
|
||
core.closePanel();
|
||
}
|
||
});
|
||
fixedUi.on('start', () => {
|
||
fixed.style.display = 'block';
|
||
});
|
||
fixedUi.on('end', () => {
|
||
fixed.style.display = 'none';
|
||
});
|
||
});
|
||
}
|
||
|
||
//#endregion
|
||
|
||
//#region legacy-setting
|
||
|
||
const COM = createSettingComponents();
|
||
|
||
// 添加不参与全局存储的设置
|
||
MotaSetting.noStorage.push('action.autoSkill', 'screen.fullscreen');
|
||
|
||
const storage = new GameStorage(GameStorage.fromAuthor('AncTe', 'setting'));
|
||
|
||
export { storage as settingStorage };
|
||
|
||
// ----- 监听设置修改
|
||
mainSetting.on('valueChange', (key, n, o) => {
|
||
if (!MotaSetting.noStorage.includes(key)) {
|
||
storage.setValue(key, n);
|
||
}
|
||
|
||
const [root, setting] = key.split('.');
|
||
|
||
if (root === 'screen') {
|
||
handleScreenSetting(setting, n, o);
|
||
} else if (root === 'action') {
|
||
handleActionSetting(setting, n, o);
|
||
} else if (root === 'audio') {
|
||
handleAudioSetting(setting, n, o);
|
||
} else if (root === 'ui') {
|
||
handleUiSetting(setting, n, o);
|
||
}
|
||
});
|
||
|
||
const root = document.getElementById('root') as HTMLDivElement;
|
||
|
||
function handleScreenSetting<T extends number | boolean>(
|
||
key: string,
|
||
n: T,
|
||
_o: T
|
||
) {
|
||
if (key === 'fullscreen') {
|
||
// 全屏
|
||
triggerFullscreen(n as boolean);
|
||
} else if (key === 'fontSize') {
|
||
// 字体大小
|
||
root.style.fontSize = `${n}px`;
|
||
const absoluteSize = (n as number) * devicePixelRatio;
|
||
storage.setValue('@@absoluteFontSize', absoluteSize);
|
||
storage.write();
|
||
} else if (key === 'scale') {
|
||
const { MAIN_HEIGHT, MAIN_WIDTH } = Mota.require(
|
||
'@user/client-modules'
|
||
);
|
||
const max = Math.min(
|
||
(window.innerHeight / MAIN_HEIGHT) * 100,
|
||
(window.innerWidth / MAIN_WIDTH) * 100,
|
||
n as number
|
||
);
|
||
const scale = Number((Math.floor((max / 100) * 4) / 4).toFixed(2));
|
||
// @ts-expect-error 遗留问题
|
||
core.domStyle.scale = scale;
|
||
Mota.require('@user/client-modules').mainRenderer.setScale(scale);
|
||
}
|
||
}
|
||
|
||
function handleActionSetting<T extends number | boolean>(
|
||
key: string,
|
||
n: T,
|
||
_o: T
|
||
) {
|
||
if (key === 'autoSkill') {
|
||
// 自动切换技能
|
||
const HeroSkill = Mota.require('@user/data-state').HeroSkill;
|
||
HeroSkill.setAutoSkill(n as boolean);
|
||
core.status.route.push(`set:autoSkill:${n}`);
|
||
}
|
||
}
|
||
|
||
function handleAudioSetting<T extends number | boolean>(
|
||
key: string,
|
||
n: T,
|
||
_o: T
|
||
) {
|
||
const { bgmController, soundPlayer } = Mota.require('@user/client-modules');
|
||
if (key === 'bgmEnabled') {
|
||
bgmController.setEnabled(n as boolean);
|
||
core.checkBgm();
|
||
} else if (key === 'bgmVolume') {
|
||
bgmController.setVolume((n as number) / 100);
|
||
} else if (key === 'soundEnabled') {
|
||
soundPlayer.setEnabled(n as boolean);
|
||
} else if (key === 'soundVolume') {
|
||
soundPlayer.setVolume((n as number) / 100);
|
||
}
|
||
}
|
||
|
||
function handleUiSetting<T extends number | boolean>(key: string, n: T, _o: T) {
|
||
if (key === 'danmaku') {
|
||
if (n) {
|
||
fixedUi.open('danmaku');
|
||
} else {
|
||
fixedUi.closeByName('danmaku');
|
||
}
|
||
} else if (key === 'tips') {
|
||
if (n && core.isPlaying()) {
|
||
fixedUi.open('tips');
|
||
} else {
|
||
fixedUi.closeByName('tips');
|
||
}
|
||
}
|
||
}
|
||
|
||
// ----- 游戏的所有设置项
|
||
mainSetting
|
||
.register(
|
||
'screen',
|
||
'显示设置',
|
||
new MotaSetting()
|
||
.register('fullscreen', '全屏游戏', false, COM.Boolean)
|
||
.register('scale', '画面缩放', 100, COM.Number, [50, 500, 25])
|
||
.setDisplayFunc('scale', value => `${value}%`)
|
||
.register('halo', '光环显示', true, COM.Boolean)
|
||
.register('itemDetail', '宝石血瓶显伤', true, COM.Boolean)
|
||
.register('transition', '界面动画', false, COM.Boolean)
|
||
.register('fontSize', '字体大小', 16, COM.Number, [2, 48, 1])
|
||
.register('criticalGem', '临界显示方式', false, COM.Boolean)
|
||
.setDisplayFunc('criticalGem', value => (value ? '宝石数' : '攻击'))
|
||
.register('keyScale', '虚拟键盘缩放', 100, COM.Number, [25, 5, 500])
|
||
.register('blur', '背景虚化', !isMobile, COM.Boolean)
|
||
)
|
||
.register(
|
||
'action',
|
||
'操作设置',
|
||
new MotaSetting()
|
||
.register('autoSkill', '自动切换技能', true, COM.Boolean)
|
||
.register('hotkey', '快捷键', false, COM.HotkeySetting)
|
||
.setDisplayFunc('hotkey', () => '')
|
||
)
|
||
.register(
|
||
'audio',
|
||
'音频设置',
|
||
new MotaSetting()
|
||
.register('bgmEnabled', '开启音乐', true, COM.Boolean)
|
||
.register('bgmVolume', '音乐音量', 80, COM.Number, [0, 100, 5])
|
||
.register('soundEnabled', '开启音效', true, COM.Boolean)
|
||
.register('soundVolume', '音效音量', 80, COM.Number, [0, 100, 5])
|
||
)
|
||
.register(
|
||
'utils',
|
||
'系统设置',
|
||
new MotaSetting().register('autoScale', '自动放缩', true, COM.Boolean)
|
||
)
|
||
.register(
|
||
'fx',
|
||
'特效设置',
|
||
new MotaSetting().register(
|
||
'portalParticle',
|
||
'传送门特效',
|
||
true,
|
||
COM.Boolean
|
||
)
|
||
)
|
||
.register(
|
||
'ui',
|
||
'ui设置',
|
||
new MotaSetting()
|
||
.register('mapScale', '小地图缩放', 100, COM.Number, [50, 1000, 50])
|
||
.setDisplayFunc('mapScale', value => `${value}%`)
|
||
.register('mapLazy', '小地图懒更新', false, COM.Boolean)
|
||
.register(
|
||
'bookScale',
|
||
'怪物手册缩放',
|
||
100,
|
||
COM.Number,
|
||
[10, 500, 10]
|
||
)
|
||
.setDisplayFunc('bookScale', value => `${value}%`)
|
||
.register('danmaku', '显示弹幕', true, COM.Boolean)
|
||
.register('danmakuSpeed', '弹幕速度', 60, COM.Number, [10, 1000, 5])
|
||
.register('tips', '小贴士', true, COM.Boolean)
|
||
);
|
||
|
||
interface SettingTextData {
|
||
[x: string]: string[] | SettingTextData;
|
||
}
|
||
|
||
mainSetting
|
||
.setDescription('audio.bgmEnabled', `是否开启背景音乐`)
|
||
.setDescription('audio.bgmVolume', `背景音乐的音量`)
|
||
.setDescription('audio.soundEnabled', `是否开启音效`)
|
||
.setDescription('audio.soundVolume', `音效的音量`)
|
||
.setDescription('ui.mapScale', `楼传小地图的缩放,百分比格式`)
|
||
.setDescription(
|
||
'ui.mapLazy',
|
||
`是否启用小地图懒更新模式,此模式下剩余怪物数量不会实时更新而变成切换地图后更新,打开小地图时出现卡顿可以尝试开启此设置`
|
||
)
|
||
.setDescription(
|
||
'ui.bookScale',
|
||
`怪物手册界面中每个怪物框体的高度缩放,最小值限定为 20% 屏幕高度`
|
||
)
|
||
.setDescription('ui.danmaku', '是否显示弹幕')
|
||
.setDescription('ui.danmakuSpeed', '弹幕速度,刷新或开关弹幕显示后起效')
|
||
.setDescription('ui.tips', `是否在游戏画面右上角常亮显示小贴士`)
|
||
.setDescription(
|
||
'screen.blur',
|
||
'打开任意ui界面时是否有背景虚化效果,移动端打开后可能会有掉帧或者发热现象。关闭ui后生效'
|
||
)
|
||
.setDescription(
|
||
'fx.portalParticle',
|
||
'是否启用苍蓝之殿的传送门粒子特效,启用后可能对性能及设备发热有所影响'
|
||
);
|
||
|
||
function setFontSize() {
|
||
const absoluteSize = storage.getValue(
|
||
'@@absoluteFontSize',
|
||
16 * devicePixelRatio
|
||
);
|
||
const size = Math.round(absoluteSize / devicePixelRatio);
|
||
mainSetting.setValue('screen.fontSize', size);
|
||
}
|
||
setFontSize();
|
||
|
||
function getSettingText(obj: SettingTextData, key?: string) {
|
||
for (const [k, value] of Object.entries(obj)) {
|
||
const setKey = key ? key + '.' + k : k;
|
||
if (value instanceof Array) {
|
||
mainSetting.setDescription(setKey, value.join('\n'));
|
||
} else {
|
||
getSettingText(value, setKey);
|
||
}
|
||
}
|
||
}
|
||
getSettingText(settingsText);
|
||
|
||
window.addEventListener('resize', () => {
|
||
setFontSize();
|
||
});
|
||
|
||
export function createSetting() {
|
||
const { loading } = Mota.require('@user/data-base');
|
||
loading.once('coreInit', () => {
|
||
mainSetting.reset({
|
||
'screen.fullscreen': !!document.fullscreenElement,
|
||
'screen.scale': storage.getValue('screen.scale', 100),
|
||
'screen.halo': !!storage.getValue('screen.showHalo', true),
|
||
'screen.itemDetail': !!storage.getValue('screen.itemDetail', true),
|
||
'screen.transition': !!storage.getValue('screen.transition', false),
|
||
'screen.fontSize': storage.getValue(
|
||
'screen.fontSize',
|
||
isMobile ? 9 : 16
|
||
),
|
||
'screen.criticalGem': !!storage.getValue(
|
||
'screen.criticalGem',
|
||
false
|
||
),
|
||
'audio.bgmEnabled': !!storage.getValue('audio.bgmEnabled', true),
|
||
'audio.bgmVolume': storage.getValue('audio.bgmVolume', 80),
|
||
'audio.soundEnabled': !!storage.getValue(
|
||
'audio.soundEnabled',
|
||
true
|
||
),
|
||
'audio.soundVolume': storage.getValue('audio.soundVolume', 80),
|
||
'utils.autoScale': !!storage.getValue('utils.autoScale', true),
|
||
'fx.portalParticle': !!storage.getValue('fx.portalParticle', true),
|
||
'ui.mapScale': storage.getValue(
|
||
'ui.mapScale',
|
||
isMobile ? 300 : Math.floor(window.innerWidth / 600) * 50
|
||
),
|
||
'ui.mapLazy': storage.getValue('ui.mapLazy', false),
|
||
'ui.bookScale': storage.getValue(
|
||
'ui.bookScale',
|
||
isMobile ? 100 : 80
|
||
),
|
||
'ui.danmaku': storage.getValue('ui.danmaku', true),
|
||
'ui.danmakuSpeed': storage.getValue(
|
||
'ui.danmakuSpeed',
|
||
Math.floor(window.innerWidth / 30) * 5
|
||
),
|
||
'ui.tips': storage.getValue('ui.tips', true)
|
||
});
|
||
});
|
||
}
|