+ add_player(session, connection) {
+ /* First see if we already have a player object for this session. */
+ const existing = this.players_by_session[session.id];
+ if (existing) {
+ existing.add_connection(connection);
+ return existing;
+ }
+
+ /* No existing player. Add a new one. */
+ const id = this.next_player_id;
+ const player = new Player(id, session.id, session.nickname, connection);
+
+ /* Broadcast before adding player to list (to avoid announcing the
+ * new player to itself). */
+ const player_data = JSON.stringify({ id: player.id, name: player.name });
+ this.broadcast_event("player-enter", player_data);
+
+ this.players.push(player);
+ this.players_by_session[session.id] = player;
+ this.next_player_id++;
+
+ /* After adding the player to the list, and if we are already past
+ * the first move, assign this player to the first team that
+ * doesn't already have a player aissgned (if any). */
+ if (! this.first_move) {
+ const have_players = Array(this.teams.length).fill(false);
+ this.players.forEach(p => {
+ if (p.team.id !== undefined)
+ have_players[p.team.id] = true;
+ });
+ const first_empty = have_players.findIndex(i => i === false);
+ this.assign_player_to_team_perhaps(player, this.teams[first_empty]);
+ }
+
+ return player;
+ }
+
+ /* Drop a connection object from a player, and if it's the last one,
+ * then drop that player from the game's list of players. */
+ remove_player_connection(player, connection) {
+ const remaining = player.remove_connection(connection);
+ if (remaining === 0) {
+ const player_data = JSON.stringify({ id: player.id });
+ this.players.filter(p => p !== player);
+ delete this.players_by_session[player.session_id];
+ this.broadcast_event("player-exit", player_data);
+ }
+ }
+
+ /* Send a string to all players */