X-Git-Url: https://git.cworth.org/git?p=lmno.games;a=blobdiff_plain;f=empires%2Fgame.js;h=05b801e352d0e6c0c51e84cfc157e43162024f50;hp=a0df9134df1e87de86b9e722a07a141bc6606397;hb=HEAD;hpb=f3188cb0892ed398112b3d14f444e01b79de6f12 diff --git a/empires/game.js b/empires/game.js index a0df913..05b801e 100644 --- a/empires/game.js +++ b/empires/game.js @@ -1,4 +1,44 @@ -const API = "https://families.cworth.org/api/"; +/* Construction of Game API endpoint paths. Logically all endpoints + * are just local resources underneath the current path, but just + * referring to them by a local name only works if the current path + * has a trailing slash. + * + * That is, if the current path is: + * + * https://lmno.games/empires/WXYZ/ + * + * Then a path of "register" goes to: + * + * https://lmno.games/empires/WXYZ/register + * + * Just as we want. But if the current path happens to be: + * + * https://lmno.games/empires/WXYZ + * + * Then a path of "register" goes to: + * + * https://lmno.games/empires/register + * + * Which cannot work since we have lost the game ID in the path. + * + * Of course, we would like to have canonical URLs for the game (with + * the trailing slash) but since that depends on macehinery outside + * the scope of this file, let's construct API paths that will work + * either way. + */ +function GAME_API(endpoint) { + var path = window.location.pathname; + if (! path.endsWith('/')); + path += '/'; + path += endpoint; + return path; +} + +var state = { + spectator_id: undefined, + spectators: [], + players: [] +}; function undisplay(element) { element.style.display="none"; @@ -14,15 +54,20 @@ ${message} } function register(form) { - var request = new XMLHttpRequest(); + const spectator_req = new XMLHttpRequest(); + + /* Before registering as a player, first remove us as a spectator. */ + spectator_req.open("DELETE", GAME_API("spectator/") + state.spectator_id); + spectator_req.send(); - request.open("POST", API + "register"); - request.setRequestHeader("Content-Type", "application/json; charset=UTF-8"); + const register_req = new XMLHttpRequest(); + + register_req.open("POST", GAME_API("register")); + register_req.setRequestHeader("Content-Type", "application/json; charset=UTF-8"); var data = { - "name": form.name.value, "character": form.character.value }; - request.send(JSON.stringify(data)); + register_req.send(JSON.stringify(data)); form.reset(); } @@ -30,8 +75,6 @@ function register(form) { function toggle_host_tools() { const host_tools = document.getElementById("host-tools"); - console.log("Toggling, host_tools.style.display is '" + host_tools.style.display + "'"); - if (host_tools.style.display === "block") host_tools.style.display = "none"; else @@ -41,25 +84,25 @@ function toggle_host_tools() { function post_reveal() { const request = new XMLHttpRequest(); - request.open("POST", API + "reveal"); + request.open("POST", GAME_API("reveal")); request.send(); } function post_start() { const request = new XMLHttpRequest(); - request.open("POST", API + "start"); + request.open("POST", GAME_API("start")); request.send(); } function post_reset() { const request = new XMLHttpRequest(); - request.open("POST", API + "reset"); + request.open("POST", GAME_API("reset")); request.send(); } -const events = new EventSource(API + "events"); +const events = new EventSource(GAME_API("events")); events.onerror = function(event) { if (event.target.readyState === EventSource.CLOSED) { @@ -67,6 +110,45 @@ events.onerror = function(event) { } }; +events.addEventListener("spectators", function(event) { + const spectators_div = document.getElementById("spectators-div"); + const spectators_element = document.getElementById("spectators"); + const spectators = JSON.parse(event.data); + + spectators_element.innerHTML = ''; + for (const spectator of spectators) { + var li = document.createElement('li'); + li.id = "spectator-" + spectator.id; + li.innerText = spectator.name; + spectators_element.appendChild(li); + } + + /* Force players list to be visible. */ + spectators_div.style.display = "block"; +}); + +events.addEventListener("spectator-join", function(event) { + const spectators_div = document.getElementById("spectators-div"); + const spectators = document.getElementById("spectators"); + const spectator = JSON.parse(event.data); + + const li = document.createElement('li'); + li.id = "spectator-" + spectator.id; + li.innerText = spectator.name; + spectators.appendChild(li); + + /* Force spectators list to be visible. */ + spectators_div.style.display = "block"; +}); + +events.addEventListener("spectator-leave", function(event) { + const spectators = document.getElementById("spectators"); + const id = JSON.parse(event.data); + const spectator = document.getElementById("spectator-" + id.id); + + spectators.removeChild(spectator); +}); + events.addEventListener("players", function(event) { const players_div = document.getElementById("players-div"); const players_element = document.getElementById("players"); @@ -107,25 +189,38 @@ events.addEventListener("player-leave", function(event) { players.removeChild(player); }); -events.addEventListener("game-state", function(event) { +function spectator_on_load() { + state.spectator_id = JSON.parse(this.response); +} + +events.addEventListener("game-phase", function(event) { const data = JSON.parse(event.data); - const old_state = data.old_state; - const new_state = data.new_state; + const old_phase = data.old_phase; + const new_phase = data.new_phase; - const hide_selector = ".show-state-" +old_state+ ",.hide-state-" +new_state; - const show_selector = ".hide-state-" +old_state+ ",.show-state-" +new_state; + const hide_selector = ".show-phase-" +old_phase+ ",.hide-phase-" +new_phase; + const show_selector = ".hide-phase-" +old_phase+ ",.show-phase-" +new_phase; - /* Hide all elements based on the state transition. */ + /* Hide all elements based on the phase transition. */ var elts = document.querySelectorAll(hide_selector); for (const elt of elts) { elt.style.display = "none"; } - /* And show all elements based on the same state transition. */ + /* And show all elements based on the same phase transition. */ elts = document.querySelectorAll(show_selector); for (const elt of elts) { elt.style.display = "block"; } + + /* Whenever the game enters the "join" phase, add ourselves as a spectator. */ + if (new_phase === "join") { + const request = new XMLHttpRequest(); + + request.addEventListener("load", spectator_on_load); + request.open("POST", GAME_API("spectator")); + request.send(); + } }); events.addEventListener("character-reveal", function(event) {