|
|
|
|
@@ -20,6 +20,7 @@ const legend = {
|
|
|
|
|
cable: 16,
|
|
|
|
|
captorTurn: 17,
|
|
|
|
|
cableVertical: 18,
|
|
|
|
|
rotatorButton: 20,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const laserColors = {
|
|
|
|
|
@@ -107,6 +108,9 @@ const doorGroups = {
|
|
|
|
|
"4,8": 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const rotatorButtons = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let laserDirection = { dx: 0, dy: 0 };
|
|
|
|
|
let laserSegments = {};
|
|
|
|
|
let mirrorOrientations = {};
|
|
|
|
|
@@ -114,6 +118,8 @@ let glassPlacements = {};
|
|
|
|
|
let activatedButtons = {};
|
|
|
|
|
let openedDoors = {};
|
|
|
|
|
let isLevelFinished = false;
|
|
|
|
|
let activeRotatorButtons = {};
|
|
|
|
|
let rotatorIntervals = {};
|
|
|
|
|
|
|
|
|
|
function getCurrentLevel() {
|
|
|
|
|
return levels[currentLevelIndex];
|
|
|
|
|
@@ -196,6 +202,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 },
|
|
|
|
|
@@ -361,13 +435,20 @@ 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)`;
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
@@ -378,6 +459,7 @@ function loadGrid() {
|
|
|
|
|
};
|
|
|
|
|
btnMirror.oncontextmenu = (event) => event.preventDefault();
|
|
|
|
|
cell.appendChild(btnMirror);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case legend.door:
|
|
|
|
|
cell.classList.add("door");
|
|
|
|
|
@@ -400,6 +482,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;
|
|
|
|
|
@@ -442,20 +530,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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -463,6 +538,7 @@ function traceLaser() {
|
|
|
|
|
laserSegments = {};
|
|
|
|
|
activatedButtons = {};
|
|
|
|
|
openedDoors = {};
|
|
|
|
|
activeRotatorButtons = {};
|
|
|
|
|
isLevelFinished = false;
|
|
|
|
|
|
|
|
|
|
const level = getCurrentLevel();
|
|
|
|
|
@@ -575,6 +651,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;
|
|
|
|
|
@@ -597,6 +688,7 @@ function traceLaser() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
syncRotatorButtons();
|
|
|
|
|
loadGrid();
|
|
|
|
|
|
|
|
|
|
if (isLevelFinished) {
|
|
|
|
|
@@ -615,6 +707,7 @@ function nextLevel() {
|
|
|
|
|
currentLevelIndex++;
|
|
|
|
|
|
|
|
|
|
isLevelFinished = false;
|
|
|
|
|
stopAllRotatorButtons();
|
|
|
|
|
|
|
|
|
|
if (currentLevelIndex >= levels.length) {
|
|
|
|
|
currentLevelIndex = 0;
|
|
|
|
|
|