/** * HybridAbilitySystem.js * * Phase 36: Hybrid Skill - Alfa Abilities * Player's unique Alfa powers to control and support zombies * * Abilities: * - Q: Heal Zombies (regenerate HP) * - E: Boost Zombies (temp strength/speed) * - R: Calm Wild Zombies (easier taming) * - F: Sense Danger (detect enemies) * * Energy System: Uses Alfa Energy (regenerates over time) */ class HybridAbilitySystem { constructor(scene) { this.scene = scene; // Alfa Energy (similar to mana, but for Alfa abilities) this.maxEnergy = 100; this.energy = 100; this.energyRegen = 5; // per second // Ability Definitions this.abilities = { // Q: Heal Zombies healZombies: { id: 'healZombies', name: 'Heal Zombies', key: 'Q', energyCost: 25, cooldown: 8000, // 8 seconds range: 150, // pixels healAmount: 30, description: 'Regenerate HP for all zombies in range', visualEffect: 'green_glow', soundEffect: 'heal_pulse' }, // E: Boost Zombies boostZombies: { id: 'boostZombies', name: 'Boost Zombies', key: 'E', energyCost: 30, cooldown: 15000, // 15 seconds range: 200, duration: 10000, // 10s buff speedBoost: 1.5, // +50% speed damageBoost: 1.3, // +30% damage efficiencyBoost: 1.5, // +50% work speed description: 'Temporarily boost zombie speed, damage, and work efficiency', visualEffect: 'yellow_aura', soundEffect: 'power_up' }, // R: Calm Wild Zombies calmWildZombies: { id: 'calmWildZombies', name: 'Calm Wild Zombies', key: 'R', energyCost: 20, cooldown: 12000, // 12 seconds range: 250, duration: 15000, // 15s peaceful state tamingBonus: 0.5, // +50% taming success chance description: 'Make wild zombies peaceful and easier to tame', visualEffect: 'blue_ripple', soundEffect: 'calm_wave' }, // F: Sense Danger senseDanger: { id: 'senseDanger', name: 'Sense Danger', key: 'F', energyCost: 15, cooldown: 20000, // 20 seconds range: 400, // large detection radius duration: 8000, // 8s reveal description: 'Detect all enemies in a large radius', visualEffect: 'red_pulse', soundEffect: 'danger_ping' } }; // Cooldown tracking this.cooldowns = new Map(); // Active buffs (zombie IDs with their buff data) this.activeBuffs = new Map(); // Revealed enemies (for Sense Danger) this.revealedEnemies = new Set(); // Visual effects this.visualEffects = []; // UI references this.energyBar = null; this.abilityIcons = new Map(); // Player level & unlocks this.playerLevel = 1; // Tracks Hybrid Skill level (1-10) this.unlockedAbilities = new Set(['healZombies']); // Start with heal this.init(); } init() { this.createUI(); this.setupInput(); this.setupEventListeners(); // Start energy regen this.scene.time.addEvent({ delay: 1000, callback: this.regenerateEnergy, callbackScope: this, loop: true }); console.log('[HybridAbilitySystem] Initialized - Alfa powers ready'); } // ==================== INPUT HANDLING ==================== setupInput() { // Ability hotkeys this.scene.input.keyboard.on('keydown-Q', () => this.useAbility('healZombies')); this.scene.input.keyboard.on('keydown-E', () => this.useAbility('boostZombies')); this.scene.input.keyboard.on('keydown-R', () => this.useAbility('calmWildZombies')); this.scene.input.keyboard.on('keydown-F', () => this.useAbility('senseDanger')); } setupEventListeners() { // Listen for zombie level up to award player XP this.scene.events.on('zombieLevelUp', (zombieId, newLevel) => { this.addPlayerXP(5); // 5 XP per zombie level }); // Listen for zombie death (inheritance) this.scene.events.on('zombieDeath', (zombieId, finalLevel) => { this.addPlayerXP(finalLevel * 2); // 2 XP per zombie's final level }); } // ==================== ABILITY USAGE ==================== useAbility(abilityId) { const ability = this.abilities[abilityId]; if (!ability) { console.warn(`[HybridAbilitySystem] Unknown ability: ${abilityId}`); return false; } // Check if unlocked if (!this.unlockedAbilities.has(abilityId)) { this.scene.uiSystem?.showMessage(`Ability locked! Unlock at Hybrid Skill level ${this.getUnlockLevel(abilityId)}`); return false; } // Check cooldown if (this.isOnCooldown(abilityId)) { const remaining = this.getCooldownRemaining(abilityId); this.scene.uiSystem?.showMessage(`${ability.name} on cooldown: ${(remaining / 1000).toFixed(1)}s`); return false; } // Check energy cost if (this.energy < ability.energyCost) { this.scene.uiSystem?.showMessage(`Not enough Alfa Energy! (${this.energy}/${ability.energyCost})`); return false; } // Execute ability console.log(`[HybridAbilitySystem] Using ${ability.name}`); this.consumeEnergy(ability.energyCost); this.startCooldown(abilityId, ability.cooldown); // Play sound if (ability.soundEffect) { this.scene.sound.play(ability.soundEffect, { volume: 0.5 }); } // Execute specific ability logic switch (abilityId) { case 'healZombies': this.executeHeal(ability); break; case 'boostZombies': this.executeBoost(ability); break; case 'calmWildZombies': this.executeCalm(ability); break; case 'senseDanger': this.executeSense(ability); break; } return true; } // ==================== ABILITY EXECUTIONS ==================== executeHeal(ability) { const player = this.scene.player; const zombieSystem = this.scene.zombieSystem; if (!zombieSystem) return; let healed = 0; // Find all zombies in range zombieSystem.zombies.forEach((zombie, zombieId) => { const dist = Phaser.Math.Distance.Between( player.x, player.y, zombie.sprite.x, zombie.sprite.y ); if (dist <= ability.range && zombie.state !== 'dead') { // Heal zombie const oldHp = zombie.hp; zombie.hp = Math.min(zombie.hp + ability.healAmount, zombie.maxHp); healed++; // Visual: Green heal particles this.createHealEffect(zombie.sprite.x, zombie.sprite.y); // Show floating text this.showFloatingText(zombie.sprite.x, zombie.sprite.y, `+${zombie.hp - oldHp} HP`, 0x00ff00); console.log(`[HybridAbilitySystem] Healed zombie ${zombieId}: ${oldHp} → ${zombie.hp}`); } }); // Player feedback this.createPlayerEffect(ability.visualEffect); this.scene.uiSystem?.showMessage(`Healed ${healed} zombie(s)!`, 0x00ff00); } executeBoost(ability) { const player = this.scene.player; const zombieSystem = this.scene.zombieSystem; if (!zombieSystem) return; let boosted = 0; zombieSystem.zombies.forEach((zombie, zombieId) => { const dist = Phaser.Math.Distance.Between( player.x, player.y, zombie.sprite.x, zombie.sprite.y ); if (dist <= ability.range && zombie.state !== 'dead') { // Apply buff this.applyBoostBuff(zombieId, zombie, ability); boosted++; // Visual: Yellow aura this.createBoostEffect(zombie.sprite); console.log(`[HybridAbilitySystem] Boosted zombie ${zombieId} for ${ability.duration}ms`); } }); this.createPlayerEffect(ability.visualEffect); this.scene.uiSystem?.showMessage(`Boosted ${boosted} zombie(s)!`, 0xffff00); } executeCalm(ability) { const player = this.scene.player; const zombieSystem = this.scene.zombieSystem; if (!zombieSystem) return; let calmed = 0; zombieSystem.zombies.forEach((zombie, zombieId) => { const dist = Phaser.Math.Distance.Between( player.x, player.y, zombie.sprite.x, zombie.sprite.y ); if (dist <= ability.range && zombie.state === 'wild') { // Apply calm buff this.applyCalmBuff(zombieId, zombie, ability); calmed++; // Visual: Blue ripple this.createCalmEffect(zombie.sprite.x, zombie.sprite.y); // Make zombie peaceful zombie.aggression = Math.max(0, zombie.aggression - 50); zombie.sprite.setTint(0x88ccff); // Blue tint console.log(`[HybridAbilitySystem] Calmed wild zombie ${zombieId}`); } }); this.createPlayerEffect(ability.visualEffect); this.scene.uiSystem?.showMessage(`Calmed ${calmed} wild zombie(s)!`, 0x00aaff); } executeSense(ability) { const player = this.scene.player; // Clear previous reveals this.revealedEnemies.clear(); // Find all enemies in range let detected = 0; // Check enemy groups (you'd have an enemySystem or similar) // For now, placeholder detection logic if (this.scene.enemies) { this.scene.enemies.forEach((enemy) => { const dist = Phaser.Math.Distance.Between( player.x, player.y, enemy.x, enemy.y ); if (dist <= ability.range) { this.revealedEnemies.add(enemy); detected++; // Visual: Red outline on enemy enemy.setTint(0xff0000); // Auto-remove tint after duration this.scene.time.delayedCall(ability.duration, () => { enemy.clearTint(); }); } }); } // Player visual: Red pulse this.createSenseEffect(player.x, player.y, ability.range); if (detected > 0) { this.scene.uiSystem?.showMessage(`⚠️ ${detected} enemies detected!`, 0xff0000); } else { this.scene.uiSystem?.showMessage(`No enemies nearby`, 0x00ff00); } console.log(`[HybridAbilitySystem] Sense Danger: ${detected} enemies revealed`); } // ==================== BUFF MANAGEMENT ==================== applyBoostBuff(zombieId, zombie, ability) { const buffData = { zombieId, type: 'boost', speedMultiplier: ability.speedBoost, damageMultiplier: ability.damageBoost, efficiencyMultiplier: ability.efficiencyBoost, startTime: Date.now(), duration: ability.duration }; this.activeBuffs.set(zombieId, buffData); // Auto-remove after duration this.scene.time.delayedCall(ability.duration, () => { this.removeBoostBuff(zombieId); }); } removeBoostBuff(zombieId) { if (this.activeBuffs.has(zombieId)) { this.activeBuffs.delete(zombieId); console.log(`[HybridAbilitySystem] Boost buff expired for zombie ${zombieId}`); } } applyCalmBuff(zombieId, zombie, ability) { const buffData = { zombieId, type: 'calm', tamingBonus: ability.tamingBonus, startTime: Date.now(), duration: ability.duration }; this.activeBuffs.set(zombieId, buffData); // Auto-remove this.scene.time.delayedCall(ability.duration, () => { this.removeCalmBuff(zombieId, zombie); }); } removeCalmBuff(zombieId, zombie) { if (this.activeBuffs.has(zombieId)) { this.activeBuffs.delete(zombieId); // Remove blue tint if (zombie && zombie.sprite) { zombie.sprite.clearTint(); } console.log(`[HybridAbilitySystem] Calm buff expired for zombie ${zombieId}`); } } // Get active buff for zombie (for ZombieSystem to query) getZombieBuff(zombieId) { return this.activeBuffs.get(zombieId); } // ==================== ENERGY MANAGEMENT ==================== consumeEnergy(amount) { this.energy = Math.max(0, this.energy - amount); this.updateEnergyBar(); } regenerateEnergy() { if (this.energy < this.maxEnergy) { this.energy = Math.min(this.maxEnergy, this.energy + this.energyRegen); this.updateEnergyBar(); } } // ==================== COOLDOWN MANAGEMENT ==================== startCooldown(abilityId, duration) { this.cooldowns.set(abilityId, Date.now() + duration); } isOnCooldown(abilityId) { if (!this.cooldowns.has(abilityId)) return false; return Date.now() < this.cooldowns.get(abilityId); } getCooldownRemaining(abilityId) { if (!this.isOnCooldown(abilityId)) return 0; return this.cooldowns.get(abilityId) - Date.now(); } // ==================== PLAYER PROGRESSION ==================== addPlayerXP(amount) { // TODO: Implement full XP/level system // For now, just log console.log(`[HybridAbilitySystem] Player gained ${amount} Hybrid XP`); // Check for level ups (placeholder) // this.checkLevelUp(); } getUnlockLevel(abilityId) { const unlockLevels = { healZombies: 1, // Start ability calmWildZombies: 3, boostZombies: 5, senseDanger: 7 }; return unlockLevels[abilityId] || 10; } unlockAbility(abilityId) { this.unlockedAbilities.add(abilityId); this.scene.uiSystem?.showMessage(`Unlocked: ${this.abilities[abilityId].name}!`, 0xffaa00); console.log(`[HybridAbilitySystem] Unlocked ability: ${abilityId}`); } // ==================== VISUAL EFFECTS ==================== createHealEffect(x, y) { // Green particles rising const particles = this.scene.add.particles(x, y, 'particle', { speed: { min: -50, max: -100 }, scale: { start: 0.5, end: 0 }, tint: 0x00ff00, lifespan: 1000, quantity: 10 }); this.scene.time.delayedCall(1000, () => particles.destroy()); } createBoostEffect(sprite) { // Yellow aura around zombie const aura = this.scene.add.circle(sprite.x, sprite.y, 30, 0xffff00, 0.3); aura.setDepth(sprite.depth - 1); // Pulse animation this.scene.tweens.add({ targets: aura, scale: { from: 1, to: 1.2 }, alpha: { from: 0.3, to: 0.1 }, duration: 500, yoyo: true, repeat: -1 }); // Remove after 10s this.scene.time.delayedCall(10000, () => aura.destroy()); } createCalmEffect(x, y) { // Blue ripple expanding const ripple = this.scene.add.circle(x, y, 10, 0x88ccff, 0.5); this.scene.tweens.add({ targets: ripple, radius: 100, alpha: 0, duration: 1000, onComplete: () => ripple.destroy() }); } createSenseEffect(x, y, range) { // Red pulse expanding to range const pulse = this.scene.add.circle(x, y, 10, 0xff0000, 0.3); this.scene.tweens.add({ targets: pulse, radius: range, alpha: 0, duration: 800, onComplete: () => pulse.destroy() }); } createPlayerEffect(effectType) { const player = this.scene.player; // Brief flash around player const flash = this.scene.add.circle(player.x, player.y, 50, effectType === 'green_glow' ? 0x00ff00 : effectType === 'yellow_aura' ? 0xffff00 : effectType === 'blue_ripple' ? 0x88ccff : 0xff0000, 0.4); this.scene.tweens.add({ targets: flash, alpha: 0, scale: 1.5, duration: 500, onComplete: () => flash.destroy() }); } showFloatingText(x, y, text, color) { const floatText = this.scene.add.text(x, y - 20, text, { fontSize: '16px', color: `#${color.toString(16).padStart(6, '0')}`, stroke: '#000', strokeThickness: 3 }).setOrigin(0.5); this.scene.tweens.add({ targets: floatText, y: y - 60, alpha: 0, duration: 1500, onComplete: () => floatText.destroy() }); } // ==================== UI ==================== createUI() { // Energy bar (top-left, below HP/Stamina) this.energyBar = this.scene.add.graphics(); this.energyBar.setScrollFactor(0); this.energyBar.setDepth(1000); this.updateEnergyBar(); // Ability icons (bottom of screen) const abilities = ['healZombies', 'calmWildZombies', 'boostZombies', 'senseDanger']; abilities.forEach((abilityId, index) => { // TODO: Create actual icons // For now just placeholders }); } updateEnergyBar() { if (!this.energyBar) return; this.energyBar.clear(); // Background this.energyBar.fillStyle(0x222222, 0.8); this.energyBar.fillRect(10, 70, 200, 20); // Energy fill (purple/pink for Alfa) const energyWidth = (this.energy / this.maxEnergy) * 196; this.energyBar.fillStyle(0xff00ff, 1); this.energyBar.fillRect(12, 72, energyWidth, 16); // Border this.energyBar.lineStyle(2, 0xffffff, 1); this.energyBar.strokeRect(10, 70, 200, 20); } // ==================== UPDATE ==================== update(time, delta) { // Update cooldown visuals // Update buff timers // (placeholder for now) } // ==================== CLEANUP ==================== destroy() { if (this.energyBar) this.energyBar.destroy(); this.visualEffects.forEach(effect => effect.destroy()); this.activeBuffs.clear(); this.cooldowns.clear(); console.log('[HybridAbilitySystem] Destroyed'); } } // Export for use in GameScene if (typeof module !== 'undefined' && module.exports) { module.exports = HybridAbilitySystem; }