Support limited glass inventory and yellow laser
Introduce per-level glass inventory and UI for draggable glass pieces, including disabled state and count labels. glassOptions now hold objects with color, maxAmount and currentAmount; palette creation uses these values to enable/disable dragging, show remaining counts, and update on place/remove. Drag-and-drop logic now tracks a draggedGlassColor fallback, prevents placing when inventory is empty, decrements/increments inventory on place/remove, and rebuilds the palette. Reset inventory on level start and when advancing levels. Also adjust laser tracing: yellow lasers are saved as segments and terminate on target, and yellow interacts with demi-wall corners by saving the segment instead of reflecting (blue still reflects). Add CSS for .glass-item:disabled and .glass-item-label. Overall fixes inventory handling and yellow-laser behavior.
This commit is contained in:
@@ -341,6 +341,24 @@ main {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.glass-item:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-item-label {
|
||||||
|
position: absolute;
|
||||||
|
right: 4px;
|
||||||
|
bottom: 3px;
|
||||||
|
z-index: 2;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #223;
|
||||||
|
background: rgba(255, 255, 255, 0.88);
|
||||||
|
padding: 1px 5px;
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
.glass-item::after,
|
.glass-item::after,
|
||||||
.cell-glass::after {
|
.cell-glass::after {
|
||||||
content: "";
|
content: "";
|
||||||
|
|||||||
@@ -31,9 +31,21 @@ const laserColors = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const glassOptions = [
|
const glassOptions = [
|
||||||
laserColors.red,
|
[
|
||||||
laserColors.blue,
|
{ color: laserColors.red, maxAmount: 1, currentAmount: 1 },
|
||||||
laserColors.yellow,
|
{ color: laserColors.blue, maxAmount: 1, currentAmount: 1 },
|
||||||
|
{ color: laserColors.yellow, maxAmount: 1, currentAmount: 1 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ color: laserColors.red, maxAmount: 1, currentAmount: 1 },
|
||||||
|
{ color: laserColors.blue, maxAmount: 1, currentAmount: 1 },
|
||||||
|
{ color: laserColors.yellow, maxAmount: 1, currentAmount: 1 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ color: laserColors.red, maxAmount: 2, currentAmount: 2 },
|
||||||
|
{ color: laserColors.blue, maxAmount: 1, currentAmount: 1 },
|
||||||
|
{ color: laserColors.yellow, maxAmount: 2, currentAmount: 2 },
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
let levels = [
|
let levels = [
|
||||||
@@ -149,6 +161,7 @@ let activeRotatorButtons = {};
|
|||||||
let rotatorIntervals = {};
|
let rotatorIntervals = {};
|
||||||
let toggledDoors = {};
|
let toggledDoors = {};
|
||||||
let poweredCaptors = {};
|
let poweredCaptors = {};
|
||||||
|
let draggedGlassColor = null;
|
||||||
|
|
||||||
function getCurrentLevel() {
|
function getCurrentLevel() {
|
||||||
return levels[currentLevelIndex];
|
return levels[currentLevelIndex];
|
||||||
@@ -158,6 +171,30 @@ function getCurrentLevelConfig(configByLevel) {
|
|||||||
return configByLevel[currentLevelIndex] || {};
|
return configByLevel[currentLevelIndex] || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurrentGlassOptions() {
|
||||||
|
return glassOptions[currentLevelIndex] || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGlassOptionByColor(color) {
|
||||||
|
const currentGlassOptions = getCurrentGlassOptions();
|
||||||
|
|
||||||
|
for (let i = 0; i < currentGlassOptions.length; i++) {
|
||||||
|
if (currentGlassOptions[i].color === color) {
|
||||||
|
return currentGlassOptions[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetGlassInventory() {
|
||||||
|
const currentGlassOptions = getCurrentGlassOptions();
|
||||||
|
|
||||||
|
for (let i = 0; i < currentGlassOptions.length; i++) {
|
||||||
|
currentGlassOptions[i].currentAmount = currentGlassOptions[i].maxAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeLaserDirection(dx, dy) {
|
function normalizeLaserDirection(dx, dy) {
|
||||||
const epsilon = 0.0001;
|
const epsilon = 0.0001;
|
||||||
const normalizedDx = Math.abs(dx) < epsilon ? 0 : Math.sign(dx);
|
const normalizedDx = Math.abs(dx) < epsilon ? 0 : Math.sign(dx);
|
||||||
@@ -367,17 +404,40 @@ function createPalette() {
|
|||||||
|
|
||||||
palette.innerHTML = "";
|
palette.innerHTML = "";
|
||||||
|
|
||||||
for (let i = 0; i < glassOptions.length; i++) {
|
const currentGlassOptions = getCurrentGlassOptions();
|
||||||
const glassColor = glassOptions[i];
|
|
||||||
|
for (let i = 0; i < currentGlassOptions.length; i++) {
|
||||||
|
const glassOption = currentGlassOptions[i];
|
||||||
|
const glassColor = glassOption.color;
|
||||||
const glassButton = document.createElement("button");
|
const glassButton = document.createElement("button");
|
||||||
glassButton.type = "button";
|
glassButton.type = "button";
|
||||||
glassButton.classList.add("glass-item", `glass-${glassColor}`);
|
glassButton.classList.add("glass-item", `glass-${glassColor}`);
|
||||||
glassButton.draggable = true;
|
glassButton.draggable = glassOption.currentAmount > 0;
|
||||||
|
|
||||||
|
if (glassOption.currentAmount <= 0) {
|
||||||
|
glassButton.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const glassLabel = document.createElement("span");
|
||||||
|
glassLabel.classList.add("glass-item-label");
|
||||||
|
glassLabel.textContent = `${glassOption.currentAmount}/${glassOption.maxAmount}`;
|
||||||
|
glassButton.appendChild(glassLabel);
|
||||||
|
|
||||||
glassButton.addEventListener("dragstart", (event) => {
|
glassButton.addEventListener("dragstart", (event) => {
|
||||||
|
if (glassOption.currentAmount <= 0) {
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
draggedGlassColor = glassColor;
|
||||||
event.dataTransfer.effectAllowed = "copy";
|
event.dataTransfer.effectAllowed = "copy";
|
||||||
event.dataTransfer.setData("application/x-glass-color", glassColor);
|
event.dataTransfer.setData("application/x-glass-color", glassColor);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
glassButton.addEventListener("dragend", () => {
|
||||||
|
draggedGlassColor = null;
|
||||||
|
});
|
||||||
|
|
||||||
palette.appendChild(glassButton);
|
palette.appendChild(glassButton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,7 +448,8 @@ function addDropEvents(cell, x, y) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!event.dataTransfer.types.includes("application/x-glass-color")) {
|
const transferTypes = event.dataTransfer ? Array.from(event.dataTransfer.types || []) : [];
|
||||||
|
if (!draggedGlassColor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,6 +458,13 @@ function addDropEvents(cell, x, y) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectedColor = draggedGlassColor;
|
||||||
|
const glassOption = getGlassOptionByColor(selectedColor);
|
||||||
|
|
||||||
|
if (!glassOption || glassOption.currentAmount <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
cell.classList.add("can-drop");
|
cell.classList.add("can-drop");
|
||||||
});
|
});
|
||||||
@@ -410,7 +478,8 @@ function addDropEvents(cell, x, y) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedColor = event.dataTransfer.getData("application/x-glass-color");
|
const transferredColor = event.dataTransfer ? event.dataTransfer.getData("application/x-glass-color") : "";
|
||||||
|
const selectedColor = transferredColor || draggedGlassColor;
|
||||||
cell.classList.remove("can-drop");
|
cell.classList.remove("can-drop");
|
||||||
|
|
||||||
if (!selectedColor) {
|
if (!selectedColor) {
|
||||||
@@ -421,8 +490,21 @@ function addDropEvents(cell, x, y) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isGlassOnCell(x, y)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const glassOption = getGlassOptionByColor(selectedColor);
|
||||||
|
|
||||||
|
if (!glassOption || glassOption.currentAmount <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
glassPlacements[`${y},${x}`] = selectedColor;
|
glassPlacements[`${y},${x}`] = selectedColor;
|
||||||
|
glassOption.currentAmount--;
|
||||||
|
draggedGlassColor = null;
|
||||||
|
createPalette();
|
||||||
traceLaser();
|
traceLaser();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -432,7 +514,16 @@ function addDropEvents(cell, x, y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isGlassOnCell(x, y)) {
|
if (isGlassOnCell(x, y)) {
|
||||||
|
const glassColor = glassPlacements[`${y},${x}`];
|
||||||
|
const glassOption = getGlassOptionByColor(glassColor);
|
||||||
|
|
||||||
delete glassPlacements[`${y},${x}`];
|
delete glassPlacements[`${y},${x}`];
|
||||||
|
|
||||||
|
if (glassOption) {
|
||||||
|
glassOption.currentAmount = Math.min(glassOption.currentAmount + 1, glassOption.maxAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
createPalette();
|
||||||
traceLaser();
|
traceLaser();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -642,6 +733,17 @@ function traceLaser() {
|
|||||||
currentLaserColor = glassColor;
|
currentLaserColor = glassColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentLaserColor === laserColors.yellow) {
|
||||||
|
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
|
||||||
|
|
||||||
|
if (cellType === legend.target) {
|
||||||
|
laserActive = false;
|
||||||
|
isLevelFinished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
switch (cellType) {
|
switch (cellType) {
|
||||||
case legend.laser:
|
case legend.laser:
|
||||||
case legend.coloredLaser:
|
case legend.coloredLaser:
|
||||||
@@ -743,25 +845,33 @@ function traceLaser() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case legend.demiWallCornerUpLeft:
|
case legend.demiWallCornerUpLeft:
|
||||||
if(currentLaserColor === laserColors.blue) {
|
if (currentLaserColor === laserColors.yellow) {
|
||||||
|
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
|
||||||
|
} else if (currentLaserColor === laserColors.blue) {
|
||||||
laserDirection = reflectLaser(laserDirection, 135);
|
laserDirection = reflectLaser(laserDirection, 135);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case legend.demiWallCornerUpRight:
|
case legend.demiWallCornerUpRight:
|
||||||
if(currentLaserColor === laserColors.blue) {
|
if (currentLaserColor === laserColors.yellow) {
|
||||||
|
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
|
||||||
|
} else if (currentLaserColor === laserColors.blue) {
|
||||||
laserDirection = reflectLaser(laserDirection, 45);
|
laserDirection = reflectLaser(laserDirection, 45);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case legend.demiWallCornerDownLeft:
|
case legend.demiWallCornerDownLeft:
|
||||||
if(currentLaserColor === laserColors.blue) {
|
if (currentLaserColor === laserColors.yellow) {
|
||||||
|
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
|
||||||
|
} else if (currentLaserColor === laserColors.blue) {
|
||||||
laserDirection = reflectLaser(laserDirection, 225);
|
laserDirection = reflectLaser(laserDirection, 225);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case legend.demiWallCornerDownRight:
|
case legend.demiWallCornerDownRight:
|
||||||
if(currentLaserColor === laserColors.blue) {
|
if (currentLaserColor === laserColors.yellow) {
|
||||||
|
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
|
||||||
|
} else if (currentLaserColor === laserColors.blue) {
|
||||||
laserDirection = reflectLaser(laserDirection, 315);
|
laserDirection = reflectLaser(laserDirection, 315);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -799,10 +909,12 @@ function nextLevel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initializeMirrorOrientations();
|
initializeMirrorOrientations();
|
||||||
|
glassPlacements = {};
|
||||||
|
resetGlassInventory();
|
||||||
|
createPalette();
|
||||||
loadGrid();
|
loadGrid();
|
||||||
laserSegments = {};
|
laserSegments = {};
|
||||||
mirrorOrientations = {};
|
mirrorOrientations = {};
|
||||||
glassPlacements = {};
|
|
||||||
activatedButtons = {};
|
activatedButtons = {};
|
||||||
openedDoors = {};
|
openedDoors = {};
|
||||||
toggledDoors = {};
|
toggledDoors = {};
|
||||||
@@ -813,6 +925,7 @@ function nextLevel() {
|
|||||||
winOverlay.style.visibility = "hidden";
|
winOverlay.style.visibility = "hidden";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetGlassInventory();
|
||||||
createPalette();
|
createPalette();
|
||||||
initializeMirrorOrientations();
|
initializeMirrorOrientations();
|
||||||
blockBrowserDrop();
|
blockBrowserDrop();
|
||||||
|
|||||||
Reference in New Issue
Block a user