diff --git a/web/assets/css/game.css b/web/assets/css/game.css index cb07ceb..cbec87f 100644 --- a/web/assets/css/game.css +++ b/web/assets/css/game.css @@ -192,6 +192,14 @@ main { background-position: center; } +.button-rotator { + background-color: #DADEEF; + background-image: url("../img/tiles/ButtonProfile.svg"), url("../img/tiles/Tuile.svg"); + background-size: 100% 100%; + background-repeat: no-repeat; + background-position: center; +} + .button-active { opacity: 0.7; } @@ -292,6 +300,10 @@ main { justify-content: center; } +.btn-mirror-locked { + cursor: default; +} + .mirror-img { width: 80%; height: 80%; diff --git a/web/assets/js/game.js b/web/assets/js/game.js index c6dd3c6..fc194a3 100644 --- a/web/assets/js/game.js +++ b/web/assets/js/game.js @@ -18,6 +18,7 @@ const legend = { button2: 14, captor: 15, cable: 16, + rotatorButton: 17, }; const laserColors = { @@ -91,6 +92,10 @@ const doorGroups = { "4,8": 2, }; +const rotatorButtons = { + "4,6": { mirrorX: 4, mirrorY: 6 }, +}; + let laserDirection = { dx: 0, dy: 0 }; let laserSegments = {}; let mirrorOrientations = {}; @@ -98,6 +103,8 @@ let glassPlacements = {}; let activatedButtons = {}; let openedDoors = {}; let isLevelFinished = false; +let activeRotatorButtons = {}; +let rotatorIntervals = {}; function getCurrentLevel() { return levels[currentLevelIndex]; @@ -180,6 +187,74 @@ function openDoorsFromButton(x, y) { } } +function getRotatorButtonConfig(x, y) { + return rotatorButtons[`${y},${x}`]; +} + +function isMirrorControlledByButton(x, y) { + const rotatorEntries = Object.values(rotatorButtons); + + for (let i = 0; i < rotatorEntries.length; i++) { + const rotatorConfig = rotatorEntries[i]; + + if (rotatorConfig.mirrorX === x && rotatorConfig.mirrorY === y) { + return true; + } + } + + return false; +} + +function rotateMirrorStep(x, y, angleStep) { + const coordKey = `${y},${x}`; + + if (getCurrentLevel()[y][x] !== legend.mirror) { + return; + } + + let currentAngle = mirrorOrientations[coordKey] || 0; + currentAngle = (currentAngle + angleStep) % 360; + + if (currentAngle < 0) { + currentAngle += 360; + } + + mirrorOrientations[coordKey] = currentAngle; +} + +function syncRotatorButtons() { + const rotatorKeys = Object.keys(rotatorButtons); + + for (let i = 0; i < rotatorKeys.length; i++) { + const key = rotatorKeys[i]; + const config = rotatorButtons[key]; + const isActive = activeRotatorButtons[key] === true; + + if (isActive && !rotatorIntervals[key]) { + rotatorIntervals[key] = window.setInterval(() => { + rotateMirrorStep(config.mirrorX, config.mirrorY, -22.5); + traceLaser(); + }, 1000); + } + + if (!isActive && rotatorIntervals[key]) { + window.clearInterval(rotatorIntervals[key]); + delete rotatorIntervals[key]; + } + } +} + +function stopAllRotatorButtons() { + const intervalKeys = Object.keys(rotatorIntervals); + + for (let i = 0; i < intervalKeys.length; i++) { + const key = intervalKeys[i]; + window.clearInterval(rotatorIntervals[key]); + } + + rotatorIntervals = {}; +} + function saveLaserSegment(x, y, direction, color) { laserSegments[`${y},${x}`] = { direction: { ...direction }, @@ -345,23 +420,31 @@ function loadGrid() { case legend.mirror: cell.classList.add("mirror"); const currentAngle = mirrorOrientations[`${y},${x}`] || 0; - const btnMirror = document.createElement("button"); - btnMirror.classList.add("btn-mirror"); - btnMirror.type = "button"; const img = document.createElement("img"); img.src = "../../assets/img/tiles/Mirror.svg"; img.classList.add("mirror-img"); img.style.transform = `rotate(${currentAngle}deg)`; - btnMirror.appendChild(img); - btnMirror.onmousedown = (event) => { - event.preventDefault(); - event.stopPropagation(); - if (!isLevelFinished) { - rotateMirror(x, y, event.button === 2); - } - }; - btnMirror.oncontextmenu = (event) => event.preventDefault(); - cell.appendChild(btnMirror); + + if (isMirrorControlledByButton(x, y)) { + const mirrorDisplay = document.createElement("div"); + mirrorDisplay.classList.add("btn-mirror", "btn-mirror-locked"); + mirrorDisplay.appendChild(img); + cell.appendChild(mirrorDisplay); + } else { + const btnMirror = document.createElement("button"); + btnMirror.classList.add("btn-mirror"); + btnMirror.type = "button"; + btnMirror.appendChild(img); + btnMirror.onmousedown = (event) => { + event.preventDefault(); + event.stopPropagation(); + if (!isLevelFinished) { + rotateMirror(x, y, event.button === 2); + } + }; + btnMirror.oncontextmenu = (event) => event.preventDefault(); + cell.appendChild(btnMirror); + } break; case legend.door: cell.classList.add("door"); @@ -384,6 +467,12 @@ function loadGrid() { cell.classList.add("button-active"); } break; + case legend.rotatorButton: + cell.classList.add("button", "button-rotator"); + if (activatedButtons[`${y},${x}`]) { + cell.classList.add("button-active"); + } + break; case legend.wall: cell.classList.add("wall"); break; @@ -420,20 +509,7 @@ function loadGrid() { } function rotateMirror(x, y, isRightClick) { - const coordKey = `${y},${x}`; - - if (getCurrentLevel()[y][x] !== legend.mirror) { - return; - } - - let currentAngle = mirrorOrientations[coordKey] || 0; - currentAngle = (currentAngle + (isRightClick ? 22.5 : -22.5)) % 360; - - if (currentAngle < 0) { - currentAngle += 360; - } - - mirrorOrientations[coordKey] = currentAngle; + rotateMirrorStep(x, y, isRightClick ? 22.5 : -22.5); traceLaser(); } @@ -441,6 +517,7 @@ function traceLaser() { laserSegments = {}; activatedButtons = {}; openedDoors = {}; + activeRotatorButtons = {}; isLevelFinished = false; const level = getCurrentLevel(); @@ -553,6 +630,21 @@ function traceLaser() { } break; + case legend.rotatorButton: + if (currentLaserColor === laserColors.red) { + const rotatorKey = `${currentY},${currentX}`; + activatedButtons[rotatorKey] = true; + activeRotatorButtons[rotatorKey] = true; + saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor); + } else if (currentLaserColor === laserColors.yellow) { + saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor); + } else if (currentLaserColor === laserColors.blue) { + laserDirection = reverseLaser(laserDirection); + } else { + laserActive = false; + } + break; + case legend.demiWallCornerUpLeft: laserDirection = reflectLaser(laserDirection, 135); break; @@ -575,6 +667,7 @@ function traceLaser() { } } + syncRotatorButtons(); loadGrid(); if (isLevelFinished) { @@ -593,6 +686,7 @@ function nextLevel() { currentLevelIndex++; isLevelFinished = false; + stopAllRotatorButtons(); if (currentLevelIndex >= levels.length) { currentLevelIndex = 0;