/** * SAVE MANAGER * Handles multiple save slots and auto-save functionality * Extends existing SaveSystem with slot management */ class SaveManager { constructor(scene) { this.scene = scene; this.maxSlots = 3; // 3 save slots this.currentSlot = 1; // Active slot (1-3) // Auto-save settings this.autoSaveEnabled = true; this.autoSaveInterval = 5 * 60 * 1000; // 5 minutes in ms this.autoSaveTimer = 0; // Initialize SaveSystem for each slot this.saveSystems = {}; for (let i = 1; i <= this.maxSlots; i++) { this.saveSystems[i] = new SaveSystem(scene); this.saveSystems[i].storageKey = `novafarma_save_slot${i}`; } console.log('💾 SaveManager initialized with 3 slots'); } /** * Save to specific slot * @param {number} slotNumber - Slot 1-3 */ saveToSlot(slotNumber) { if (slotNumber < 1 || slotNumber > this.maxSlots) { console.error(`Invalid slot number: ${slotNumber}`); return false; } console.log(`💾 Saving to slot ${slotNumber}...`); this.saveSystems[slotNumber].saveGame(); this.currentSlot = slotNumber; // Save metadata (last save time, playtime, etc.) this.saveSlotMetadata(slotNumber); return true; } /** * Load from specific slot * @param {number} slotNumber - Slot 1-3 */ loadFromSlot(slotNumber) { if (slotNumber < 1 || slotNumber > this.maxSlots) { console.error(`Invalid slot number: ${slotNumber}`); return false; } console.log(`📂 Loading from slot ${slotNumber}...`); const success = this.saveSystems[slotNumber].loadGame(); if (success) { this.currentSlot = slotNumber; } return success; } /** * Delete specific slot * @param {number} slotNumber - Slot 1-3 */ deleteSlot(slotNumber) { if (slotNumber < 1 || slotNumber > this.maxSlots) { console.error(`Invalid slot number: ${slotNumber}`); return false; } const key = `novafarma_save_slot${slotNumber}`; const metaKey = `novafarma_slot${slotNumber}_meta`; localStorage.removeItem(key); localStorage.removeItem(metaKey); console.log(`🗑️ Deleted slot ${slotNumber}`); return true; } /** * Save metadata for slot (thumbnail, playtime, day, etc.) */ saveSlotMetadata(slotNumber) { const metadata = { slotNumber, lastSaved: Date.now(), playerName: 'Player', dayCount: this.scene.timeSystem ? this.scene.timeSystem.dayCount : 1, playtime: this.scene.playtimeTracker ? this.scene.playtimeTracker.stats.playtimeSeconds : 0, playerLevel: this.scene.player ? (this.scene.player.level || 1) : 1 }; const metaKey = `novafarma_slot${slotNumber}_meta`; localStorage.setItem(metaKey, JSON.stringify(metadata)); } /** * Get metadata for slot */ getSlotMetadata(slotNumber) { const metaKey = `novafarma_slot${slotNumber}_meta`; const raw = localStorage.getItem(metaKey); if (!raw) return null; try { return JSON.parse(raw); } catch (e) { console.error(`Failed to parse metadata for slot ${slotNumber}:`, e); return null; } } /** * Get all slots info */ getAllSlotsInfo() { const slots = []; for (let i = 1; i <= this.maxSlots; i++) { const metadata = this.getSlotMetadata(i); const exists = this.slotExists(i); slots.push({ number: i, exists, metadata: metadata || { playerName: 'Empty', dayCount: 0, playtime: 0, lastSaved: null } }); } return slots; } /** * Check if slot exists */ slotExists(slotNumber) { const key = `novafarma_save_slot${slotNumber}`; return localStorage.getItem(key) !== null; } /** * Quick save to current slot */ quickSave() { console.log(`⚡ Quick save to slot ${this.currentSlot}`); this.saveToSlot(this.currentSlot); } /** * Quick load from current slot */ quickLoad() { console.log(`⚡ Quick load from slot ${this.currentSlot}`); return this.loadFromSlot(this.currentSlot); } /** * Update auto-save timer * Call this in scene update() */ update(delta) { if (!this.autoSaveEnabled) return; this.autoSaveTimer += delta; if (this.autoSaveTimer >= this.autoSaveInterval) { this.autoSaveTimer = 0; console.log('💾 Auto-saving...'); this.quickSave(); // Show notification if (this.scene.events) { this.scene.events.emit('show-floating-text', { x: this.scene.cameras.main.scrollX + this.scene.cameras.main.width - 100, y: this.scene.cameras.main.scrollY + 50, text: '💾 Auto-Saved', color: '#00ff00' }); } } } /** * Toggle auto-save */ toggleAutoSave() { this.autoSaveEnabled = !this.autoSaveEnabled; console.log(`Auto-save: ${this.autoSaveEnabled ? 'ON' : 'OFF'}`); return this.autoSaveEnabled; } /** * Get time until next auto-save */ getTimeUntilNextSave() { if (!this.autoSaveEnabled) return -1; return Math.max(0, this.autoSaveInterval - this.autoSaveTimer); } /** * Export save data as JSON (for backup) */ exportSlot(slotNumber) { if (!this.slotExists(slotNumber)) { console.error(`Slot ${slotNumber} is empty`); return null; } const key = `novafarma_save_slot${slotNumber}`; const data = localStorage.getItem(key); // Create downloadable file const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(data); const downloadAnchorNode = document.createElement('a'); downloadAnchorNode.setAttribute("href", dataStr); downloadAnchorNode.setAttribute("download", `novafarma_slot${slotNumber}_${Date.now()}.json`); document.body.appendChild(downloadAnchorNode); downloadAnchorNode.click(); downloadAnchorNode.remove(); console.log(`📤 Exported slot ${slotNumber}`); return true; } /** * Import save data from JSON file */ importSlot(slotNumber, jsonData) { try { const key = `novafarma_save_slot${slotNumber}`; localStorage.setItem(key, jsonData); console.log(`📥 Imported to slot ${slotNumber}`); return true; } catch (e) { console.error('Failed to import:', e); return false; } } } // Make available globally window.SaveManager = SaveManager; // Convenience functions window.save = function (slot = 1) { const scene = game.scene.scenes.find(s => s.saveManager); if (scene && scene.saveManager) { return scene.saveManager.saveToSlot(slot); } }; window.load = function (slot = 1) { const scene = game.scene.scenes.find(s => s.saveManager); if (scene && scene.saveManager) { return scene.saveManager.loadFromSlot(slot); } }; console.log('💾 SaveManager loaded. Use: save(1), load(1), or F5/F9 keys');