/** 档位权重固定键(与 GameConfig / GameUser JSON 一致) */ export const TIER_WEIGHT_KEYS = ['T1', 'T2', 'T3', 'T4', 'T5'] as const /** 中大奖权重固定键 */ export const BIGWIN_WEIGHT_KEYS = ['5', '10', '15', '20', '25', '30'] as const /** 默认大奖权重:点数 5、30 为豹子号必中,权重固定 10000 */ export function isBigwinDiceLockedKey(key: string): boolean { return key === '5' || key === '30' } export type WeightRow = { key: string; val: string } export function weightArrayToMap(arr: unknown): Record { const map: Record = {} if (!Array.isArray(arr)) { return map } for (const item of arr) { if (item !== null && typeof item === 'object' && !Array.isArray(item)) { for (const [k, v] of Object.entries(item)) { map[k] = v === null || v === undefined ? '' : String(v) } } } return map } /** 解析 game_weight JSON 为键值映射(键为 T1 / 5 等) */ export function parseWeightJsonToMap(raw: unknown): Record { if (raw === null || raw === undefined || raw === '') { return {} } if (typeof raw === 'string') { const s = raw.trim() if (!s || s === '[]') { return {} } try { const parsed = JSON.parse(s) return weightArrayToMap(parsed) } catch { return {} } } if (Array.isArray(raw)) { return weightArrayToMap(raw) } return {} } export function fixedRowsFromKeys(keys: readonly string[], map: Record): WeightRow[] { const rows: WeightRow[] = [] for (const k of keys) { rows.push({ key: k, val: map[k] ?? '' }) } return rows } export function rowsToMap(rows: WeightRow[]): Record { const m: Record = {} for (const r of rows) { m[r.key] = r.val } return m } export function jsonStringFromFixedKeys(keys: readonly string[], map: Record): string { const pairs: Record[] = [] for (const k of keys) { const one: Record = {} one[k] = map[k] ?? '' pairs.push(one) } return JSON.stringify(pairs) } /** * 统一配置标识:trim、去掉「 (说明)」「(说明)」「(说明)」等后缀、小写,避免下拉/接口返回不一致导致走错位校验(如误报每项≤10000) */ export function normalizeGameWeightConfigName(name: string | undefined): string { if (name === undefined || name === null) { return '' } let s = String(name).trim() // 截到第一个半角/全角左括号之前(兼容 "key (说明)"、"key(说明)"、"key(说明)"、无前导空格) const m = s.match(/^([^((]+)/u) if (m) { s = m[1].trim() } return s.toLowerCase() } /** 当前行是否为大奖骰子键 5~30(与 BIGWIN_WEIGHT_KEYS 一致) */ export function weightRowsMatchBigwinDiceKeys(rows: { key: string }[]): boolean { const keys = rows .map((r) => r.key.trim()) .filter((k) => k !== '') .sort((a, b) => Number(a) - Number(b)) if (keys.length !== BIGWIN_WEIGHT_KEYS.length) { return false } return BIGWIN_WEIGHT_KEYS.every((k, i) => keys[i] === k) } /** GameConfig 中按 name 判断是否使用固定键编辑 */ export function getFixedKeysForGameConfigName(name: string | undefined): readonly string[] | null { const n = normalizeGameWeightConfigName(name) /** 击杀分权重与档位权重同为 T1~T5;库中 JSON 为 [{"T1":"0"},...],非骰子点 5~30 */ if (n === 'default_tier_weight' || n === 'default_kill_score_weight') { return TIER_WEIGHT_KEYS } if (n === 'default_bigwin_weight') { return BIGWIN_WEIGHT_KEYS } return null }