forked from Simnation/Main
330 lines
10 KiB
JavaScript
330 lines
10 KiB
JavaScript
const HEX_VALUES = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
|
|
const NUM_ROWS = 9;
|
|
const NUM_COLS = 18;
|
|
const PENALTY = 5000;
|
|
|
|
let solutions = ["", ""];
|
|
let solutionPos = [
|
|
[1, 1],
|
|
[1, 1],
|
|
];
|
|
let userSolPos = [
|
|
[1, 1],
|
|
[1, 15],
|
|
];
|
|
let gameStarted = false;
|
|
let solved = [false, false];
|
|
let endTime = 0;
|
|
let thread;
|
|
let mistakes = 0;
|
|
let lastBeep = 0;
|
|
let lastUpdateTime = 0;
|
|
let lastBeepTime = 0;
|
|
let gameTable = Array.from({ length: NUM_ROWS }, () => []);
|
|
let lastReseed = Array.from({ length: NUM_ROWS }, () => []);
|
|
|
|
const game = document.getElementById("game");
|
|
const hackingContainer = document.querySelector(".hacking-container");
|
|
const infobox = document.getElementById("infobox");
|
|
const screentext = document.getElementById("screentext");
|
|
const screen = document.getElementById("screen");
|
|
|
|
const resetGameState = () => {
|
|
hackingContainer.style.display = "none";
|
|
if (thread) {
|
|
cancelAnimationFrame(thread);
|
|
thread = null;
|
|
}
|
|
solutions = ["", ""];
|
|
solutionPos = [
|
|
[1, 1],
|
|
[1, 1],
|
|
];
|
|
userSolPos = [
|
|
[1, 1],
|
|
[1, 15],
|
|
];
|
|
solved = [false, false];
|
|
gameStarted = false;
|
|
mistakes = 0;
|
|
document.querySelectorAll(".sol2").forEach((el) => el.classList.remove("sol2"));
|
|
};
|
|
|
|
const getRandomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
|
|
|
|
const wrongSolution = () => {
|
|
mistakes++;
|
|
endTime -= mistakes * PENALTY;
|
|
};
|
|
|
|
const playSound = (snd, vol) => {
|
|
document.getElementById(snd).load();
|
|
document.getElementById(snd).volume = vol;
|
|
document.getElementById(snd).play();
|
|
};
|
|
|
|
const tryFinish = () => {
|
|
if (solved.every((val) => val)) {
|
|
document.getElementById("infobox").textContent = "Success";
|
|
setTimeout(() => {
|
|
playSound("audiofinish", 1);
|
|
fetch(`https://${GetParentResourceName()}/hackSuccess`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({}),
|
|
});
|
|
resetGameState();
|
|
}, 2000);
|
|
}
|
|
};
|
|
|
|
const writeSolution = () => {
|
|
for (let i = 0; i < solutions[0].length; i++) {
|
|
const cell1 = document.getElementById(`${solutionPos[0][0]}${solutionPos[0][1] + i}`);
|
|
if (cell1) {
|
|
cell1.textContent = solutions[0].charAt(i);
|
|
}
|
|
|
|
const cell2 = document.getElementById(`${solutionPos[1][0]}${solutionPos[1][1] + i}`);
|
|
if (cell2) {
|
|
cell2.textContent = solutions[1].charAt(i);
|
|
}
|
|
}
|
|
};
|
|
|
|
const writeUserSolution = () => {
|
|
document.querySelectorAll(".sol").forEach((el) => el.classList.remove("sol"));
|
|
for (let i = 0; i < solutions[0].length; i++) {
|
|
const el1 = document.getElementById(`${userSolPos[0][0]}${userSolPos[0][1] + i}`);
|
|
if (el1) {
|
|
el1.textContent = solutions[0].charAt(i);
|
|
el1.classList.add("sol");
|
|
}
|
|
|
|
const el2 = document.getElementById(`${userSolPos[1][0]}${userSolPos[1][1] + i}`);
|
|
if (el2) {
|
|
el2.textContent = solutions[1].charAt(i);
|
|
el2.classList.add("sol");
|
|
}
|
|
}
|
|
};
|
|
|
|
const writeTime = () => {
|
|
if (!solved.every((val) => val)) {
|
|
document.getElementById("infobox").textContent = `${((endTime - new Date().getTime()) / 1000.0).toFixed(2)}s`;
|
|
}
|
|
};
|
|
|
|
const seedTable = (timestamp) => {
|
|
now = new Date().getTime();
|
|
if (now >= endTime) {
|
|
infobox.textContent = "Failure";
|
|
setTimeout(() => {
|
|
playSound("audiofail", 1);
|
|
fetch(`https://${GetParentResourceName()}/hackFail`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({}),
|
|
});
|
|
resetGameState();
|
|
}, 2000);
|
|
return;
|
|
}
|
|
|
|
writeTime();
|
|
|
|
if (timestamp - lastUpdateTime > 200) {
|
|
for (let i = 0; i < NUM_ROWS; i++) {
|
|
for (let j = 0; j < NUM_COLS; j++) {
|
|
const cellId = `${i + 1}${j + 1}`;
|
|
const cell = document.getElementById(cellId);
|
|
if (cell) {
|
|
gameTable[i][j] = HEX_VALUES[getRandomInt(0, 15)];
|
|
cell.textContent = gameTable[i][j];
|
|
}
|
|
}
|
|
}
|
|
writeSolution();
|
|
writeUserSolution();
|
|
lastUpdateTime = timestamp;
|
|
}
|
|
|
|
if (timestamp - lastBeepTime > 600) {
|
|
playSound("audiobeep", 0.08);
|
|
lastBeepTime = timestamp;
|
|
}
|
|
|
|
thread = requestAnimationFrame(seedTable);
|
|
};
|
|
|
|
const generateSolutions = (s) => {
|
|
solutionPos[0] = [getRandomInt(1, 9), getRandomInt(1, 18 - s)];
|
|
let goodsolution = false;
|
|
while (!goodsolution) {
|
|
solutionPos[1] = [getRandomInt(1, 9), getRandomInt(1, 18 - s)];
|
|
if (solutionPos[0][0] == solutionPos[1][0]) {
|
|
if (solutionPos[0][1] + s < solutionPos[1][1]) {
|
|
goodsolution = true;
|
|
} else if (solutionPos[0][1] > solutionPos[1][1] + s) {
|
|
goodsolution = true;
|
|
}
|
|
} else {
|
|
goodsolution = true;
|
|
}
|
|
}
|
|
for (let i = 0; i < s; i++) {
|
|
solutions[0] = solutions[0] + HEX_VALUES[getRandomInt(0, 15)];
|
|
solutions[1] = solutions[1] + HEX_VALUES[getRandomInt(0, 15)];
|
|
}
|
|
userSolPos = [
|
|
[1, 1],
|
|
[1, 19 - s],
|
|
];
|
|
};
|
|
|
|
const startGame = (solutionsize, timeout) => {
|
|
initializeGameTable();
|
|
for (let i = 0; i < NUM_ROWS; i++) {
|
|
for (let j = 0; j < NUM_COLS; j++) {
|
|
lastReseed[i][j] = 0;
|
|
}
|
|
}
|
|
generateSolutions(solutionsize);
|
|
gameStarted = true;
|
|
endTime = new Date().getTime() + timeout * 1000;
|
|
if (thread) {
|
|
cancelAnimationFrame(thread);
|
|
}
|
|
thread = requestAnimationFrame(seedTable);
|
|
};
|
|
|
|
const initializeGameTable = () => {
|
|
const existingTable = document.getElementById("gametable");
|
|
if (existingTable) {
|
|
existingTable.remove();
|
|
}
|
|
const gametable = document.createElement("table");
|
|
gametable.id = "gametable";
|
|
|
|
for (let i = 0; i < 9; i++) {
|
|
const row = document.createElement("tr");
|
|
row.setAttribute("id", `row${i + 1}`);
|
|
gametable.appendChild(row);
|
|
|
|
for (let j = 0; j < 18; j++) {
|
|
const cell = document.createElement("td");
|
|
cell.setAttribute("id", `${i + 1}${j + 1}`);
|
|
cell.innerHTML = " ";
|
|
row.appendChild(cell);
|
|
}
|
|
}
|
|
const game = document.getElementById("game");
|
|
game.appendChild(gametable);
|
|
};
|
|
|
|
document.addEventListener("keydown", (event) => {
|
|
if (!gameStarted) return;
|
|
|
|
const key = event.key;
|
|
|
|
if (gameStarted && key === "Escape") {
|
|
gameStarted = false;
|
|
fetch(`https://${GetParentResourceName()}/hackClosed`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ userCancelled: true }),
|
|
});
|
|
resetGameState();
|
|
return;
|
|
}
|
|
|
|
if (!solved[0]) {
|
|
switch (key) {
|
|
case "w":
|
|
if (userSolPos[0][0] > 1) userSolPos[0][0]--;
|
|
break;
|
|
case "a":
|
|
if (userSolPos[0][1] > 1) userSolPos[0][1]--;
|
|
break;
|
|
case "s":
|
|
if (userSolPos[0][0] < NUM_ROWS) userSolPos[0][0]++;
|
|
break;
|
|
case "d":
|
|
if (userSolPos[0][1] < NUM_COLS) userSolPos[0][1]++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!solved[1]) {
|
|
switch (key) {
|
|
case "ArrowUp":
|
|
if (userSolPos[1][0] > 1) userSolPos[1][0]--;
|
|
break;
|
|
case "ArrowLeft":
|
|
if (userSolPos[1][1] > 1) userSolPos[1][1]--;
|
|
break;
|
|
case "ArrowDown":
|
|
if (userSolPos[1][0] < NUM_ROWS) userSolPos[1][0]++;
|
|
break;
|
|
case "ArrowRight":
|
|
if (userSolPos[1][1] < NUM_COLS - solutions[1].length + 1) userSolPos[1][1]++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!solved[0] && key === " ") {
|
|
if (userSolPos[0][0] === solutionPos[0][0] && userSolPos[0][1] === solutionPos[0][1]) {
|
|
solved[0] = true;
|
|
for (let i = 0; i < solutions[0].length; i++) {
|
|
const cellId = userSolPos[0][0] + "" + (userSolPos[0][1] + i);
|
|
const cell = document.getElementById(cellId);
|
|
cell.classList.add("sol2");
|
|
}
|
|
const sol2Elements = document.querySelectorAll(".sol2");
|
|
sol2Elements.forEach((el) => {
|
|
el.style.transition = "opacity 0.5s";
|
|
el.style.opacity = "0";
|
|
setTimeout(() => (el.style.opacity = "1"), 500);
|
|
});
|
|
playSound("audiocorrect", 1);
|
|
tryFinish();
|
|
} else {
|
|
playSound("audiowrong", 1);
|
|
wrongSolution();
|
|
}
|
|
}
|
|
|
|
if (!solved[1] && key === "Enter") {
|
|
if (userSolPos[1][0] === solutionPos[1][0] && userSolPos[1][1] === solutionPos[1][1]) {
|
|
solved[1] = true;
|
|
for (let i = 0; i < solutions[1].length; i++) {
|
|
const cellId = userSolPos[1][0] + "" + (userSolPos[1][1] + i);
|
|
const cell = document.getElementById(cellId);
|
|
cell.classList.add("sol2");
|
|
}
|
|
const sol2Elements = document.querySelectorAll(".sol2");
|
|
sol2Elements.forEach((el) => {
|
|
el.style.transition = "opacity 0.5s";
|
|
el.style.opacity = "0";
|
|
setTimeout(() => (el.style.opacity = "1"), 500);
|
|
});
|
|
playSound("audiocorrect", 1);
|
|
tryFinish();
|
|
} else {
|
|
playSound("audiowrong", 1);
|
|
wrongSolution();
|
|
}
|
|
}
|
|
});
|
|
|
|
window.addEventListener("message", (event) => {
|
|
let data = event.data;
|
|
if (data.action === "startHack") {
|
|
if (!gameStarted) {
|
|
hackingContainer.style.display = "flex";
|
|
startGame(data.solutionsize, data.timeout);
|
|
}
|
|
}
|
|
});
|