53 lines
3.0 KiB
JavaScript
53 lines
3.0 KiB
JavaScript
// ui/gameLogic/settings.js — settings defaults and sanitising. Re-exported from ../gameLogic.js.
|
|
|
|
import { VOICE_LANGS, sanitizeVoiceOverrides } from '../../voicePrefs.js';
|
|
export { VOICE_LANGS } from '../../voicePrefs.js';
|
|
|
|
import { clamp, isObj } from './shared.js';
|
|
import { DEFAULT_HOTKEYS, sanitizeHotkeys } from './shortcuts.js';
|
|
|
|
|
|
// ---- settings ------------------------------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* The operator voice dubs (settings 语音语言): 'cn' 中文 (`audio.voice`, the default) and 'jp' 日本語 (`audio.voiceJp`,
|
|
* falling back to the Chinese line it lacks — public/js/audio.js voiceLine). Not tied to the interface language.
|
|
*/
|
|
|
|
|
|
/**
|
|
* The steps of 设置 →「文字大小」 (textSize): the interface text root `--t` of css/theme.css — 'sm' is the design's own
|
|
* sizes (`--t: 1rem`), the others lift the phone's 40 px root by a floor and grow the desktop gently. Text only: the
|
|
* layout root `1rem` (and with it the field camera, the detail card's side and the DOM fallback board) never moves.
|
|
*/
|
|
export const TEXT_SIZES = Object.freeze(['sm', 'md', 'lg', 'xl']);
|
|
|
|
/** keys: the in-match shortcuts' key map (ui/gameLogic/shortcuts.js; settings → 快捷键). voiceLang: VOICE_LANGS.
|
|
* textSize: TEXT_SIZES (css/theme.css `--t`, applied by ui/settings.js applyTextSize). */
|
|
export const DEFAULT_SETTINGS = Object.freeze({ bgm: 0.6, sfx: 0.8, voice: 0.8, voiceLang: 'cn', voiceOverrides: Object.freeze({}), muted: false, damageNumbers: true, officialDamageNumbers: false, quality: 'high', textSize: 'sm', keys: DEFAULT_HOTKEYS });
|
|
const QUALITIES = ['high', 'medium', 'low'];
|
|
|
|
/**
|
|
* Sanitize persisted settings.
|
|
* @param {any} raw
|
|
* @returns {{ bgm: number, sfx: number, voice: number, voiceLang: 'cn'|'jp', voiceOverrides: Record<string, string>, muted: boolean, damageNumbers: boolean, officialDamageNumbers: boolean, quality: 'high'|'medium'|'low',
|
|
* textSize: 'sm'|'md'|'lg'|'xl', keys: Record<'refresh'|'freeze'|'levelUp'|'retreat'|'sell'|'ready', string> }}
|
|
*/
|
|
export function sanitizeSettings(raw) {
|
|
const r = isObj(raw) ? raw : {};
|
|
const vol = (v, d) => (Number.isFinite(v) ? clamp(Math.round(v * 100) / 100, 0, 1) : d);
|
|
return {
|
|
bgm: vol(r.bgm, DEFAULT_SETTINGS.bgm),
|
|
sfx: vol(r.sfx, DEFAULT_SETTINGS.sfx),
|
|
voice: vol(r.voice, DEFAULT_SETTINGS.voice),
|
|
voiceLang: VOICE_LANGS.includes(r.voiceLang) ? r.voiceLang : DEFAULT_SETTINGS.voiceLang,
|
|
voiceOverrides: sanitizeVoiceOverrides(r.voiceOverrides),
|
|
muted: typeof r.muted === 'boolean' ? r.muted : DEFAULT_SETTINGS.muted,
|
|
damageNumbers: typeof r.damageNumbers === 'boolean' ? r.damageNumbers : DEFAULT_SETTINGS.damageNumbers,
|
|
officialDamageNumbers: typeof r.officialDamageNumbers === 'boolean' ? r.officialDamageNumbers : false,
|
|
quality: QUALITIES.includes(r.quality) ? r.quality : DEFAULT_SETTINGS.quality,
|
|
textSize: TEXT_SIZES.includes(r.textSize) ? r.textSize : DEFAULT_SETTINGS.textSize,
|
|
keys: sanitizeHotkeys(r.keys),
|
|
};
|
|
}
|