diff --git a/assets/sounds/lockpick_binding.mp3 b/assets/sounds/lockpick_binding.mp3 new file mode 100644 index 0000000..653dcd7 Binary files /dev/null and b/assets/sounds/lockpick_binding.mp3 differ diff --git a/assets/sounds/lockpick_click.mp3 b/assets/sounds/lockpick_click.mp3 new file mode 100644 index 0000000..0c68c37 Binary files /dev/null and b/assets/sounds/lockpick_click.mp3 differ diff --git a/assets/sounds/lockpick_overtension.mp3 b/assets/sounds/lockpick_overtension.mp3 new file mode 100644 index 0000000..dc26a85 Binary files /dev/null and b/assets/sounds/lockpick_overtension.mp3 differ diff --git a/assets/sounds/lockpick_reset.mp3 b/assets/sounds/lockpick_reset.mp3 new file mode 100644 index 0000000..7a031ab Binary files /dev/null and b/assets/sounds/lockpick_reset.mp3 differ diff --git a/assets/sounds/lockpick_set.mp3 b/assets/sounds/lockpick_set.mp3 new file mode 100644 index 0000000..59715f8 Binary files /dev/null and b/assets/sounds/lockpick_set.mp3 differ diff --git a/assets/sounds/lockpick_success.mp3 b/assets/sounds/lockpick_success.mp3 new file mode 100644 index 0000000..6b467c1 Binary files /dev/null and b/assets/sounds/lockpick_success.mp3 differ diff --git a/assets/sounds/lockpick_tension.mp3 b/assets/sounds/lockpick_tension.mp3 new file mode 100644 index 0000000..a5bef96 Binary files /dev/null and b/assets/sounds/lockpick_tension.mp3 differ diff --git a/assets/sounds/lockpick_wrong.mp3 b/assets/sounds/lockpick_wrong.mp3 new file mode 100644 index 0000000..9b378c8 Binary files /dev/null and b/assets/sounds/lockpick_wrong.mp3 differ diff --git a/index.html b/index.html index ee08393..1e69794 100644 --- a/index.html +++ b/index.html @@ -3096,10 +3096,42 @@ }); // Add audio feedback - let clickSound = null; + const lockSounds = { + click: null, // Basic pin movement sound + binding: null, // Sound when a pin is binding (correct tension) + set: null, // Sound when a pin is successfully set + reset: null, // Sound when pins are reset + wrong: null, // Sound when wrong tension or wrong pin + tension: null, // Sound when changing tension + success: null, // Sound when successfully picking the lock + overTension: null // Sound when over-tensioning the lock + }; + const initAudio = () => { - if (!clickSound) { - clickSound = new Audio('data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoGAACBhYqFbF1fdH2Dam9ycG5wdX2Dg4CBhIWCgX+Af4B/goCDgIJ/gn+BfoF/gn+CgIF/gn+Cf4F/g4CDgIJ/hIGFgoWBhYKGgoaCh4OIg4mEioWLhIyFjYaOhI+FkIaRhZKGk4eUhpWHloeXiJiImYiaiZuKnIqdi56LoIyhjaKOo4+kj6WQppGnkqiTqZSqlauWrJetmK6Zr5qwm7GcsZ2yn7OgtKG1oraitqO3pLiltqe4qLmpuqq7q7ysvq2/rsCwwbHCssOzxbTGtce2yLfJuMq5y7rMu827zrzPvdC+0b/SwdPC1MPVxNbF18bYx9nI2sjbydvK3Mvdy97M383gzuHP4tDj0eTT5dTm1efW6Nfp2Ora69vt3O7d797w3/Lh8+P05fXn9+j46Prs+/D89v77AQYHDA8VGh8lKi8zOD1CRkpPVFhbX2NobHBydHZ4enx+gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vPz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=='); + if (!lockSounds.click) { + // Basic click sound (when pressing a pin) + lockSounds.click = new Audio('assets/sounds/lockpick_click.mp3'); + + // Binding sound (when a pin is binding with correct tension) + lockSounds.binding = new Audio('assets/sounds/lockpick_binding.mp3'); + + // Set sound (when a pin is successfully set) + lockSounds.set = new Audio('assets/sounds/lockpick_set.mp3'); + + // Reset sound (when pins are reset) + lockSounds.reset = new Audio('assets/sounds/lockpick_reset.mp3'); + + // Wrong sound (when using wrong tension or pressing wrong pin) + lockSounds.wrong = new Audio('assets/sounds/lockpick_wrong.mp3'); + + // Tension sound (when changing tension levels) + lockSounds.tension = new Audio('assets/sounds/lockpick_tension.mp3'); + + // Success sound (when successfully picking the lock) + lockSounds.success = new Audio('assets/sounds/lockpick_success.mp3'); + + // Over-tension sound (when applying too much tension) + lockSounds.overTension = new Audio('assets/sounds/lockpick_overtension.mp3'); } }; @@ -3185,6 +3217,12 @@ const previousTensionLevel = gameState.tensionLevel; gameState.tensionLevel = (gameState.tensionLevel % 3) + 1; + // Play tension change sound + if (lockSounds.tension) { + lockSounds.tension.currentTime = 0; + lockSounds.tension.play().catch(e => console.log('Audio play failed:', e)); + } + updateTensionWrench(); // Check if we're over-tensioning - but only if we've started interacting with pins @@ -3203,6 +3241,12 @@ tensionWrench.style.background = '#ff3333'; tensionWrench.style.transform = 'rotate(15deg)'; + // Play over-tension sound + if (lockSounds.overTension) { + lockSounds.overTension.currentTime = 0; + lockSounds.overTension.play().catch(e => console.log('Audio play failed:', e)); + } + setTimeout(() => { alert("You applied too much tension and jammed the lock!"); resetPins(); @@ -3501,6 +3545,12 @@ // Set the flag to indicate we're actively picking a pin gameState.isActivelyPickingPin = true; + // Play basic click sound + if (lockSounds.click) { + lockSounds.click.currentTime = 0; + lockSounds.click.play().catch(e => console.log('Audio play failed:', e)); + } + pressStartTime = Date.now(); pressTimer = setInterval(checkPinPress, 100); @@ -3516,6 +3566,12 @@ const correctTension = (gameState.tensionLevel === requiredTension); if (correctTension && !gameState.overTensioned) { + // Play binding sound - correct pin with correct tension + if (lockSounds.binding) { + lockSounds.binding.currentTime = 0; + lockSounds.binding.play().catch(e => console.log('Audio play failed:', e)); + } + if (!gameState.hardMode) { pin.style.background = '#00f'; } @@ -3531,6 +3587,12 @@ gameState.currentBindingIndex++; gameState.lastPinSetTime = Date.now(); + // Play set sound - pin successfully set + if (lockSounds.set) { + lockSounds.set.currentTime = 0; + lockSounds.set.play().catch(e => console.log('Audio play failed:', e)); + } + if (!gameState.hardMode) { pin.style.background = '#0f0'; pinIndicator.style.background = '#0f0'; @@ -3545,6 +3607,12 @@ }, 500); } else if (gameState.tensionLevel > 0) { // Wrong tension but trying - give feedback + // Play wrong sound - wrong tension on correct pin + if (lockSounds.wrong) { + lockSounds.wrong.currentTime = 0; + lockSounds.wrong.play().catch(e => console.log('Audio play failed:', e)); + } + if (!gameState.hardMode) { pin.style.background = '#00f'; } @@ -3553,6 +3621,12 @@ gameState.pinPressTime[pinIndex] = Date.now(); } } else if (gameState.tensionLevel > 0 && gameState.pinStates[pinIndex] !== 2) { + // Wrong pin - give feedback + if (lockSounds.wrong) { + lockSounds.wrong.currentTime = 0; + lockSounds.wrong.play().catch(e => console.log('Audio play failed:', e)); + } + if (!gameState.hardMode) { pin.style.background = '#00f'; } @@ -3628,31 +3702,54 @@ // Add this function before the pin creation loop function checkWinCondition() { if (gameState.currentBindingIndex >= numPins) { + // Play success sound + if (lockSounds.success) { + lockSounds.success.currentTime = 0; + lockSounds.success.play().catch(e => console.log('Audio play failed:', e)); + } + console.log('Lock picked successfully:', lockable); - // For doors, we need to check properties and handle differently - if (lockable && lockable.properties && lockable.properties.locked) { - console.log('Unlocking door tile:', lockable); - unlockDoor(lockable, lockable.layer); - alert("Lock successfully picked! The door is now unlocked."); - } - // For containers and other lockable items - else if (lockable.scenarioData) { - console.log('Unlocking container:', lockable.scenarioData); - lockable.scenarioData.locked = false; - - if (lockable.scenarioData.contents) { - lockable.scenarioData.isUnlockedButNotCollected = true; - alert("Lock successfully picked! You can now interact with it to collect the contents."); - } else { - alert("Lock successfully picked!"); - } - } + // Create success message + const successMessage = document.createElement('div'); + successMessage.style.cssText = ` + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: rgba(0, 0, 0, 0.8); + color: #0f0; + padding: 20px; + border-radius: 10px; + font-size: 24px; + text-align: center; + z-index: 1002; + `; + successMessage.textContent = "Lock successfully picked!"; + iframe.appendChild(successMessage); + + // Disable further interaction + gameContainer.style.pointerEvents = 'none'; + + setTimeout(() => { + // For doors, we need to check properties and handle differently + if (lockable && lockable.properties && lockable.properties.locked) { + console.log('Unlocking door tile:', lockable); + unlockDoor(lockable, lockable.layer); + } + // For containers and other lockable items + else if (lockable && lockable.scenarioData) { + console.log('Unlocking container:', lockable.scenarioData); + lockable.scenarioData.locked = false; + } + + // Remove the minigame + document.body.removeChild(iframe); + if (currentScene && currentScene.input && currentScene.input.mouse) { + currentScene.input.mouse.enabled = true; + } + }, 1500); - document.body.removeChild(iframe); - if (currentScene && currentScene.input && currentScene.input.mouse) { - currentScene.input.mouse.enabled = true; - } return true; } return false;