X-Git-Url: https://git.cworth.org/git?p=lmno.games;a=blobdiff_plain;f=empires%2Fgame.js;h=8043d32dc281799adf2734c3ce1306bd50168617;hp=d3d34949cdf87fe1875893939962b600f527b11d;hb=5bcc934af2effc02ea873e847bf564bbc6b61125;hpb=4d7bbd9fca8c718cd6a10ea7f7107974a5039138 diff --git a/empires/game.js b/empires/game.js index d3d3494..8043d32 100644 --- a/empires/game.js +++ b/empires/game.js @@ -1,3 +1,45 @@ +/* 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"; } @@ -12,15 +54,20 @@ ${message} } function register(form) { - var request = new XMLHttpRequest(); + const spectator_req = new XMLHttpRequest(); - request.open("POST", "register"); - request.setRequestHeader("Content-Type", "application/json; charset=UTF-8"); + /* Before registering as a player, first remove us as a spectator. */ + spectator_req.open("DELETE", GAME_API("spectator/") + state.spectator_id); + spectator_req.send(); + + 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(); } @@ -39,25 +86,25 @@ function toggle_host_tools() { function post_reveal() { const request = new XMLHttpRequest(); - request.open("POST", "reveal"); + request.open("POST", GAME_API("reveal")); request.send(); } function post_start() { const request = new XMLHttpRequest(); - request.open("POST", "start"); + request.open("POST", GAME_API("start")); request.send(); } function post_reset() { const request = new XMLHttpRequest(); - request.open("POST", "reset"); + request.open("POST", GAME_API("reset")); request.send(); } -const events = new EventSource(window.location + "events"); +const events = new EventSource(GAME_API("events")); events.onerror = function(event) { if (event.target.readyState === EventSource.CLOSED) { @@ -65,6 +112,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"); @@ -105,6 +191,10 @@ events.addEventListener("player-leave", function(event) { players.removeChild(player); }); +function spectator_on_load() { + state.spectator_id = JSON.parse(this.response); +} + events.addEventListener("game-state", function(event) { const data = JSON.parse(event.data); const old_state = data.old_state; @@ -124,6 +214,15 @@ events.addEventListener("game-state", function(event) { for (const elt of elts) { elt.style.display = "block"; } + + /* Whenever the game enters the "join" state, add ourselves as a spectator. */ + if (new_state === "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) {