// Spiel-Parameter, live per Admin-Panel einstellbar, persistent in data/config.json. // Wird pro Request frisch gelesen -> Aenderungen wirken SOFORT (Server + Client). import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const DATA_DIR = join(__dirname, '..', 'data'); const CONFIG_FILE = join(DATA_DIR, 'config.json'); // Defaults = die bisherigen Konstanten aus public/js/app.js + server/index.js export const DEFAULT_CONFIG = { // Timer startTime: 15, maxTime: 30, bonus: 1.2, penalty: 2.0, // Objekt-Anzahl-Kurve countBase: 10, countPerScore: 1.5, stepStart: 25, stepEvery: 3, stepAdd: 2, countCap: 100, // Schwierigkeits-Stufen (Score-Grenzen) + Tempo stageScatter: 3, // ab hier "scatter" stageGroups: 6, // ab hier "groups" stageIndividual: 11, // ab hier "individual" speedGroupsBase: 45, speedGroupsPer: 10, speedGroupsMax: 150, speedIndivBase: 70, speedIndivPer: 12, speedIndivMax: 320, }; // Nur bekannte Keys uebernehmen, Werte auf sinnvolle Zahlen begrenzen function sanitize(input) { const out = { ...DEFAULT_CONFIG }; if (input && typeof input === 'object') { for (const key of Object.keys(DEFAULT_CONFIG)) { const v = Number(input[key]); if (Number.isFinite(v)) out[key] = clampField(key, v); } } return out; } function clampField(key, v) { const bounds = { startTime: [3, 120], maxTime: [5, 300], bonus: [0, 30], penalty: [0, 30], countBase: [1, 200], countPerScore: [0, 20], stepStart: [0, 500], stepEvery: [1, 100], stepAdd: [0, 50], countCap: [5, 400], stageScatter: [0, 1000], stageGroups: [0, 1000], stageIndividual: [0, 1000], speedGroupsBase: [0, 2000], speedGroupsPer: [0, 500], speedGroupsMax: [0, 5000], speedIndivBase: [0, 2000], speedIndivPer: [0, 500], speedIndivMax: [0, 5000], }; const [min, max] = bounds[key] || [-1e9, 1e9]; return Math.max(min, Math.min(max, v)); } export function getConfig() { try { if (!existsSync(CONFIG_FILE)) return { ...DEFAULT_CONFIG }; return sanitize(JSON.parse(readFileSync(CONFIG_FILE, 'utf8'))); } catch { return { ...DEFAULT_CONFIG }; } } export function setConfig(input) { if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true }); const next = sanitize(input); writeFileSync(CONFIG_FILE, JSON.stringify(next, null, 2)); return next; } // Objekt-Anzahl aus Config + Score (identisch fuer Server & Client) export function objectCount(cfg, score) { let count = cfg.countBase + Math.floor(score * cfg.countPerScore); if (score >= cfg.stepStart) count += Math.floor((score - cfg.stepStart) / cfg.stepEvery) * cfg.stepAdd; return Math.min(count, cfg.countCap); }