import { generate_keypair } from "../crypto/main.js"; import { Random } from "./random.js"; import { Barrier } from "./barrier.js"; import { Packet } from "./packet.js"; import { updateDom } from "./dom.js"; export const ID = window.crypto.randomUUID(); export let us = null; export const game = new Game(); export let socket; let random; let barrier; let keys; // Not totally reliable but better than nothing. window.addEventListener("beforeunload", () => { socket.emit("message", Packet.createDisconnect()); }); document.addEventListener("DOMContentLoaded", () => { socket = io(); random = new Random(); barrier = new Barrier(); keys = generate_keypair(); socket.on("connect", () => { window.console.log("Connected!"); socket.emit("message", Packet.createAnnounce()); game.addPlayer(ID, name, true); }); socket.on("message", async (data) => { // todo validate signature switch (data.type) { case "RANDOM": if (data.author === ID) { return; } await random.processCooperativeRandom(data); break; case "BARRIER": if (data.author === ID) { return; } barrier.resolve(data); break; default: const event = new CustomEvent(data.type, { detail: data }); document.dispatchEvent(event); break; } }); }); /** * Process player connect packets: these inform that a new player has joined. * * @param data Packet received */ document.addEventListener("ANNOUNCE", (data) => { if (data.author === ID) return; let is_new = game.addPlayer(data.author, data.name, false); // When a new player is seen, all announce to ensure they know all players. if (is_new) { socket.emit("message", Packet.createAnnounce()); } }); document.addEventListener("DISCONNECT", (data) => { game.removePlayer(data.author); }); /** * Process keep-alive packets: these are packets that check players are still online. * * @param data Packet received */ document.addEventListener("KEEPALIVE", (data) => { game.keepAlive(data.author); }); document.addEventListener("ACT", async (data) => { if (data.author !== game.currentPlayer().id) { if (data.action === "DEFENSE") { await game.players[data.author].setDefense(data.amount); } return; } if (game.isWaiting()) { game.setReady(data.author, data.ready); } else if (game.isPregame()) { if (!Region.allRegionsClaimed()) { // Claim a region in the pregame. if (game.currentPlayer().claim(data)) { // Increment to next player. game.currentPlayer().endTurn(); } } else if (!Region.allReinforcementsPlaced()) { if (game.currentPlayer().reinforce(data)) { game.currentPlayer().endTurn(); } } if (Region.allReinforcementsPlaced()) { game.incrementState(); } } else { if (await game.currentPlayer().act(data)) { game.currentPlayer().endTurn(); } } }); export async function startPregame() { gameState = PRE_GAME; let firstPlayerIndex = await random.get(Object.keys(players).length, "first-player"); let firstPlayer = Object.values(players).sort((a, b) => (a.id < b.id ? -1 : 1))[ firstPlayerIndex ]; firstPlayer.isPlaying = true; await barrier.wait(); updateDom(); }