/** * lab.js * Laboratory logic: accept goods, analyse for special goods, * trigger medication production. No rendering, no DOM. */ const LabState = Object.freeze({ IDLE: 'idle', ANALYZING: 'analyzing', }); class Lab { constructor() { this.reset(); } reset() { this.state = LabState.IDLE; this.analyzeTimer = 0; this.totalProcessed = 0; this.flashTimer = 0; // brief visual flash on deposit this._onMedReady = null; } /** * Deposit an array of goods into the lab. * @param {Good[]} goods – goods from player inventory * @param {function} onMedicationReady – called (no args) when special analysis completes * @returns {number} count of goods deposited */ depositGoods(goods, onMedicationReady) { if (!goods.length) return 0; let hasSpecial = false; goods.forEach(good => { this.totalProcessed++; if (good.isSpecial) hasSpecial = true; }); // Flash feedback this.flashTimer = 500; // Start analysis only if we got a special good and aren't already analysing if (hasSpecial && this.state === LabState.IDLE) { this.state = LabState.ANALYZING; this.analyzeTimer = SETTINGS.LAB_ANALYZE_TIME; this._onMedReady = onMedicationReady; } return goods.length; } /** True briefly after goods are deposited (visual feedback). */ isFlashing() { return this.flashTimer > 0; } /** True while analysing a special good. */ isAnalyzing() { return this.state === LabState.ANALYZING; } /** Progress 0–1 of the current analysis (0 if idle). */ analyzeProgress() { if (this.state !== LabState.ANALYZING) return 0; return 1 - this.analyzeTimer / SETTINGS.LAB_ANALYZE_TIME; } update(dt) { if (this.flashTimer > 0) this.flashTimer -= dt; if (this.state === LabState.ANALYZING) { this.analyzeTimer -= dt; if (this.analyzeTimer <= 0) { this.analyzeTimer = 0; this.state = LabState.IDLE; if (this._onMedReady) { this._onMedReady(); this._onMedReady = null; } } } } }