/** * BuffManager.js * Manages pre-game buff purchases and activation. * Buffs are one-time per round: Shield (100g) and Double Fire (150g). */ /** Buff type definitions. */ const BUFF_TYPE = { SHIELD: 'SHIELD', DOUBLE_FIRE: 'DOUBLE_FIRE', }; /** Buff cost in gold. */ const BUFF_COST = { [BUFF_TYPE.SHIELD]: 100, [BUFF_TYPE.DOUBLE_FIRE]: 150, }; /** Double fire duration in seconds. */ const DOUBLE_FIRE_DURATION = 10; class BuffManager { constructor() { /** @type {Set} Active buffs for the current round. */ this._activeBuffs = new Set(); /** @type {number} Remaining double fire time in seconds. */ this._doubleFireTimer = 0; /** @type {boolean} Whether shield is currently active. */ this._shieldActive = false; } // ============================================================ // Purchase // ============================================================ /** * Purchase a buff for the upcoming round. * Deducts gold via CurrencyManager. * @param {string} buffType - One of BUFF_TYPE values. * @returns {{ success: boolean, error?: string }} */ purchaseBuff(buffType) { const cost = BUFF_COST[buffType]; if (cost === undefined) { return { success: false, error: 'Invalid buff type' }; } if (this._activeBuffs.has(buffType)) { return { success: false, error: 'Already purchased' }; } const cm = GameGlobal.currencyManager; if (!cm || !cm.hasGold(cost)) { return { success: false, error: 'Insufficient gold' }; } const spent = cm.spendGold(cost); if (!spent) { return { success: false, error: 'Insufficient gold' }; } this._activeBuffs.add(buffType); console.log(`[BuffManager] Purchased buff: ${buffType} for ${cost} gold`); // Emit event try { if (GameGlobal.eventBus) { GameGlobal.eventBus.emit('buff:purchased', { type: buffType, cost }); } } catch (e) {} return { success: true }; } // ============================================================ // Activation & Game Logic // ============================================================ /** * Check if a buff was purchased for this round. * @param {string} buffType * @returns {boolean} */ hasBuff(buffType) { return this._activeBuffs.has(buffType); } /** * Get all active buffs for this round. * @returns {string[]} */ getActiveBuffs() { return Array.from(this._activeBuffs); } /** * Activate buffs at the start of a round. * Should be called when the game scene initializes. * @param {object} playerTank - The player tank instance. */ activateBuffs(playerTank) { if (!playerTank) return; // Shield buff: add a shield layer to the player tank if (this._activeBuffs.has(BUFF_TYPE.SHIELD)) { this._shieldActive = true; playerTank._buffShield = true; console.log('[BuffManager] Shield buff activated'); } // Double fire buff: start the timer if (this._activeBuffs.has(BUFF_TYPE.DOUBLE_FIRE)) { this._doubleFireTimer = DOUBLE_FIRE_DURATION; playerTank._buffDoubleFire = true; console.log('[BuffManager] Double fire buff activated'); } } /** * Update buff timers. Called every frame from GameScene. * @param {number} dt - Delta time in seconds. * @param {object} playerTank - The player tank instance. */ update(dt, playerTank) { if (!playerTank) return; // Double fire timer countdown if (this._doubleFireTimer > 0) { this._doubleFireTimer -= dt; if (this._doubleFireTimer <= 0) { this._doubleFireTimer = 0; playerTank._buffDoubleFire = false; console.log('[BuffManager] Double fire buff expired'); } } } /** * Consume the shield buff (called when player takes damage). * @param {object} playerTank - The player tank instance. * @returns {boolean} True if shield was consumed (damage absorbed). */ consumeShield(playerTank) { if (this._shieldActive && playerTank && playerTank._buffShield) { this._shieldActive = false; playerTank._buffShield = false; console.log('[BuffManager] Shield buff consumed'); // Emit event for visual feedback try { if (GameGlobal.eventBus) { GameGlobal.eventBus.emit('buff:shield:consumed'); } } catch (e) {} return true; } return false; } /** * Check if double fire is currently active. * @returns {boolean} */ isDoubleFireActive() { return this._doubleFireTimer > 0; } /** * Get remaining double fire time in seconds. * @returns {number} */ getDoubleFireRemaining() { return Math.max(0, this._doubleFireTimer); } /** * Check if shield buff is still active (not yet consumed). * @returns {boolean} */ isShieldActive() { return this._shieldActive; } // ============================================================ // Round Lifecycle // ============================================================ /** * Clear all buffs at the end of a round. * Must be called when the game ends (win or lose). */ clearBuffs() { this._activeBuffs.clear(); this._doubleFireTimer = 0; this._shieldActive = false; console.log('[BuffManager] All buffs cleared'); } /** * Get buff cost. * @param {string} buffType * @returns {number} */ getBuffCost(buffType) { return BUFF_COST[buffType] || 0; } } // Export constants BuffManager.BUFF_TYPE = BUFF_TYPE; BuffManager.BUFF_COST = BUFF_COST; BuffManager.DOUBLE_FIRE_DURATION = DOUBLE_FIRE_DURATION; module.exports = BuffManager;