]> git.cworth.org Git - lmno.games/blobdiff - empires/game.js
Add some autofocus attributes
[lmno.games] / empires / game.js
index d3d34949cdf87fe1875893939962b600f527b11d..05b801e352d0e6c0c51e84cfc157e43162024f50 100644 (file)
@@ -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();
 }
@@ -28,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
@@ -39,25 +84,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 +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");
@@ -105,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) {