diff --git a/assets/scenarios/ceo_exfil.json b/assets/scenarios/ceo_exfil.json index 81ba64a..bf5be26 100644 --- a/assets/scenarios/ceo_exfil.json +++ b/assets/scenarios/ceo_exfil.json @@ -159,7 +159,7 @@ "locked": true, "lockType": "key", "requires": "ceo_office_key", - "difficulty": "hard", + "difficulty": "easy", "objects": [ { "type": "pc", diff --git a/index.html b/index.html index f25443f..7339822 100644 --- a/index.html +++ b/index.html @@ -3254,9 +3254,22 @@ border-radius: 5px; cursor: pointer; position: relative; - transition: transform 0.1s; + transition: transform 0.1s, background-color 0.3s; `; + // Add a subtle indicator at the bottom of each pin + const pinIndicator = document.createElement('div'); + pinIndicator.style.cssText = ` + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 5px; + background: #555; + transition: background-color 0.3s; + `; + pin.appendChild(pinIndicator); + const pinNumber = document.createElement('div'); pinNumber.style.cssText = ` position: absolute; @@ -3268,6 +3281,106 @@ pinNumber.textContent = (i + 1).toString(); pin.appendChild(pinNumber); + // Function to update pin appearance based on its state and binding status + function updatePinAppearance() { + // Reset to default first + pin.style.background = '#555'; + pinIndicator.style.background = '#555'; + + // If the pin is set, show it as green + if (gameState.pinStates[i] === 2) { + pin.style.background = '#0f0'; + pin.style.cursor = 'default'; + pinIndicator.style.background = '#0f0'; + return; + } + + // Get the current binding pin + const bindingPin = bindingOrder[gameState.currentBindingIndex]; + + // If this is the current binding pin, give a subtle hint based on difficulty + if (i === bindingPin) { + // For easy difficulty, make the binding pin more obvious + if (difficulty === 'easy') { + pinIndicator.style.background = '#ff9900'; // Orange indicator for binding pin + + // Also show the required tension level with a color hint + const requiredTension = gameState.tensionRequirements[i]; + if (requiredTension === 1) { + pin.style.borderColor = '#66ccff'; // Light blue for light tension + } else if (requiredTension === 2) { + pin.style.borderColor = '#9966ff'; // Purple for medium tension + } else { + pin.style.borderColor = '#ff6666'; // Red for heavy tension + } + } + // For medium difficulty, just show which pin is binding + else if (difficulty === 'medium') { + pinIndicator.style.background = '#ff9900'; // Orange indicator for binding pin + } + // For hard difficulty, no visual indicators + } + + // If we've set at least one pin, provide a subtle hint about the next binding pin + // but only for easy and medium difficulties + if (gameState.currentBindingIndex > 0 && !gameState.hardMode) { + // Make pins slightly "wiggle" based on how close they are to being the binding pin + const distanceFromBinding = Math.abs(i - bindingPin); + + if (distanceFromBinding === 0 && difficulty !== 'hard') { + // This is the binding pin, add a subtle animation + pin.style.animation = 'pinWiggle 2s infinite'; + } else if (distanceFromBinding <= 2 && difficulty === 'easy') { + // Close to binding pin, add a very subtle hint for easy difficulty + pin.style.animation = 'pinWiggle 4s infinite'; + } + } + } + + // Add the wiggle animation to the document + if (!document.getElementById('pinWiggleAnimation')) { + const style = document.createElement('style'); + style.id = 'pinWiggleAnimation'; + style.textContent = ` + @keyframes pinWiggle { + 0% { transform: translateY(0); } + 25% { transform: translateY(-2px); } + 50% { transform: translateY(0); } + 75% { transform: translateY(-1px); } + 100% { transform: translateY(0); } + } + `; + document.head.appendChild(style); + } + + // Update all pins whenever a pin state changes + function updateAllPins() { + Array.from(pinsContainer.children).forEach((pin, index) => { + // Find the indicator within this pin + const indicator = pin.querySelector('div:first-child'); + + // Update based on current game state + if (gameState.pinStates[index] === 2) { + pin.style.background = '#0f0'; + pin.style.cursor = 'default'; + if (indicator) indicator.style.background = '#0f0'; + } else { + pin.style.background = '#555'; + pin.style.cursor = 'pointer'; + if (indicator) indicator.style.background = '#555'; + + // Check if this is the binding pin + const bindingPin = bindingOrder[gameState.currentBindingIndex]; + if (index === bindingPin && !gameState.hardMode) { + if (indicator) indicator.style.background = '#ff9900'; + } + } + }); + } + + // Call updatePinAppearance initially and whenever the game state changes + updatePinAppearance(); + let pressStartTime = 0; let pressTimer = null; @@ -3322,16 +3435,20 @@ if (stillCorrectTension && !gameState.overTensioned) { gameState.pinStates[pinIndex] = 2; gameState.currentBindingIndex++; - gameState.lastPinSetTime = Date.now(); // Record when this pin was set + gameState.lastPinSetTime = Date.now(); if (!gameState.hardMode) { pin.style.background = '#0f0'; + pinIndicator.style.background = '#0f0'; } + // Update all pins to show new binding state + updateAllPins(); + checkWinCondition(); } } - }, 500); // Need to hold for 500ms to set + }, 500); } else if (gameState.tensionLevel > 0) { // Wrong tension but trying - give feedback if (!gameState.hardMode) { @@ -3363,21 +3480,11 @@ pin.style.transform = 'translateY(0)'; if (gameState.pinStates[i] !== 2) { pin.style.background = '#555'; + // Update appearance to show binding status + updatePinAppearance(); } }; - // Add this inside the pin creation loop, after setting up the original event handlers - // This adds logging to each pin's mousedown event - const originalPinOnMouseDown = pin.onmousedown; - pin.onmousedown = function() { - const pinIndex = Array.from(pinsContainer.children).indexOf(this); - const bindingPin = bindingOrder[gameState.currentBindingIndex]; - const requiredTension = gameState.tensionRequirements[pinIndex]; - - // Call the original handler - originalPinOnMouseDown.call(this); - }; - pinsContainer.appendChild(pin); }