/** * CurrencyManager.js * Manages the single in-game currency: Gold. * Simplified from the original multi-currency system (monetization-lite). * Provides add/spend/get operations with EventBus notifications, * StorageManager persistence, and overflow protection. */ /** Maximum gold cap to prevent overflow. */ const MAX_GOLD = 999999; class CurrencyManager { constructor() { this._gold = 0; this._load(); } // ============================================================ // Persistence // ============================================================ /** * Load currency data from StorageManager. * @private */ _load() { try { if (GameGlobal && GameGlobal.storageManager) { const data = GameGlobal.storageManager.get('currency', null); if (data) { this._gold = data.gold || 0; } } } catch (e) { console.warn('[CurrencyManager] Failed to load currency data:', e); } } /** * Save currency data to StorageManager. * @private */ _save() { try { if (GameGlobal && GameGlobal.storageManager) { GameGlobal.storageManager.set('currency', { gold: this._gold, }); } } catch (e) { console.warn('[CurrencyManager] Failed to save currency data:', e); } } /** * Emit a currency change event via EventBus. * @private */ _emitGoldChanged() { try { if (GameGlobal && GameGlobal.eventBus) { GameGlobal.eventBus.emit('currency:gold:changed', this._gold); } } catch (e) {} } // ============================================================ // Gold // ============================================================ /** * Get current gold amount. * @returns {number} */ getGold() { return this._gold; } /** * Add gold (capped at MAX_GOLD). * @param {number} amount - Must be positive. * @returns {number} Actual amount added (may be less if capped). */ addGold(amount) { if (amount <= 0) return 0; const before = this._gold; this._gold = Math.min(this._gold + Math.floor(amount), MAX_GOLD); const added = this._gold - before; if (added > 0) { this._save(); this._emitGoldChanged(); } return added; } /** * Spend gold. * @param {number} amount - Must be positive. * @returns {boolean} True if successful, false if insufficient. */ spendGold(amount) { if (amount <= 0) return true; if (this._gold < amount) { // Emit insufficient event for UI to handle try { if (GameGlobal && GameGlobal.eventBus) { GameGlobal.eventBus.emit('currency:gold:insufficient', { required: amount, current: this._gold }); } } catch (e) {} return false; } this._gold -= Math.floor(amount); this._save(); this._emitGoldChanged(); return true; } /** * Check if player has enough gold. * @param {number} amount * @returns {boolean} */ hasGold(amount) { return this._gold >= amount; } /** * Check if gold is at maximum cap. * @returns {boolean} */ isGoldFull() { return this._gold >= MAX_GOLD; } /** * Get the maximum gold cap. * @returns {number} */ getMaxGold() { return MAX_GOLD; } // ============================================================ // Cloud Sync // ============================================================ /** * Get currency data for cloud sync. * @returns {object} */ getCloudSyncData() { return { gold: this._gold, }; } /** * Restore currency data from cloud (merge: keep higher values). * @param {object} cloudData */ restoreFromCloud(cloudData) { if (!cloudData) return; if (cloudData.gold !== undefined && cloudData.gold > this._gold) { this._gold = Math.min(cloudData.gold, MAX_GOLD); this._save(); this._emitGoldChanged(); } } } module.exports = CurrencyManager;