/** * SAVE/LOAD SYSTEM & AGING ENGINE * Persistent storage for player progress, Kai aging, and companion states */ class SaveLoadSystem { constructor() { this.saveKey = 'mrtva_dolina_save'; this.currentSave = null; this.autoSaveInterval = 300000; // 5 minutes this.autoSaveTimer = null; } /** * CREATE NEW SAVE FILE */ createNewSave() { this.currentSave = { version: '1.0.0', created: new Date().toISOString(), lastSaved: new Date().toISOString(), // Player data player: { position: { x: 0, y: 0 }, age_level: 1, // 1-9 (corresponds to age stages) current_age: 14, // Actual age in years age_sprite: 'kai_age14', inventory: [], equipped_tools: { weapon: null, tool: null }, health: 100, stamina: 100, stats: { strength: 1, speed: 1, farming: 1 } }, // Progress tracking progress: { memories_found: 0, total_memories: 100, quests_completed: [], quests_active: [], npcs_met: [], biomes_unlocked: ['grassland'], locations_discovered: [], enemies_defeated: 0, crops_harvested: 0, buildings_built: 0 }, // Companions companions: { gronk: { unlocked: false, level: 1, xp: 0, stats: {} }, susi: { unlocked: false, position: { x: 0, y: 0 }, loyalty: 100 } }, // Farm state farm: { crops: [], buildings: [], animals: [], resources: { wood: 0, stone: 0, cannabis_capital: 0 } }, // Economic state economy: { money: 0, cannabis_seeds: 5, // Starting capital! cannabis_harvested: 0, total_earnings: 0 }, // Game settings settings: { difficulty: 'normal', language: 'en', music_volume: 0.7, sfx_volume: 0.8 }, // Playtime playtime: 0 // seconds }; console.log('💾 New save file created'); return this.currentSave; } /** * SAVE GAME */ save() { if (!this.currentSave) { this.currentSave = this.createNewSave(); } this.currentSave.lastSaved = new Date().toISOString(); try { localStorage.setItem(this.saveKey, JSON.stringify(this.currentSave)); console.log('💾 Game saved successfully'); // Show save notification this.showSaveNotification(); return true; } catch (e) { console.error('❌ Save failed:', e); return false; } } /** * LOAD GAME */ load() { try { const saved = localStorage.getItem(this.saveKey); if (!saved) { console.log('📂 No save file found, creating new...'); return this.createNewSave(); } this.currentSave = JSON.parse(saved); console.log('📂 Game loaded successfully'); console.log(' Age Level:', this.currentSave.player.age_level); console.log(' Memories:', this.currentSave.progress.memories_found + '/' + this.currentSave.progress.total_memories); return this.currentSave; } catch (e) { console.error('❌ Load failed:', e); return this.createNewSave(); } } /** * UPDATE PLAYER DATA */ updatePlayer(data) { if (!this.currentSave) this.load(); this.currentSave.player = { ...this.currentSave.player, ...data }; this.save(); } /** * UPDATE PROGRESS */ updateProgress(data) { if (!this.currentSave) this.load(); this.currentSave.progress = { ...this.currentSave.progress, ...data }; // Check if aging should trigger this.checkAgingProgress(); this.save(); } /** * START AUTO-SAVE */ startAutoSave() { if (this.autoSaveTimer) { clearInterval(this.autoSaveTimer); } this.autoSaveTimer = setInterval(() => { this.save(); console.log('💾 Auto-save triggered'); }, this.autoSaveInterval); } /** * STOP AUTO-SAVE */ stopAutoSave() { if (this.autoSaveTimer) { clearInterval(this.autoSaveTimer); this.autoSaveTimer = null; } } /** * AGING ENGINE - CHECK IF KAI SHOULD AGE UP */ checkAgingProgress() { if (!this.currentSave) return; const memoriesFound = this.currentSave.progress.memories_found; const totalMemories = this.currentSave.progress.total_memories; const progress = (memoriesFound / totalMemories) * 100; let newAgeLevel = 1; let newAge = 14; let newSprite = 'kai_age14'; // Age progression based on memory recovery if (progress >= 90) { newAgeLevel = 9; newAge = 60; newSprite = 'kai_age60'; } else if (progress >= 75) { newAgeLevel = 7; newAge = 50; newSprite = 'kai_age50'; } else if (progress >= 60) { newAgeLevel = 6; newAge = 40; newSprite = 'kai_age40'; } else if (progress >= 50) { newAgeLevel = 5; newAge = 30; newSprite = 'kai_age30'; } else if (progress >= 35) { newAgeLevel = 4; newAge = 25; newSprite = 'kai_age25'; } else if (progress >= 25) { newAgeLevel = 3; newAge = 20; newSprite = 'kai_age20'; } else if (progress >= 10) { newAgeLevel = 2; newAge = 16; newSprite = 'kai_age16'; } // Check if age changed if (newAgeLevel > this.currentSave.player.age_level) { this.triggerAging(newAgeLevel, newAge, newSprite); } } /** * TRIGGER AGING CUTSCENE */ triggerAging(newLevel, newAge, newSprite) { const oldLevel = this.currentSave.player.age_level; const oldAge = this.currentSave.player.current_age; // Update save data this.currentSave.player.age_level = newLevel; this.currentSave.player.current_age = newAge; this.currentSave.player.age_sprite = newSprite; console.log(`⏰ KAI AGES UP!`); console.log(` ${oldAge} → ${newAge} years old`); console.log(` Sprite: ${newSprite}`); // Emit aging event for cutscene const event = new CustomEvent('kai-aging', { detail: { oldLevel: oldLevel, newLevel: newLevel, oldAge: oldAge, newAge: newAge, newSprite: newSprite, memoriesFound: this.currentSave.progress.memories_found } }); window.dispatchEvent(event); this.save(); } /** * SHOW SAVE NOTIFICATION */ showSaveNotification() { const event = new CustomEvent('game-saved', { detail: { time: new Date().toLocaleTimeString(), slot: 1 } }); window.dispatchEvent(event); } /** * GET CURRENT SAVE DATA */ getCurrentSave() { if (!this.currentSave) { this.load(); } return this.currentSave; } /** * DELETE SAVE */ deleteSave() { if (confirm('Are you sure you want to delete your save file?')) { localStorage.removeItem(this.saveKey); this.currentSave = null; console.log('🗑️ Save file deleted'); return true; } return false; } /** * EXPORT SAVE (for backup) */ exportSave() { if (!this.currentSave) return null; const saveData = JSON.stringify(this.currentSave, null, 2); const blob = new Blob([saveData], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `mrtva_dolina_save_${Date.now()}.json`; a.click(); console.log('📤 Save exported'); } /** * IMPORT SAVE (from backup) */ importSave(fileInput) { const file = fileInput.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { try { const imported = JSON.parse(e.target.result); localStorage.setItem(this.saveKey, JSON.stringify(imported)); this.currentSave = imported; console.log('📥 Save imported successfully'); } catch (err) { console.error('❌ Import failed:', err); } }; reader.readAsText(file); } } // Singleton instance const saveLoadSystem = new SaveLoadSystem(); export default saveLoadSystem;