/** * EnhancedAudioSystem.js * * Complete audio system with: * - Ambient loops (crickets, wind, city noise) * - Animal sounds (random intervals near farm) * - Intro heartbeat + blur effect * - Accessibility (visual indicators) * - Xbox haptic feedback * - .wav -> .ogg optimization * * Created: Jan 10, 2026 * Author: David "HIPO" Kotnik * Studio: Hipodevil666 Studiosโ„ข */ export default class EnhancedAudioSystem { constructor(scene) { this.scene = scene; // Audio references this.ambientLoops = {}; this.animalSounds = {}; this.currentAmbient = null; // Animal sound timers this.animalTimers = {}; // Haptic feedback support this.hapticEnabled = true; // Visual accessibility indicators this.visualIndicators = {}; console.log('๐Ÿ”Š Enhanced Audio System initialized!'); } /** * Load all audio assets */ preloadAudio() { const scene = this.scene; // AMBIENT LOOPS scene.load.audio('ambient_crickets', 'assets/audio/ambient/crickets_loop.ogg'); scene.load.audio('ambient_wind', 'assets/audio/ambient/wind_loop.ogg'); scene.load.audio('ambient_city', 'assets/audio/ambient/city_noise_loop.ogg'); scene.load.audio('ambient_forest', 'assets/audio/ambient/forest_loop.ogg'); // ANIMAL SOUNDS scene.load.audio('animal_sheep', 'assets/audio/animals/sheep.ogg'); scene.load.audio('animal_pig', 'assets/audio/animals/pig.ogg'); scene.load.audio('animal_chicken', 'assets/audio/animals/chicken.ogg'); scene.load.audio('animal_horse', 'assets/audio/animals/horse.ogg'); scene.load.audio('animal_goat', 'assets/audio/animals/goat.ogg'); scene.load.audio('animal_cow', 'assets/audio/animals/cow.ogg'); // INTRO EFFECTS scene.load.audio('intro_heartbeat', 'assets/audio/effects/heartbeat.ogg'); // UI SOUNDS scene.load.audio('raid_warning', 'assets/audio/ui/raid_alarm.ogg'); console.log('๐ŸŽต Audio assets queued for loading...'); } /** * Initialize audio after load */ initialize() { const scene = this.scene; // Create ambient loops this.ambientLoops = { crickets: scene.sound.add('ambient_crickets', { loop: true, volume: 0.3 }), wind: scene.sound.add('ambient_wind', { loop: true, volume: 0.2 }), city: scene.sound.add('ambient_city', { loop: true, volume: 0.15 }), forest: scene.sound.add('ambient_forest', { loop: true, volume: 0.25 }) }; // Create animal sounds this.animalSounds = { sheep: scene.sound.add('animal_sheep', { volume: 0.4 }), pig: scene.sound.add('animal_pig', { volume: 0.4 }), chicken: scene.sound.add('animal_chicken', { volume: 0.35 }), horse: scene.sound.add('animal_horse', { volume: 0.5 }), goat: scene.sound.add('animal_goat', { volume: 0.4 }), cow: scene.sound.add('animal_cow', { volume: 0.45 }) }; console.log('๐ŸŽต Enhanced Audio System ready!'); } /** * Play ambient loop based on biome */ playAmbient(biomeType) { // Stop current ambient if (this.currentAmbient) { this.currentAmbient.stop(); } // Select ambient based on biome let ambient = null; switch (biomeType) { case 'grassland': case 'farm': ambient = this.ambientLoops.crickets; break; case 'forest': ambient = this.ambientLoops.forest; break; case 'wasteland': case 'radioactive': ambient = this.ambientLoops.wind; break; case 'town': case 'city': ambient = this.ambientLoops.city; break; default: ambient = this.ambientLoops.crickets; } if (ambient) { ambient.play(); this.currentAmbient = ambient; console.log(`๐ŸŽต Playing ambient: ${biomeType}`); } } /** * Start random animal sounds near farm */ startAnimalSounds(playerX, playerY) { // Random intervals: 5-15 seconds Object.keys(this.animalSounds).forEach(animal => { this.animalTimers[animal] = this.scene.time.addEvent({ delay: Phaser.Math.Between(5000, 15000), callback: () => { // Check if player is near farm (within 500px) // This is simplified - you'd check actual farm position const nearFarm = true; // TODO: Implement proximity check if (nearFarm && !this.animalSounds[animal].isPlaying) { this.animalSounds[animal].play(); console.log(`๐Ÿ‘ ${animal} sound played!`); } }, loop: true }); }); console.log('๐Ÿ„ Animal sounds started!'); } /** * Stop animal sounds */ stopAnimalSounds() { Object.values(this.animalTimers).forEach(timer => { if (timer) timer.remove(); }); this.animalTimers = {}; console.log('๐Ÿ”‡ Animal sounds stopped!'); } /** * Play intro sequence (heartbeat + blur effect) */ playIntroSequence() { const scene = this.scene; // Play heartbeat const heartbeat = scene.sound.add('intro_heartbeat', { volume: 0.6 }); heartbeat.play(); // Blur-to-clear effect (Kai's amnesia) const blurStrength = 10; const camera = scene.cameras.main; // Apply initial blur (using postFX if available) // Note: Phaser 3.60+ has built-in blur, older versions need custom shader if (camera.setPostPipeline) { // Modern Phaser blur camera.setPostPipeline('BlurPostFX'); } // Clear blur over 3 seconds (synchronized with heartbeat) scene.tweens.add({ targets: camera, scrollX: 0, // Placeholder - actual blur would use custom property duration: 3000, ease: 'Power2', onUpdate: (tween) => { // Reduce blur over time const progress = tween.progress; // TODO: Update actual blur shader strength here }, onComplete: () => { // Remove blur effect if (camera.resetPostPipeline) { camera.resetPostPipeline(); } console.log('๐Ÿ‘๏ธ Vision cleared - amnesia intro complete!'); } }); // Haptic feedback (heartbeat pulse) this.vibrate(200, 500); // 200ms pulse, 500ms between console.log('๐Ÿ’“ Intro sequence playing...'); } /** * Show visual indicator for deaf accessibility */ showVisualIndicator(type, duration = 2000) { const scene = this.scene; const { width, height } = scene.cameras.main; let indicator; let color = 0xFFFFFF; let icon = '!'; switch (type) { case 'raid': color = 0xFF0000; // Red icon = 'โš ๏ธ RAID!'; break; case 'animal': color = 0x00FF00; // Green icon = '๐Ÿ„'; break; case 'danger': color = 0xFF8800; // Orange icon = 'โšก'; break; default: icon = '๐Ÿ””'; } // Create visual indicator indicator = scene.add.text(width / 2, 100, icon, { fontSize: '48px', color: '#' + color.toString(16).padStart(6, '0'), stroke: '#000000', strokeThickness: 4, shadow: { offsetX: 0, offsetY: 0, color: '#' + color.toString(16).padStart(6, '0'), blur: 20, fill: true } }).setOrigin(0.5); indicator.setScrollFactor(0); // Fixed to camera indicator.setDepth(1000); // Always on top // Pulse animation scene.tweens.add({ targets: indicator, scaleX: 1.2, scaleY: 1.2, alpha: 0.7, duration: 500, yoyo: true, repeat: Math.floor(duration / 1000) }); // Remove after duration scene.time.delayedCall(duration, () => { indicator.destroy(); }); console.log(`๐Ÿ‘๏ธ Visual indicator shown: ${type}`); } /** * Xbox controller vibration (haptic feedback) */ vibrate(duration = 200, interval = 0) { if (!this.hapticEnabled) return; const scene = this.scene; // Check for gamepad support if (scene.input.gamepad && scene.input.gamepad.total > 0) { const pad = scene.input.gamepad.getPad(0); if (pad && pad.vibration) { // Vibrate motors (weak, strong) pad.vibration.playEffect('dual-rumble', { startDelay: 0, duration: duration, weakMagnitude: 0.5, strongMagnitude: 1.0 }); // Repeat if interval specified if (interval > 0) { scene.time.delayedCall(duration + interval, () => { this.vibrate(duration, interval); }); } console.log(`๐ŸŽฎ Haptic feedback: ${duration}ms`); } } } /** * Play raid warning with visual + haptic feedback */ playRaidWarning() { const scene = this.scene; // Audio warning const raidSound = scene.sound.add('raid_warning', { volume: 0.7 }); raidSound.play(); // Visual indicator (accessibility) this.showVisualIndicator('raid', 3000); // Haptic feedback (3 strong pulses) this.vibrate(300, 300); this.vibrate(300, 600); this.vibrate(300, 900); console.log('โš ๏ธ RAID WARNING! (audio + visual + haptic)'); } /** * Update system (called in scene's update loop) */ update(time, delta) { // Future: proximity checks for animal sounds, etc. } /** * Cleanup */ destroy() { // Stop all sounds if (this.currentAmbient) { this.currentAmbient.stop(); } this.stopAnimalSounds(); console.log('๐Ÿ”‡ Enhanced Audio System destroyed!'); } }