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}//${window.location.hostname}:${window.location.port}${window.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) => s + String.fromCodePoint(c), ""); 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 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 = ((tpos.x + 0.5) * tile_w) + 'px'; win.style.top = ((tpos.y + 0.5) * 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)); }