274 lines
7.6 KiB
JavaScript
274 lines
7.6 KiB
JavaScript
/**
|
|
* 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');
|