Session 12: Save Slot System (3 slots, autosave toggle, cross-slot import/export) + fix goldenBlooms field missing from reset()/switchSlot empty-state
This commit is contained in:
@@ -515,6 +515,98 @@ h2, h3 {
|
|||||||
border-color: var(--danger);
|
border-color: var(--danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Save Slot System */
|
||||||
|
.footer-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding-right: 10px;
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section:last-of-type {
|
||||||
|
border-right: none;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-label {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slot-btn {
|
||||||
|
background: var(--bg-card);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
min-width: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slot-btn:hover:not(:disabled) {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
border-color: var(--accent-purple);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slot-btn.active {
|
||||||
|
background: var(--accent-purple);
|
||||||
|
color: var(--text-primary);
|
||||||
|
border-color: var(--accent-gold);
|
||||||
|
box-shadow: 0 0 12px rgba(155, 89, 182, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slot-btn:disabled {
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Autosave toggle button */
|
||||||
|
.toggle-btn {
|
||||||
|
background: var(--bg-card);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-btn.on {
|
||||||
|
background: var(--accent-green);
|
||||||
|
color: #0a0a1a;
|
||||||
|
border-color: var(--accent-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-btn:not(.on) {
|
||||||
|
background: var(--bg-card);
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Import modal slot selector */
|
||||||
|
.import-slot-selector {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-slot-label {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-hint {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
#last-saved {
|
#last-saved {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
|
|||||||
+22
-3
@@ -63,7 +63,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="achievements-tab" class="tab-content">
|
<div id="achievements-tab" class="tab-content">
|
||||||
<h3>Achievements (0/33)</h3>
|
<h3>Achievements (0/31)</h3>
|
||||||
<div id="achievements-list"></div>
|
<div id="achievements-list"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -103,10 +103,22 @@
|
|||||||
|
|
||||||
<!-- Footer: Controls -->
|
<!-- Footer: Controls -->
|
||||||
<footer id="game-footer">
|
<footer id="game-footer">
|
||||||
|
<div class="footer-section">
|
||||||
|
<span class="footer-label">Slot:</span>
|
||||||
|
<button class="slot-btn" data-slot="0">1</button>
|
||||||
|
<button class="slot-btn" data-slot="1">2</button>
|
||||||
|
<button class="slot-btn" data-slot="2">3</button>
|
||||||
|
</div>
|
||||||
|
<div class="footer-section">
|
||||||
|
<span class="footer-label">Auto:</span>
|
||||||
|
<button id="autosave-btn" class="toggle-btn on">ON</button>
|
||||||
|
</div>
|
||||||
|
<div class="footer-section">
|
||||||
<button id="save-btn">💾 Save</button>
|
<button id="save-btn">💾 Save</button>
|
||||||
<button id="export-btn">📤 Export Save</button>
|
<button id="export-btn">📤 Export</button>
|
||||||
<button id="import-btn">📥 Import Save</button>
|
<button id="import-btn">📥 Import</button>
|
||||||
<button id="reset-btn">🗑️ Reset</button>
|
<button id="reset-btn">🗑️ Reset</button>
|
||||||
|
</div>
|
||||||
<span id="last-saved"></span>
|
<span id="last-saved"></span>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,7 +130,14 @@
|
|||||||
<div id="import-modal" class="modal hidden">
|
<div id="import-modal" class="modal hidden">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<h3>Import Save</h3>
|
<h3>Import Save</h3>
|
||||||
|
<p class="modal-hint">Paste your save data, then choose which slot to import into.</p>
|
||||||
<textarea id="import-data" placeholder="Paste your save data here..."></textarea>
|
<textarea id="import-data" placeholder="Paste your save data here..."></textarea>
|
||||||
|
<div class="import-slot-selector">
|
||||||
|
<span class="import-slot-label">Import into slot:</span>
|
||||||
|
<button class="slot-btn" data-import-slot="0">1</button>
|
||||||
|
<button class="slot-btn" data-import-slot="1">2</button>
|
||||||
|
<button class="slot-btn" data-import-slot="2">3</button>
|
||||||
|
</div>
|
||||||
<div class="modal-buttons">
|
<div class="modal-buttons">
|
||||||
<button id="confirm-import">Import</button>
|
<button id="confirm-import">Import</button>
|
||||||
<button id="cancel-import">Cancel</button>
|
<button id="cancel-import">Cancel</button>
|
||||||
|
|||||||
+199
-6
@@ -20,6 +20,10 @@ const Game = {
|
|||||||
totalPrestigeEssence: 0,
|
totalPrestigeEssence: 0,
|
||||||
prestigeUpgrades: [],
|
prestigeUpgrades: [],
|
||||||
|
|
||||||
|
// Save Slot System
|
||||||
|
activeSlot: 0, // index of the currently selected save slot (0..SLOTS-1)
|
||||||
|
autoSave: true, // whether the periodic autosave loop is running
|
||||||
|
|
||||||
// Golden Starbloom random event state
|
// Golden Starbloom random event state
|
||||||
goldenBlooms: {
|
goldenBlooms: {
|
||||||
active: false, // is a bloom currently visible on screen?
|
active: false, // is a bloom currently visible on screen?
|
||||||
@@ -34,6 +38,10 @@ const Game = {
|
|||||||
tickRate: 100, // ms per tick (10 ticks/sec)
|
tickRate: 100, // ms per tick (10 ticks/sec)
|
||||||
autoSaveInterval: 30000, // 30 seconds
|
autoSaveInterval: 30000, // 30 seconds
|
||||||
costScaling: 1.15, // Cost multiplier per building level
|
costScaling: 1.15, // Cost multiplier per building level
|
||||||
|
|
||||||
|
// Save Slot System - number of independent save slots available
|
||||||
|
SLOTS: 3,
|
||||||
|
|
||||||
goldenBloomMinMs: 45000, // min ms between bloom spawns (45s)
|
goldenBloomMinMs: 45000, // min ms between bloom spawns (45s)
|
||||||
goldenBloomMaxMs: 90000, // max ms between bloom spawns (90s)
|
goldenBloomMaxMs: 90000, // max ms between bloom spawns (90s)
|
||||||
goldenBloomDuration: 12, // seconds a visible bloom stays before vanishing
|
goldenBloomDuration: 12, // seconds a visible bloom stays before vanishing
|
||||||
@@ -59,6 +67,9 @@ const Game = {
|
|||||||
* Setup event listeners
|
* Setup event listeners
|
||||||
*/
|
*/
|
||||||
setupEventListeners() {
|
setupEventListeners() {
|
||||||
|
// Track which slot the user has selected for importing.
|
||||||
|
this.importSlot = 0;
|
||||||
|
|
||||||
// Harvest button - support both click and touch
|
// Harvest button - support both click and touch
|
||||||
const harvestBtn = document.getElementById('harvest-btn');
|
const harvestBtn = document.getElementById('harvest-btn');
|
||||||
|
|
||||||
@@ -100,9 +111,12 @@ const Game = {
|
|||||||
document.getElementById('confirm-import').addEventListener('click', () => {
|
document.getElementById('confirm-import').addEventListener('click', () => {
|
||||||
const data = document.getElementById('import-data').value;
|
const data = document.getElementById('import-data').value;
|
||||||
if (data) {
|
if (data) {
|
||||||
this.loadFromData(data);
|
const ok = this.importSlotFromData(data, this.importSlot);
|
||||||
UI.hideImportModal();
|
UI.hideImportModal();
|
||||||
UI.showNotification('Save imported!', 'success');
|
if (ok) {
|
||||||
|
// If the import landed in the active slot, switchSlot already re-rendered.
|
||||||
|
UI.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -116,6 +130,37 @@ const Game = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Save Slot System: slot selection buttons.
|
||||||
|
document.querySelectorAll('.slot-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
if (this.state.activeSlot === parseInt(btn.dataset.slot, 10)) {
|
||||||
|
UI.showNotification(`Already on Slot ${parseInt(btn.dataset.slot, 10) + 1}`, 'info');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (confirm(`Switch to Slot ${parseInt(btn.dataset.slot, 10) + 1}?\nUnsaved changes will be saved first.`)) {
|
||||||
|
this.save(); // Persist current slot before switching.
|
||||||
|
this.switchSlot(parseInt(btn.dataset.slot, 10));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Autosave toggle button.
|
||||||
|
document.getElementById('autosave-btn').addEventListener('click', () => {
|
||||||
|
this.state.autoSave = !this.state.autoSave;
|
||||||
|
const btn = document.getElementById('autosave-btn');
|
||||||
|
if (this.state.autoSave) {
|
||||||
|
btn.classList.add('on');
|
||||||
|
btn.textContent = 'ON';
|
||||||
|
UI.showNotification('Autosave enabled', 'success');
|
||||||
|
} else {
|
||||||
|
btn.classList.remove('on');
|
||||||
|
btn.textContent = 'OFF';
|
||||||
|
UI.showNotification('Autosave disabled', 'info');
|
||||||
|
}
|
||||||
|
// Persist the toggle preference immediately.
|
||||||
|
localStorage.setItem('cosmicGardenAutoSave', String(this.state.autoSave));
|
||||||
|
});
|
||||||
|
|
||||||
// Tab switching
|
// Tab switching
|
||||||
document.querySelectorAll('.tab-btn').forEach(btn => {
|
document.querySelectorAll('.tab-btn').forEach(btn => {
|
||||||
btn.addEventListener('click', (e) => {
|
btn.addEventListener('click', (e) => {
|
||||||
@@ -126,6 +171,14 @@ const Game = {
|
|||||||
document.getElementById(`${tab}-tab`).classList.add('active');
|
document.getElementById(`${tab}-tab`).classList.add('active');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Import slot selector buttons.
|
||||||
|
document.querySelectorAll('[data-import-slot]').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
this.importSlot = parseInt(btn.dataset.importSlot, 10);
|
||||||
|
UI.showNotification(`Importing into Slot ${this.importSlot + 1}`, 'info');
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -480,6 +533,8 @@ const Game = {
|
|||||||
*/
|
*/
|
||||||
startAutoSave() {
|
startAutoSave() {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
// Only autosave when the player has enabled it (default on).
|
||||||
|
if (!this.state.autoSave) return;
|
||||||
this.save();
|
this.save();
|
||||||
document.getElementById('last-saved').textContent =
|
document.getElementById('last-saved').textContent =
|
||||||
`Last saved: ${new Date().toLocaleTimeString()}`;
|
`Last saved: ${new Date().toLocaleTimeString()}`;
|
||||||
@@ -487,22 +542,46 @@ const Game = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save game state
|
* localStorage key for a given slot's save data.
|
||||||
|
*/
|
||||||
|
getSaveKey(slot) {
|
||||||
|
return `cosmicGardenSave-${slot}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key holding the selected slot index across page loads.
|
||||||
|
*/
|
||||||
|
getActiveSlotKey() {
|
||||||
|
return 'cosmicGardenActiveSlot';
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save game state to the currently active slot.
|
||||||
*/
|
*/
|
||||||
save() {
|
save() {
|
||||||
this.state.lastSaveTime = Date.now();
|
this.state.lastSaveTime = Date.now();
|
||||||
localStorage.setItem('cosmicGardenSave', JSON.stringify(this.state));
|
localStorage.setItem(this.getSaveKey(this.state.activeSlot), JSON.stringify(this.state));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load game state
|
* Load game state
|
||||||
*/
|
*/
|
||||||
loadState() {
|
loadState() {
|
||||||
const saved = localStorage.getItem('cosmicGardenSave');
|
// Restore the persisted selected-slot index before reading its data.
|
||||||
|
const persistedSlot = localStorage.getItem(this.getActiveSlotKey());
|
||||||
|
if (persistedSlot !== null) {
|
||||||
|
this.state.activeSlot = parseInt(persistedSlot, 10) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const saved = localStorage.getItem(this.getSaveKey(this.state.activeSlot));
|
||||||
if (saved) {
|
if (saved) {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(saved);
|
const parsed = JSON.parse(saved);
|
||||||
this.state = { ...this.state, ...parsed };
|
this.state = { ...this.state, ...parsed };
|
||||||
|
// The explicitly-persisted slot selection always wins.
|
||||||
|
if (persistedSlot !== null) {
|
||||||
|
this.state.activeSlot = parseInt(persistedSlot, 10) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate offline progress
|
// Calculate offline progress
|
||||||
const offlineTime = (Date.now() - this.state.lastSaveTime) / 1000;
|
const offlineTime = (Date.now() - this.state.lastSaveTime) / 1000;
|
||||||
@@ -543,6 +622,117 @@ const Game = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the data stored in a specific slot index (without changing it).
|
||||||
|
* Returns the parsed state, or null if that slot is empty.
|
||||||
|
*/
|
||||||
|
loadSlot(slot) {
|
||||||
|
const raw = localStorage.getItem(this.getSaveKey(slot));
|
||||||
|
if (!raw) return null;
|
||||||
|
try {
|
||||||
|
return JSON.parse(raw);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Failed to read slot ${slot}:`, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch the active save slot. Persists the selection and reloads that
|
||||||
|
* slot's data from localStorage into the live game state, preserving
|
||||||
|
* prestige-related counters that should carry across slots only when
|
||||||
|
* present in the target slot.
|
||||||
|
*/
|
||||||
|
switchSlot(slot) {
|
||||||
|
slot = ((parseInt(slot, 10) || 0) + this.config.SLOTS) % this.config.SLOTS;
|
||||||
|
|
||||||
|
// Persist the selection first so loadState() reads it back.
|
||||||
|
localStorage.setItem(this.getActiveSlotKey(), String(slot));
|
||||||
|
this.state.activeSlot = slot;
|
||||||
|
|
||||||
|
const data = this.loadSlot(slot);
|
||||||
|
if (data) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(JSON.stringify(data));
|
||||||
|
this.state = { ...this.state, ...parsed };
|
||||||
|
// Ensure the slot index stays consistent.
|
||||||
|
this.state.activeSlot = slot;
|
||||||
|
|
||||||
|
UI.showNotification(
|
||||||
|
`Saved to Slot ${slot + 1}!`, 'success'
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load selected slot:', e);
|
||||||
|
UI.showNotification('Could not load that slot!', 'warning');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Target slot is empty: reset to a fresh start but keep essence.
|
||||||
|
this.state = {
|
||||||
|
stardust: 0,
|
||||||
|
totalStardust: 0,
|
||||||
|
totalClicks: 0,
|
||||||
|
clickPower: 1,
|
||||||
|
startTime: Date.now(),
|
||||||
|
lastSaveTime: Date.now(),
|
||||||
|
buildings: {},
|
||||||
|
upgrades: [],
|
||||||
|
achievements: [],
|
||||||
|
stellarEssence: this.state.stellarEssence || 0,
|
||||||
|
prestigeCount: this.state.prestigeCount || 0,
|
||||||
|
totalPrestigeEssence: this.state.totalPrestigeEssence || 0,
|
||||||
|
prestigeUpgrades: this.state.prestigeUpgrades || [],
|
||||||
|
goldenBlooms: { active: false, timer: 0, lastSpawn: Date.now(), totalClaimed: 0 },
|
||||||
|
activeSlot: slot,
|
||||||
|
autoSave: this.state.autoSave
|
||||||
|
};
|
||||||
|
UI.showNotification(
|
||||||
|
`Empty Slot ${slot + 1} - new game started!`, 'success'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-render dynamic UI and refresh the golden-bloom badge.
|
||||||
|
UI.init();
|
||||||
|
UI.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export a single slot's save as base64 (for backup or transfer).
|
||||||
|
*/
|
||||||
|
exportSlotToBase64(slot) {
|
||||||
|
const data = this.loadSlot(slot);
|
||||||
|
if (!data) {
|
||||||
|
UI.showNotification(`Slot ${slot + 1} is empty!`, 'warning');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const encoded = btoa(JSON.stringify(data));
|
||||||
|
navigator.clipboard.writeText(encoded).then(() => {
|
||||||
|
UI.showNotification(`Slot ${slot + 1} copied to clipboard!`, 'success');
|
||||||
|
});
|
||||||
|
return encoded;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import base64 save data into a chosen slot.
|
||||||
|
*/
|
||||||
|
importSlotFromData(data, slot) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(atob(data));
|
||||||
|
localStorage.setItem(this.getSaveKey(slot), JSON.stringify(parsed));
|
||||||
|
UI.showNotification(`Imported into Slot ${slot + 1}!`, 'success');
|
||||||
|
|
||||||
|
// If we imported into the active slot, reload it.
|
||||||
|
if (parseInt(slot, 10) === this.state.activeSlot) {
|
||||||
|
this.switchSlot(slot);
|
||||||
|
} else {
|
||||||
|
UI.update();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
UI.showNotification('Invalid save data!', 'warning');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export save as base64
|
* Export save as base64
|
||||||
*/
|
*/
|
||||||
@@ -572,7 +762,10 @@ const Game = {
|
|||||||
stellarEssence: 0,
|
stellarEssence: 0,
|
||||||
prestigeCount: 0,
|
prestigeCount: 0,
|
||||||
totalPrestigeEssence: 0,
|
totalPrestigeEssence: 0,
|
||||||
prestigeUpgrades: []
|
prestigeUpgrades: [],
|
||||||
|
goldenBlooms: { active: false, timer: 0, lastSpawn: Date.now(), totalClaimed: 0 },
|
||||||
|
activeSlot: this.state.activeSlot,
|
||||||
|
autoSave: this.state.autoSave
|
||||||
};
|
};
|
||||||
UI.update();
|
UI.update();
|
||||||
UI.showNotification('Game reset!', 'warning');
|
UI.showNotification('Game reset!', 'warning');
|
||||||
|
|||||||
+24
@@ -75,6 +75,16 @@ const Stats = {
|
|||||||
<div class="stat-bar-fill" id="stat-progress-bar" style="width: 0%"></div>
|
<div class="stat-bar-fill" id="stat-progress-bar" style="width: 0%"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Save Slot System -->
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">Active Save Slot</div>
|
||||||
|
<div class="stat-value" id="stat-active-slot">Slot 1 / ${Game.config.SLOTS}</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">Autosave</div>
|
||||||
|
<div class="stat-value" id="stat-autosave">ON</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -132,6 +142,20 @@ const Stats = {
|
|||||||
achievementsEl.textContent = `${Achievements.getCount()}/${Achievements.getTotal()}`;
|
achievementsEl.textContent = `${Achievements.getCount()}/${Achievements.getTotal()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Active save slot display
|
||||||
|
const activeSlotEl = document.getElementById('stat-active-slot');
|
||||||
|
if (activeSlotEl) {
|
||||||
|
const idx = Game.state.activeSlot || 0;
|
||||||
|
activeSlotEl.textContent = `Slot ${idx + 1} / ${Game.config.SLOTS}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autosave status display
|
||||||
|
const autosaveEl = document.getElementById('stat-autosave');
|
||||||
|
if (autosaveEl) {
|
||||||
|
autosaveEl.textContent = Game.state.autoSave ? 'ON' : 'OFF';
|
||||||
|
autosaveEl.style.color = Game.state.autoSave ? 'var(--accent-green)' : 'var(--text-muted)';
|
||||||
|
}
|
||||||
|
|
||||||
// Total Golden Blooms claimed
|
// Total Golden Blooms claimed
|
||||||
const goldenBloomsEl = document.getElementById('stat-golden-blooms');
|
const goldenBloomsEl = document.getElementById('stat-golden-blooms');
|
||||||
if (goldenBloomsEl) {
|
if (goldenBloomsEl) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const UI = {
|
|||||||
this.renderBuildings();
|
this.renderBuildings();
|
||||||
this.renderUpgrades();
|
this.renderUpgrades();
|
||||||
this.renderAchievements();
|
this.renderAchievements();
|
||||||
|
this.updateSlotUI();
|
||||||
this.update();
|
this.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -41,6 +42,9 @@ const UI = {
|
|||||||
|
|
||||||
// Golden Starbloom countdown badge
|
// Golden Starbloom countdown badge
|
||||||
this.updateGoldenBloomBadge();
|
this.updateGoldenBloomBadge();
|
||||||
|
|
||||||
|
// Save Slot System highlight / toggle state
|
||||||
|
this.updateSlotUI();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -297,6 +301,30 @@ const UI = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reflect the active save slot highlight and autosave toggle state.
|
||||||
|
*/
|
||||||
|
updateSlotUI() {
|
||||||
|
// Highlight the selected slot button.
|
||||||
|
document.querySelectorAll('.slot-btn').forEach(btn => {
|
||||||
|
const idx = parseInt(btn.dataset.slot, 10);
|
||||||
|
btn.classList.toggle('active', idx === Game.state.activeSlot);
|
||||||
|
btn.disabled = idx === Game.state.activeSlot;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reflect the autosave toggle state.
|
||||||
|
const autosaveBtn = document.getElementById('autosave-btn');
|
||||||
|
if (autosaveBtn) {
|
||||||
|
if (Game.state.autoSave) {
|
||||||
|
autosaveBtn.classList.add('on');
|
||||||
|
autosaveBtn.textContent = 'ON';
|
||||||
|
} else {
|
||||||
|
autosaveBtn.classList.remove('on');
|
||||||
|
autosaveBtn.textContent = 'OFF';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show floating text animation
|
* Show floating text animation
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user