ok
This commit is contained in:
281
EMERGENCY_SYSTEMS_RECOVERY/SaveSystem.js
Normal file
281
EMERGENCY_SYSTEMS_RECOVERY/SaveSystem.js
Normal file
@@ -0,0 +1,281 @@
|
||||
class SaveSystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.storageKey = 'novafarma_savefile';
|
||||
}
|
||||
|
||||
saveGame() {
|
||||
console.log('💾 Saving game...');
|
||||
|
||||
if (!this.scene.player || !this.scene.terrainSystem) {
|
||||
console.error('Cannot save: Player or TerrainSystem missing.');
|
||||
return;
|
||||
}
|
||||
|
||||
const playerPos = this.scene.player.getPosition();
|
||||
|
||||
// Zberi podatke o NPCjih
|
||||
const npcsData = this.scene.npcs.map(npc => ({
|
||||
type: npc.type,
|
||||
x: npc.gridX,
|
||||
y: npc.gridY
|
||||
}));
|
||||
|
||||
// Zberi podatke o terenu - FLAT 2D (no seed, no crops yet!)
|
||||
const terrainSeed = this.scene.terrainSystem.noise?.seed || 0; // Optional for old system
|
||||
|
||||
// Flat2DTerrainSystem doesn't have cropsMap yet - skip for now
|
||||
const cropsData = this.scene.terrainSystem.cropsMap
|
||||
? Array.from(this.scene.terrainSystem.cropsMap.entries())
|
||||
: [];
|
||||
|
||||
const decorData = this.scene.terrainSystem.decorationsMap
|
||||
? Array.from(this.scene.terrainSystem.decorationsMap.values())
|
||||
: [];
|
||||
|
||||
// Inventory
|
||||
const inventoryData = {
|
||||
slots: this.scene.inventorySystem.slots,
|
||||
gold: this.scene.inventorySystem.gold || 0
|
||||
};
|
||||
|
||||
const saveData = {
|
||||
version: 2.5, // 2D Flat Version
|
||||
timestamp: Date.now(),
|
||||
player: { x: playerPos.x, y: playerPos.y },
|
||||
terrain: {
|
||||
seed: terrainSeed,
|
||||
crops: cropsData,
|
||||
decorations: decorData
|
||||
},
|
||||
npcs: npcsData,
|
||||
inventory: inventoryData,
|
||||
time: {
|
||||
gameTime: this.scene.timeSystem ? this.scene.timeSystem.gameTime : 8,
|
||||
dayCount: this.scene.timeSystem ? this.scene.timeSystem.dayCount : 1
|
||||
},
|
||||
stats: this.scene.statsSystem ? {
|
||||
health: this.scene.statsSystem.health,
|
||||
hunger: this.scene.statsSystem.hunger,
|
||||
thirst: this.scene.statsSystem.thirst
|
||||
} : null,
|
||||
camera: { zoom: this.scene.cameras.main.zoom }
|
||||
};
|
||||
|
||||
try {
|
||||
const jsonString = JSON.stringify(saveData);
|
||||
// Compress data to save space
|
||||
try {
|
||||
const compressed = Compression.compress(jsonString);
|
||||
localStorage.setItem(this.storageKey, 'LZW:' + compressed);
|
||||
console.log(`✅ Game saved! Size: ${jsonString.length} -> ${compressed.length} chars`);
|
||||
} catch (compErr) {
|
||||
console.warn("Compression failed, saving raw JSON:", compErr);
|
||||
localStorage.setItem(this.storageKey, jsonString);
|
||||
}
|
||||
|
||||
// Pokaži obvestilo (preko UIScene če obstaja)
|
||||
this.showNotification('GAME SAVED');
|
||||
} catch (e) {
|
||||
console.error('❌ Failed to save game:', e);
|
||||
this.showNotification('SAVE FAILED');
|
||||
}
|
||||
}
|
||||
|
||||
loadGame() {
|
||||
console.log('📂 Loading game... DISABLED - Fresh start!');
|
||||
// ONEMOGOČENO - vedno vrne false za fresh start
|
||||
return false;
|
||||
|
||||
try {
|
||||
let jsonString = rawData;
|
||||
// Check for compression
|
||||
if (rawData.startsWith('LZW:')) {
|
||||
const compressed = rawData.substring(4); // Remove prefix
|
||||
jsonString = Compression.decompress(compressed);
|
||||
}
|
||||
|
||||
const saveData = JSON.parse(jsonString);
|
||||
console.log('Loading save data:', saveData);
|
||||
|
||||
// Preveri verzijo - če je stara, izbriši save
|
||||
if (!saveData.version || saveData.version < 2.4) {
|
||||
console.log('⚠️ Stara verzija save file-a detected, clearing...');
|
||||
localStorage.removeItem(this.storageKey);
|
||||
this.showNotification('OLD SAVE CLEARED - NEW GAME');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1. Load Player
|
||||
if (this.scene.player) {
|
||||
// Zahteva metodo setPosition(gridX, gridY) v Player.js
|
||||
// Trenutno imamo moveToGrid ampak za instant load rabimo direkten set.
|
||||
// Uporabimo updatePosition logic iz NPC, ali pa kar moveToGrid s hitrostjo 0?
|
||||
// Bolje dodati setGridPosition v Player.js.
|
||||
// Za zdaj workaround:
|
||||
this.scene.player.gridX = saveData.player.x;
|
||||
this.scene.player.gridY = saveData.player.y;
|
||||
// Force update screen pos
|
||||
const screenPos = this.scene.player.iso.toScreen(saveData.player.x, saveData.player.y);
|
||||
this.scene.player.sprite.setPosition(
|
||||
screenPos.x + this.scene.player.offsetX,
|
||||
screenPos.y + this.scene.player.offsetY
|
||||
);
|
||||
this.scene.player.updateDepth();
|
||||
}
|
||||
|
||||
// 2. Load Terrain (Regenerate + Restore dynamic)
|
||||
if (this.scene.terrainSystem && saveData.terrain) {
|
||||
// A) Seed / Base Terrain
|
||||
if (saveData.terrain.seed && this.scene.terrainSystem.noise.seed !== saveData.terrain.seed) {
|
||||
// Regenerate world if seed mismatch
|
||||
// (Actually we might want to ALWAYS regenerate to clear default decors then overwrite?)
|
||||
// Current logic: generate() spawns default decorations.
|
||||
// To handle persistence properly:
|
||||
// 1. Clear current decorations
|
||||
// 2. Load saved decorations
|
||||
|
||||
this.scene.terrainSystem.noise = new PerlinNoise(saveData.terrain.seed);
|
||||
// this.scene.terrainSystem.generate(); // This re-adds random flowers
|
||||
// Instead of full generate, we might just re-calc tiles if seed changed?
|
||||
// For now assume seed is constant for "New Game", but let's re-run generate to be safe
|
||||
}
|
||||
|
||||
// Clear EVERYTHING first
|
||||
this.scene.terrainSystem.decorationsMap.clear();
|
||||
this.scene.terrainSystem.decorations = [];
|
||||
this.scene.terrainSystem.cropsMap.clear();
|
||||
// We should also hide active sprites?
|
||||
this.scene.terrainSystem.visibleDecorations.forEach(s => s.setVisible(false));
|
||||
this.scene.terrainSystem.visibleDecorations.clear();
|
||||
this.scene.terrainSystem.visibleCrops.forEach(s => s.setVisible(false));
|
||||
this.scene.terrainSystem.visibleCrops.clear();
|
||||
// Sproščanje objektov se samodejno dogaja preko release() v clearanju zgoraj
|
||||
|
||||
// B) Restore Crops
|
||||
if (saveData.terrain.crops) {
|
||||
// Map was saved as array of entries
|
||||
saveData.terrain.crops.forEach(entry => {
|
||||
const [key, cropData] = entry;
|
||||
this.scene.terrainSystem.cropsMap.set(key, cropData);
|
||||
|
||||
// Set flag on tile
|
||||
const [gx, gy] = key.split(',').map(Number);
|
||||
const tile = this.scene.terrainSystem.getTile(gx, gy);
|
||||
if (tile) tile.hasCrop = true;
|
||||
});
|
||||
}
|
||||
|
||||
// C) Restore Decorations (Flowers, Houses, Walls, Fences...)
|
||||
if (saveData.terrain.decorations) {
|
||||
saveData.terrain.decorations.forEach(d => {
|
||||
this.scene.terrainSystem.decorations.push(d);
|
||||
this.scene.terrainSystem.decorationsMap.set(d.id, d);
|
||||
|
||||
const tile = this.scene.terrainSystem.getTile(d.gridX, d.gridY);
|
||||
if (tile) tile.hasDecoration = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Force Update Visuals
|
||||
this.scene.terrainSystem.updateCulling(this.scene.cameras.main);
|
||||
}
|
||||
|
||||
// 3. Load Inventory
|
||||
if (this.scene.inventorySystem && saveData.inventory) {
|
||||
this.scene.inventorySystem.slots = saveData.inventory.slots;
|
||||
this.scene.inventorySystem.gold = saveData.inventory.gold;
|
||||
this.scene.inventorySystem.updateUI();
|
||||
}
|
||||
|
||||
// 4. Load Time & Stats
|
||||
if (this.scene.timeSystem && saveData.time) {
|
||||
this.scene.timeSystem.gameTime = saveData.time.gameTime;
|
||||
this.scene.timeSystem.dayCount = saveData.time.dayCount || 1;
|
||||
}
|
||||
if (this.scene.statsSystem && saveData.stats) {
|
||||
this.scene.statsSystem.health = saveData.stats.health;
|
||||
this.scene.statsSystem.hunger = saveData.stats.hunger;
|
||||
this.scene.statsSystem.thirst = saveData.stats.thirst;
|
||||
}
|
||||
|
||||
// 3. Load NPCs
|
||||
// 3. Load NPCs
|
||||
// Pobriši trenutne
|
||||
this.scene.npcs.forEach(npc => npc.destroy());
|
||||
this.scene.npcs = [];
|
||||
|
||||
let hasMerchant = false;
|
||||
|
||||
// Ustvari shranjene
|
||||
if (saveData.npcs) {
|
||||
saveData.npcs.forEach(npcData => {
|
||||
const npc = new NPC(
|
||||
this.scene,
|
||||
npcData.x,
|
||||
npcData.y,
|
||||
this.scene.terrainOffsetX,
|
||||
this.scene.terrainOffsetY,
|
||||
npcData.type
|
||||
);
|
||||
this.scene.npcs.push(npc);
|
||||
if (npcData.type === 'merchant') hasMerchant = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Force Spawn Merchant if missing
|
||||
if (!hasMerchant) {
|
||||
// Spawn near current player position so user can find him
|
||||
const px = saveData.player ? saveData.player.x : 50;
|
||||
const py = saveData.player ? saveData.player.y : 50;
|
||||
const mX = Math.max(0, Math.min(99, Math.floor(px) + 3));
|
||||
const mY = Math.max(0, Math.min(99, Math.floor(py) + 3));
|
||||
|
||||
const merchant = new NPC(this.scene, mX, mY, this.scene.terrainOffsetX, this.scene.terrainOffsetY, 'merchant');
|
||||
this.scene.npcs.push(merchant);
|
||||
console.log("🏪 FORCE SPAWNED MERCHANT at", mX, mY);
|
||||
}
|
||||
|
||||
// 4. Camera
|
||||
if (saveData.camera) {
|
||||
this.scene.cameras.main.setZoom(saveData.camera.zoom);
|
||||
}
|
||||
|
||||
this.showNotification('GAME LOADED');
|
||||
return true;
|
||||
|
||||
} catch (e) {
|
||||
console.error('❌ Failed to load game:', e);
|
||||
this.showNotification('LOAD FAILED');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
showNotification(text) {
|
||||
const uiScene = this.scene.scene.get('UIScene');
|
||||
if (uiScene) {
|
||||
const width = uiScene.cameras.main.width;
|
||||
const height = uiScene.cameras.main.height;
|
||||
|
||||
const msg = uiScene.add.text(width / 2, height / 2, text, {
|
||||
fontFamily: 'Courier New',
|
||||
fontSize: '32px',
|
||||
fill: '#ffffff',
|
||||
backgroundColor: '#000000',
|
||||
padding: { x: 10, y: 5 }
|
||||
});
|
||||
msg.setOrigin(0.5);
|
||||
msg.setScrollFactor(0);
|
||||
|
||||
uiScene.tweens.add({
|
||||
targets: msg,
|
||||
alpha: 0,
|
||||
duration: 2000,
|
||||
delay: 500,
|
||||
onComplete: () => {
|
||||
msg.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user