diff --git a/assets/audio/footstep_grass.wav b/assets/audio/footstep_grass.wav new file mode 100644 index 000000000..1b31189a6 --- /dev/null +++ b/assets/audio/footstep_grass.wav @@ -0,0 +1,1446 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page not found · GitHub · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+ + + +
+
+ +
+
+ 404 “This is not the web page you are looking for” + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/assets/audio/forest_ambient.mp3 b/assets/audio/forest_ambient.mp3 new file mode 100644 index 000000000..58778f780 --- /dev/null +++ b/assets/audio/forest_ambient.mp3 @@ -0,0 +1,1446 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page not found · GitHub · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+ + + +
+
+ +
+
+ 404 “This is not the web page you are looking for” + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/assets/audio/wood_chop.wav b/assets/audio/wood_chop.wav new file mode 100644 index 000000000..707b76dfc --- /dev/null +++ b/assets/audio/wood_chop.wav @@ -0,0 +1,1446 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page not found · GitHub · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+ + + +
+
+ +
+
+ 404 “This is not the web page you are looking for” + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/src/entities/Player.js b/src/entities/Player.js index 71a362048..f8d799204 100644 --- a/src/entities/Player.js +++ b/src/entities/Player.js @@ -450,6 +450,23 @@ class Player { if (this.sprite.anims.currentAnim) { this.sprite.anims.currentAnim.frameRate = frameRate; } + + // 🔉 PHASE 8: Footstep triggers (frames 1 and 3 are usually down-steps) + const currentFrame = this.sprite.anims.currentFrame ? this.sprite.anims.currentFrame.index : 0; + if ((currentFrame === 1 || currentFrame === 3) && this.lastFootstepFrame !== currentFrame) { + if (this.scene.soundManager) { + // Determine surface + let surface = 'grass'; + if (this.scene.terrainSystem && this.scene.terrainSystem.getTile) { + const tile = this.scene.terrainSystem.getTile(this.gridX, this.gridY); + if (tile && tile.type === 'dirt') surface = 'dirt'; + } + this.scene.soundManager.playFootstep(surface); + } + this.lastFootstepFrame = currentFrame; + } else if (currentFrame !== 1 && currentFrame !== 3) { + this.lastFootstepFrame = -1; + } } } @@ -773,6 +790,8 @@ class Player { const used = this.scene.statusEffectSystem.applyEffect('high'); if (used) { invSys.removeItem(slot.type, 1); + // Audio feedback + if (this.scene.soundManager) this.scene.soundManager.playSmokeSound(); // Visual feedback this.createSmokeParticles(this.gridX, this.gridY); this.scene.events.emit('show-floating-text', { diff --git a/src/scenes/GameScene.js b/src/scenes/GameScene.js index 607787bcc..eb482f365 100644 --- a/src/scenes/GameScene.js +++ b/src/scenes/GameScene.js @@ -809,6 +809,7 @@ class GameScene extends Phaser.Scene { console.log('🎵 Initializing Sound Manager...'); this.soundManager = new SoundManager(this); this.soundManager.startMusic(); + this.soundManager.playForestAmbient(); // 🌲 PHASE 9: Start background ambience // Initialize Parallax System console.log('🌄 Initializing Parallax System...'); @@ -1987,7 +1988,26 @@ class GameScene extends Phaser.Scene { } } - // Parallax Logic + // 🎵 PHASE 8: Pond Proximity Audio Modulation + if (this.player && this.lakeSystem && this.soundManager) { + const playerPos = this.player.getPosition(); + let minPondDist = 1000; + + // Find nearest pond + this.lakeSystem.lakes.forEach(lake => { + if (lake.type === 'pond' || lake.type === 'lake') { + const d = Phaser.Math.Distance.Between(playerPos.x, playerPos.y, lake.x, lake.y); + if (d < minPondDist) minPondDist = d; + } + }); + + // Map distance to modulation factor (e.g., 0 within 5 tiles, 1 far away) + // Or 1 at pond center, 0 far away? User said "malo spremeni, ko sem blizu" + // Let's go with 1.0 (max change) at dist=0, and 0.0 (no change) beyond 15 tiles + const modFactor = Phaser.Math.Clamp(1 - (minPondDist / 15), 0, 1); + this.soundManager.setAmbientModulation(modFactor); + } + if (this.parallaxSystem && this.player) { const playerPos = this.player.getPosition(); // 🎨 FLAT 2D (NEW!) - Direct position, no conversion diff --git a/src/scenes/PreloadScene.js b/src/scenes/PreloadScene.js index b6030f333..aacd5fc1a 100644 --- a/src/scenes/PreloadScene.js +++ b/src/scenes/PreloadScene.js @@ -386,10 +386,12 @@ class PreloadScene extends Phaser.Scene { console.log('🎮 Krvava Žetev: 122+ sprite sheets loaded!'); */ - // ═══════════════════════════════════════════════════════════════ - // End of Krvava Žetev Asset Library (DISABLED) - // ═══════════════════════════════════════════════════════════════ + // 🔉 AUDIO ASSETS + this.load.audio('footstep_grass', 'assets/audio/footstep_grass.wav'); + this.load.audio('wood_chop', 'assets/audio/wood_chop.wav'); + this.load.audio('forest_ambient', 'assets/audio/forest_ambient.mp3'); + console.log('🔉 Audio assets queued for loading'); } createAnimations() { diff --git a/src/systems/SoundManager.js b/src/systems/SoundManager.js index c2261471a..b495b292a 100644 --- a/src/systems/SoundManager.js +++ b/src/systems/SoundManager.js @@ -14,6 +14,9 @@ class SoundManager { if (this.scene.sound.get(key)) { this.scene.sound.play(key, { volume: this.sfxVolume }); + } else if (key === 'chop' && this.scene.sound.get('wood_chop')) { + // Priority for real wood chop sound + this.scene.sound.play('wood_chop', { volume: this.sfxVolume }); } else { // Enhanced placeholder beeps if (key === 'chop') { @@ -32,6 +35,24 @@ class SoundManager { } } + playMusic(key, loop = true) { + if (this.isMuted) return; + + // Stop current music + if (this.currentMusic) { + this.currentMusic.stop(); + } + + if (this.scene.sound.get(key)) { + this.currentMusic = this.scene.sound.add(key, { volume: this.musicVolume, loop: loop }); + this.currentMusic.play(); + } + } + + playForestAmbient() { + this.playMusic('forest_ambient', true); + } + beepChop() { if (!this.scene.sound.context) return; const ctx = this.scene.sound.context; @@ -151,18 +172,29 @@ class SoundManager { } beepFootstep() { - if (!this.scene.sound.context) return; - const ctx = this.scene.sound.context; - const osc = ctx.createOscillator(); - const gain = ctx.createGain(); - osc.connect(gain); - gain.connect(ctx.destination); - osc.frequency.value = 120 + Math.random() * 20; - osc.type = 'sine'; - gain.gain.setValueAtTime(0.05, ctx.currentTime); - gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.03); - osc.start(); - osc.stop(ctx.currentTime + 0.03); + this.playFootstep('grass'); + } + + playFootstep(surface = 'grass') { + if (this.isMuted) return; + const key = `footstep_${surface}`; + if (this.scene.sound.get(key)) { + this.scene.sound.play(key, { volume: this.sfxVolume * 0.4 }); + } else { + // Fallback beep + if (!this.scene.sound.context) return; + const ctx = this.scene.sound.context; + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.connect(gain); + gain.connect(ctx.destination); + osc.frequency.value = 120 + Math.random() * 20; + osc.type = 'sine'; + gain.gain.setValueAtTime(0.05, ctx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.03); + osc.start(); + osc.stop(ctx.currentTime + 0.03); + } } beepDeath() { @@ -257,6 +289,38 @@ class SoundManager { }, 2000); } + setAmbientModulation(factor) { + // factor 0 to 1 (proximity to pond) + this.ambientModFactor = factor; + // Optionally adjust existing music pitch or filter + if (this.currentMusic && this.currentMusic.isPlaying) { + this.currentMusic.setRate(1.0 - (factor * 0.1)); // Slightly slow down + } + } + + startHighMusic() { + if (!this.scene.sound.context || this.highInterval) return; + + console.log('🌈 Starting High Ambient Music...'); + // Warped/Low scales for high effect + const scale = [65.41, 77.78, 87.31, 98.00, 116.54, 130.81]; + + this.highInterval = setInterval(() => { + if (this.isMuted) return; + if (Math.random() > 0.4) { + const freq = scale[Math.floor(Math.random() * scale.length)]; + this.playProceduralNote(freq, 4.0, 0.1, 'sawtooth'); // More buzzy/long + } + }, 3000); + } + + stopHighMusic() { + if (this.highInterval) { + clearInterval(this.highInterval); + this.highInterval = null; + } + } + stopMusic() { if (this.musicInterval) { clearInterval(this.musicInterval); @@ -264,7 +328,7 @@ class SoundManager { } } - playProceduralNote(freq) { + playProceduralNote(freq, duration = 2.0, volumeMod = 0.05, type = 'sine') { if (!this.scene.sound.context) return; const ctx = this.scene.sound.context; @@ -275,13 +339,12 @@ class SoundManager { gain.connect(ctx.destination); osc.frequency.value = freq; - osc.type = 'sine'; // Soft tone + osc.type = type; const now = ctx.currentTime; - const duration = 2.0; // Long decay like reverb/pad gain.gain.setValueAtTime(0, now); - gain.gain.linearRampToValueAtTime(0.05 * this.musicVolume, now + 0.5); // Slow attack + gain.gain.linearRampToValueAtTime(volumeMod * this.musicVolume, now + 0.5); // Slow attack gain.gain.exponentialRampToValueAtTime(0.001, now + duration); // Long release osc.start(now); @@ -294,7 +357,13 @@ class SoundManager { console.log(this.isMuted ? '🔇 Muted' : '🔊 Unmuted'); } - playChop() { this.playSFX('chop'); } + playChop() { + if (this.scene.sound.get('wood_chop')) { + this.scene.sound.play('wood_chop', { volume: this.sfxVolume }); + } else { + this.playSFX('chop'); + } + } playPlant() { this.playSFX('plant'); } playHarvest() { this.playSFX('harvest'); } playBuild() { this.playSFX('build'); } @@ -307,6 +376,77 @@ class SoundManager { playDeath() { this.beepDeath(); } playRainSound() { this.startRainNoise(); } stopRainSound() { this.stopRainNoise(); } + playHighAmbient() { this.startHighMusic(); } + stopHighAmbient() { this.stopHighMusic(); } + + playCraftSound() { + if (!this.scene.sound.context) return; + const ctx = this.scene.sound.context; + // Hammering rhythm + for (let i = 0; i < 3; i++) { + const time = ctx.currentTime + (i * 0.3); + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.connect(gain); + gain.connect(ctx.destination); + osc.frequency.setValueAtTime(200 - (i * 20), time); + osc.type = 'square'; + gain.gain.setValueAtTime(0.1, time); + gain.gain.exponentialRampToValueAtTime(0.01, time + 0.1); + osc.start(time); + osc.stop(time + 0.1); + } + } + + playSuccessSound() { + if (!this.scene.sound.context) return; + const ctx = this.scene.sound.context; + const notes = [523.25, 659.25, 783.99, 1046.50]; // C5, E5, G5, C6 + notes.forEach((freq, i) => { + const time = ctx.currentTime + (i * 0.1); + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.connect(gain); + gain.connect(ctx.destination); + osc.frequency.value = freq; + osc.type = 'sine'; + gain.gain.setValueAtTime(0, time); + gain.gain.linearRampToValueAtTime(0.1, time + 0.05); + gain.gain.exponentialRampToValueAtTime(0.001, time + 0.3); + osc.start(time); + osc.stop(time + 0.3); + }); + } + + playSmokeSound() { + if (!this.scene.sound.context) return; + const ctx = this.scene.sound.context; + + // Inhale (White noise sweep) + const bufferSize = ctx.sampleRate * 0.5; + const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate); + const data = buffer.getChannelData(0); + for (let i = 0; i < bufferSize; i++) data[i] = Math.random() * 2 - 1; + + const source = ctx.createBufferSource(); + source.buffer = buffer; + const filter = ctx.createBiquadFilter(); + const gain = ctx.createGain(); + + source.connect(filter); + filter.connect(gain); + gain.connect(ctx.destination); + + filter.type = 'lowpass'; + filter.frequency.setValueAtTime(100, ctx.currentTime); + filter.frequency.exponentialRampToValueAtTime(2000, ctx.currentTime + 0.5); + + gain.gain.setValueAtTime(0, ctx.currentTime); + gain.gain.linearRampToValueAtTime(0.1, ctx.currentTime + 0.1); + gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.5); + + source.start(); + } beepUIClick() { if (!this.scene.sound.context) return;