218 lines
5.5 KiB
JavaScript
218 lines
5.5 KiB
JavaScript
/**
|
|
* 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<string>} 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;
|