window.id = NaN;
window.name = "anon";
window.clr = "#f03333";
window.info_elem = document.getElementById("miscinfo");
window.info_elem.innerHTML =`
`;
window.board_elem = document.getElementById("board");
window.bwidth = NaN;
window.bheight = NaN;
window.tile_w = NaN;
window.tile_h = NaN;
window.mine_ratio = "unk";
window.socket = {};
window.last_packet = {};
window.cursors = new Map();
window.board = {};
window.board_bounds = {}; // init when we actually have the board loaded
function register() {
window.name = document.getElementById("name-in").value;
window.clr = document.getElementById("clr-in").value;
window.socket = connect();
}
function connect() {
let wsproto = (window.location.protocol == "https:")? "wss:": "ws:";
let s = new WebSocket(`${wsproto}//${location.hostname}:${location.port}${location.pathname}/ws`);
s.onopen = function() {
s.send(`register ${window.name} ${window.clr}`);
}
s.onmessage = function(e) {
last_packet = e;
let d = e.data;
if (typeof d == "object") {
d.arrayBuffer().then(acceptBoard);
info_elem.onclick = undefined;
info_elem.innerHTML = `Running, ${mine_ratio} tiles are mines`;
} else if (typeof e.data == "string") {
let fields = d.split(" ");
switch (fields[0]) {
case "pos": {
let oid = Number(fields[1]);
let name = fields[2];
let clr = fields[3];
let x = fields[4];
let y = fields[5];
if (!cursors.has(oid)) {
createCursor(oid, name, clr);
}
let celem = cursors.get(oid).elem;
celem.style.left = x + 'px';
celem.style.top = y + 'px';
movSelWin(cursors.get(oid).selwin, x, y);
} break;
case "regack": {
name = fields[1];
id = Number(fields[2]);
let dims = fields[3].split("x");
bwidth = Number(dims[0]);
bheight = Number(dims[1]);
mine_ratio = fields[4];
createCursor(id, name, clr);
} break;
case "win": {
info_elem.innerHTML = "You win! Click here to play again.
";
info_elem.onclick = e => { s.send("reset") };
} break;
case "lose": {
let badone = fields[1];
info_elem.innerHTML = `You lost, ${badone} was blown up. Click here to retry.
`;
info_elem.onclick = e => { s.send("reset") };
} break;
case "logoff": {
let oid = Number(fields[1]);
cursors.get(oid).elem.remove();
cursors.get(oid).selwin.remove();
cursors.delete(oid);
} break;
}
}
}
s.onerror = function(e) { info_elem.innerHTML += `
Error ${e}`; }
s.onclose = function(e) { info_elem.innerHTML = "Closed"; }
return s;
}
function acceptBoard(data) {
let vals = new Uint8Array(data);
board = Array.from(vals).reduce((s,c) => {
let v = String.fromCodePoint(c);
if (v == ' ') {
s = s + " ";
} else {
s = s + v;
}
return s;
}, "");
let last = board[0];
let last_idx = 0;
let split_board = [];
for (let i = 1; i < board.length+1; i++) {
let cur = board[i];
let gamechars = /^[CFO# 1-8]+$/;
if ((cur != last && gamechars.test(cur)) || cur == undefined) {
let txt = board.substr(last_idx, i-last_idx);
switch(txt[0]) {
case 'O':
txt = `${txt}`;
break;
case 'C':
txt = `${txt}`;
break;
case 'F':
txt = `${txt}`;
break;
case '1': txt = `${txt}`; break;
case '2': txt = `${txt}`; break;
case '3': txt = `${txt}`; break;
case '4': txt = `${txt}`; break;
case '5': txt = `${txt}`; break;
case '6': txt = `${txt}`; break;
default: txt = `${txt}`; break;
}
split_board.push(txt);
last_idx = i;
}
last = board[i];
}
board_elem.innerHTML = split_board.join("");
}
function createCursor(id, name, clr) {
// shit doesn't line up
let cursor = document.createElement("div");
cursor.style.position = "absolute";
let nametag = document.createElement("p");
nametag.innerHTML = name;
nametag.classList.add('cursor-name');
let selection_window = document.createElement("div");
selection_window.style.backgroundColor = clr + "a0";
selection_window.style.position = "absolute";
selection_window.classList.add('cursor');
cursor.appendChild(nametag);
cursor.classList.add('cursor');
cursor.style.color = clr;
document.getElementById('board-container').append(cursor);
document.getElementById('board-container').append(selection_window);
if (id == window.id) {
document.addEventListener('mousemove', e => {
cursor.style.left = (e.pageX + 15) + 'px';
cursor.style.top = (e.pageY + 15) + 'px';
movSelWin(selection_window, e.clientX, e.clientY);
let tpos = tilepos(e.clientX, e.clientY);
socket.send(`pos ${e.pageX} ${e.pageY}`);
},
false);
}
cursors.set(id, {name: name, elem: cursor, selwin: selection_window});
return cursor;
}
function movSelWin(win, x, y) {
let anch = board_elem.getBoundingClientRect();
let tpos = tilepos(x, y);
if (tpos.x > (bwidth - 1) || tpos.x < 0 || tpos.y > (bheight - 1) || tpos.y < 0) {
win.style.display = "none";
} else {
win.style.display = "";
}
win.style.left = (window.scrollX + anch.x + (tpos.x * tile_w)) + 'px';
win.style.top = (window.scrollY + anch.y + ((tpos.y + 0.35) * tile_h)) + 'px';
win.style.width = tile_w + 'px';
win.style.height = tile_h + 'px';
}
function getBoardBounds() {
let boardb = board_elem.getBoundingClientRect();
tile_w = boardb.width / bwidth;
tile_h = 22;
return {
ox: boardb.x,
oy: boardb.y,
w: boardb.width,
h: boardb.height
};
}
board_elem.onclick = function(e) {
let tpos = tilepos(e.clientX, e.clientY);
let cmd = `reveal ${tpos.x} ${tpos.y}`;
console.log(cmd);
socket.send(cmd);
}
board_elem.oncontextmenu = function(e) {
let tpos = tilepos(e.clientX, e.clientY);
let cmd = `flag ${tpos.x} ${tpos.y}`;
console.log(cmd);
socket.send(cmd);
return false;
}
function tilepos(x,y) {
board_bounds = getBoardBounds();
let b = board_bounds;
let relx = (x - b.ox);
let rely = (y - b.oy);
let tilex = Math.floor(bwidth * relx/b.w);
let tiley = Math.floor(bheight * rely/b.h);
return { x: tilex, y: tiley };
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}