/** * StorageManager.js * Handles local data persistence using wx.setStorageSync/getStorageSync. * Manages game save data, settings, and high scores. */ class StorageManager { constructor() { this._prefix = 'tankwar_'; } // ============================================================ // Generic Storage // ============================================================ /** * Save a value to local storage. * @param {string} key * @param {*} value - Will be JSON-serialized. */ set(key, value) { try { wx.setStorageSync(this._prefix + key, JSON.stringify(value)); } catch (e) { console.warn(`[StorageManager] Failed to save "${key}":`, e); } } /** * Load a value from local storage. * @param {string} key * @param {*} [defaultValue=null] * @returns {*} Parsed value, or defaultValue if not found. */ get(key, defaultValue = null) { try { const raw = wx.getStorageSync(this._prefix + key); if (raw === '' || raw === undefined || raw === null) return defaultValue; return JSON.parse(raw); } catch (e) { console.warn(`[StorageManager] Failed to load "${key}":`, e); return defaultValue; } } /** * Remove a value from local storage. * @param {string} key */ remove(key) { try { wx.removeStorageSync(this._prefix + key); } catch (e) {} } // ============================================================ // Game Progress // ============================================================ /** * Save game progress. * @param {object} progress * @param {number} progress.currentLevel * @param {number} progress.lives * @param {number} progress.fireLevel * @param {string} progress.mode */ saveProgress(progress) { this.set('progress', progress); } /** * Load game progress. * @returns {object|null} */ loadProgress() { return this.get('progress', null); } /** * Clear saved progress. */ clearProgress() { this.remove('progress'); } // ============================================================ // High Scores // ============================================================ /** * Get the high score for a mode. * @param {string} mode - Game mode. * @returns {number} */ getHighScore(mode) { const scores = this.get('highscores', {}); return scores[mode] || 0; } /** * Update high score if the new score is higher. * @param {string} mode * @param {number} score * @returns {boolean} Whether a new high score was set. */ updateHighScore(mode, score) { const scores = this.get('highscores', {}); if (score > (scores[mode] || 0)) { scores[mode] = score; this.set('highscores', scores); return true; } return false; } /** * Get the highest level reached. * @returns {number} */ getHighestLevel() { return this.get('highest_level', 0); } /** * Update highest level if new level is higher. * @param {number} level */ updateHighestLevel(level) { const current = this.getHighestLevel(); if (level > current) { this.set('highest_level', level); } } // ============================================================ // Settings // ============================================================ /** * Save game settings. * @param {object} settings */ saveSettings(settings) { this.set('settings', settings); } /** * Load game settings. * @returns {object} */ loadSettings() { return this.get('settings', { soundEnabled: true, musicEnabled: true, vibrationEnabled: true, }); } // ============================================================ // Purchases & Unlocks // ============================================================ /** * Record a purchase. * @param {string} itemId */ recordPurchase(itemId) { const purchases = this.get('purchases', []); if (!purchases.includes(itemId)) { purchases.push(itemId); this.set('purchases', purchases); } } /** * Check if an item has been purchased. * @param {string} itemId * @returns {boolean} */ hasPurchased(itemId) { const purchases = this.get('purchases', []); return purchases.includes(itemId); } // ============================================================ // First-time flags // ============================================================ /** * Check if this is the first time playing. * @returns {boolean} */ isFirstPlay() { return !this.get('has_played', false); } /** * Mark that the player has played. */ markPlayed() { this.set('has_played', true); } // ============================================================ // Cloud Sync Helpers // ============================================================ /** * Get data to sync to cloud. * @returns {object} */ getCloudSyncData() { return { highscores: this.get('highscores', {}), highest_level: this.getHighestLevel(), purchases: this.get('purchases', []), }; } /** * Restore data from cloud. * @param {object} cloudData */ restoreFromCloud(cloudData) { if (cloudData.highscores) { const local = this.get('highscores', {}); // Merge: keep the higher score for (const [mode, score] of Object.entries(cloudData.highscores)) { if (score > (local[mode] || 0)) { local[mode] = score; } } this.set('highscores', local); } if (cloudData.highest_level) { this.updateHighestLevel(cloudData.highest_level); } if (cloudData.purchases) { const local = this.get('purchases', []); const merged = [...new Set([...local, ...cloudData.purchases])]; this.set('purchases', merged); } } } module.exports = StorageManager;