1
0
Fork 0
forked from Simnation/Main
Main/resources/[qb]/qb-minigames/html/js/hacking.js

331 lines
10 KiB
JavaScript
Raw Normal View History

2025-06-07 08:51:21 +02:00
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 = "&nbsp;";
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);
}
}
});