]> git.cworth.org Git - empires-server/blobdiff - empires.js
Add new game.js with a new parent class Game
[empires-server] / empires.js
index a8c177109a08f409969be419951e97da59d2a96f..749f26ed9058bbfa60d30138b23ce62a9732e5ab 100644 (file)
@@ -1,18 +1,9 @@
 const express = require("express");
-const cors = require("cors");
-const body_parser = require("body-parser");
-const path = require("path");
-const nunjucks = require("nunjucks");
-
-const app = express();
-app.use(cors());
-app.use(body_parser.urlencoded({ extended: false }));
-app.use(body_parser.json());
-
-nunjucks.configure("templates", {
-  autoescape: true,
-  express: app
-});
+const Game = require("./game.js");
+
+const engine_name = "empires";
+
+const router = express.Router();
 
 const GameState = {
   JOIN:    1,
@@ -42,11 +33,14 @@ function shuffle(a) {
   }
 }
 
-class Game {
+class Empires extends Game {
   constructor() {
+    super(engine_name);
+    this._spectators = [];
+    this.next_spectator_id = 1;
     this._players = [];
-    this.characters_to_reveal = null;
     this.next_player_id = 1;
+    this.characters_to_reveal = null;
     this.clients = [];
     this.next_client_id = 1;
     this.state = GameState.JOIN;
@@ -55,6 +49,31 @@ class Game {
     setInterval(() => {this.broadcast_string(":");}, 15000);
   }
 
+  add_spectator(name, session_id) {
+    /* Don't add another spectator that matches an existing session. */
+    const existing = this._spectators.findIndex(
+      spectator => spectator.session_id === session_id);
+    if (existing >= 0)
+      return existing.id;
+
+    const new_spectator = {id: this.next_spectator_id,
+                           name: name,
+                           session_id: session_id
+                          };
+    this._spectators.push(new_spectator);
+    this.next_spectator_id++;
+    this.broadcast_event("spectator-join", JSON.stringify(new_spectator));
+
+    return new_spectator.id;
+  }
+
+  remove_spectator(id) {
+    const index = this._spectators.findIndex(spectator => spectator.id === id);
+    this._spectators.splice(index, 1);
+
+    this.broadcast_event("spectator-leave", `{"id": ${id}}`);
+  }
+
   add_player(name, character) {
     const new_player = {id: this.next_player_id,
                        name: name,
@@ -84,6 +103,7 @@ class Game {
 
     this.change_state(GameState.JOIN);
 
+    this.broadcast_event("spectators", "{}");
     this.broadcast_event("players", "{}");
   }
 
@@ -155,6 +175,14 @@ class Game {
     return this._players.map(player => ({id: player.id, captures: player.captures}));
   }
 
+  get spectators() {
+    /* We return only "id" and "name" here (specifically not session_id!). */
+    return this._spectators.map(spectator => ({
+      id: spectator.id,
+      name: spectator.name
+    }));
+  }
+
   get players() {
     return this._players.map(player => ({id: player.id, name: player.name }));
   }
@@ -227,7 +255,13 @@ function handle_events(request, response) {
   response.writeHead(200, headers);
 
   /* Now that a client has connected, first we need to stream all of
-   * the existing players (if any). */
+   * the existing spectators and players (if any). */
+  if (game._spectators.length > 0) {
+    const spectators_json = JSON.stringify(game.spectators);
+    const spectators_data = `event: spectators\ndata: ${spectators_json}\n\n`;
+    response.write(spectators_data);
+  }
+
   if (game._players.length > 0) {
     const players_json = JSON.stringify(game.players);
     const players_data = `event: players\ndata: ${players_json}\n\n`;
@@ -255,77 +289,107 @@ function handle_events(request, response) {
   });
 }
 
-app.get('/', (request, response) => {
+router.get('/', (request, response) => {
   if (! request.session.nickname)
-    response.render('choose-nickname.html');
+    response.render('choose-nickname.html', { game_name: "Empires" });
   else
-    response.sendFile(path.join(__dirname, './game.html'));
+    response.render('empires-game.html');
 });
 
-app.post('/register', (request, response) => {
+router.post('/spectator', (request, response) => {
   const game = request.game;
-  game.add_player(request.body.name, request.body.character);
+  var name = request.session.nickname;
+
+  /* If the request includes a name, that overrides the session nickname. */
+  if (request.body.name)
+    name = request.body.name;
+
+  const id = game.add_spectator(name, request.session.id);
+  response.send(JSON.stringify(id));
+});
+
+router.delete('/spectator/:id', (request, response) => {
+  const game = request.game;
+  game.remove_spectator(parseInt(request.params.id));
+  response.send();
+});
+
+router.post('/register', (request, response) => {
+  const game = request.game;
+  var name = request.session.nickname;;
+
+  /* If the request includes a name, that overrides the session nickname. */
+  if (request.body.name)
+    name = request.body.name;
+
+  game.add_player(name, request.body.character);
   response.send();
 });
 
-app.post('/deregister/:id', (request, response) => {
+router.post('/deregister/:id', (request, response) => {
   const game = request.game;
   game.remove_player(parseInt(request.params.id));
   response.send();
 });
 
-app.post('/reveal', (request, response) => {
+router.post('/reveal', (request, response) => {
   const game = request.game;
   game.reveal();
   response.send();
 });
 
-app.post('/start', (request, response) => {
+router.post('/start', (request, response) => {
   const game = request.game;
   game.start();
   response.send();
 });
 
-app.post('/reset', (request, response) => {
+router.post('/reset', (request, response) => {
   const game = request.game;
   game.reset();
   response.send();
 });
 
-app.post('/capture/:captor/:captee', (request, response) => {
+router.post('/capture/:captor/:captee', (request, response) => {
   const game = request.game;
   game.capture(parseInt(request.params.captor), parseInt(request.params.captee));
   response.send();
 });
 
-app.post('/liberate/:id', (request, response) => {
+router.post('/liberate/:id', (request, response) => {
   const game = request.game;
   game.liberate(parseInt(request.params.id));
   response.send();
 });
 
-app.post('/restart', (request, response) => {
+router.post('/restart', (request, response) => {
   const game = request.game;
   game.restart(parseInt(request.params.id));
     response.send();
 });
 
-app.get('/characters', (request, response) => {
+router.get('/characters', (request, response) => {
   const game = request.game;
   response.send(game.characters);
 });
 
-app.get('/empires', (request, response) => {
+router.get('/empires', (request, response) => {
   const game = request.game;
   response.send(game.empires);
 });
 
-app.get('/players', (request, response) => {
+router.get('/spectators', (request, response) => {
+  const game = request.game;
+  response.send(game.spectators);
+});
+
+router.get('/players', (request, response) => {
   const game = request.game;
   response.send(game.players);
 });
 
-app.get('/events', handle_events);
+router.get('/events', handle_events);
 
-exports.app = app;
-exports.Game = Game;
+exports.router = router;
+exports.name = engine_name;
+exports.Game = Empires;