diff --git a/back/src/Game.ts b/back/src/Game.ts index 028dd21..4643da6 100644 --- a/back/src/Game.ts +++ b/back/src/Game.ts @@ -1,4 +1,4 @@ -import {canPlay, Card, cmpCard, Suit} from 'bsx-core'; +import {Card, Suit} from 'bsx-core'; import Client from './Client'; import logSocket from './logSocket'; @@ -9,6 +9,7 @@ class Player { game: Game; client: Client; cards: Card[] = []; + stack: Card[] = []; disconnected = false; disconnectListener?: () => void; rank = 0; @@ -17,7 +18,6 @@ class Player { this.client = client; } sendGameState() { - this.cards.sort(cmpCard); const i = this.game.players.indexOf(this); const otherPlayers = []; for (let j = 1; j < this.game.players.length; ++j) @@ -30,6 +30,7 @@ class Player { numCards: p.cards.length, rank: p.rank, })), + phase: this.game.phase, lastPlayed: this.game.lastPlayed, lastPlayedPlayer: this.game.lastPlayedPlayer < 0 ? null : this.game.players[this.game.lastPlayedPlayer].client.username, playerTurn: this.game.players[this.game.playerTurn].client.username @@ -76,7 +77,7 @@ export default class Game { }); if (playersLeft.length < 2) { if (playersLeft.length === 1) - playersLeft[0].rank = ++this.playersFinished; + playersLeft[0].rank = ++this.playersFinished; // rank is reversed, fix later break; } await this.round(); @@ -93,33 +94,56 @@ export default class Game { } async round() { this.phase = 0; - await this.prepare(); + await this.prepare(); // Phase 0 this.phase = 1; - while (true) { + this.lastPlayed = 0; + while (true) { // Phase 1 const p = this.players[this.playerTurn]; if (p.rank || p.disconnected) { this.playerTurn = (this.playerTurn + 1) % this.players.length; continue; } - let result = await this.turn(); - if (result === false) break; // Called BS! + await this.turn(); + if (this.phase === 2) break; // Called BS! this.lastPlayedPlayer = this.playerTurn; this.playerTurn = (this.playerTurn + 1) % this.players.length; } - this.phase = 2; - while (this.lastPlayed > 0) { - let result = await this.flip(); - if (result === false) { // Oops, flipped over a red card - + while (this.lastPlayed > 0) { // Phase 2 + await this.flip(); + if (this.phase === 3) { // Oops, flipped over a red card! + await this.giveup(); // The player who called BS won and now the challenged player must give up a card! + return; } } - this.lastPlayed = 0; + await this.giveup(); // The player who called BS won and now they must give up a card! } - async prepare() { + async prepare() { // Players prepare their hand for this round this.broadcastGameState(); + const playerPromises = []; + for (let i = 0; i < this.room.clients.length; ++i) { + const p = this.players[i]; + if (p.rank || p.disconnected) continue; + playerPromises.push(new Promise(resolve => { + p.client.once('prepare', order => { + delete p.disconnectListener; + (() => { + + p.client.socket.disconnect(); + logSocket(p.client.socket, 'Bad cards argument on turn'); + })(); + resolve(); + }); + p.disconnectListener = () => { + delete p.disconnectListener; + p.client.removeAllListeners('prepare'); + resolve(); + }; + })); + } + await Promise.all(playerPromises); } - async turn() { + async turn() { // Do a turn const p = this.players[this.playerTurn]; this.broadcastGameState(); await new Promise(resolve => { @@ -127,11 +151,12 @@ export default class Game { delete p.disconnectListener; (() => { if (num === -1) { - return false; // Called BS! + this.phase = 2; // Called BS, move on to the next phase! + return; } if (num > this.lastPlayed) { this.lastPlayed = num; - return true; + return; } p.client.socket.disconnect(); logSocket(p.client.socket, 'Bad cards argument on turn'); @@ -145,17 +170,19 @@ export default class Game { }; }); } - async flip() { + async flip() { // Someone called BS and now the challenged player must flip over a card const p = this.players[this.lastPlayedPlayer]; this.broadcastGameState(); await new Promise(resolve => { p.client.once('turn', selectedPlayer => { delete p.disconnectListener; (() => { - if (this.players[selectedPlayer].cards === -1) { - return false; + if (this.players[selectedPlayer].stack.length > 0) { + if (this.players[selectedPlayer].stack[0].suit === Suit.Diamonds || + this.players[selectedPlayer].stack[0].suit === Suit.Hearts) this.phase = 3; // Red card + this.players[selectedPlayer].stack.splice(0); + return; } - p.client.socket.disconnect(); logSocket(p.client.socket, 'Bad cards argument on turn'); })(); @@ -163,7 +190,27 @@ export default class Game { }); p.disconnectListener = () => { delete p.disconnectListener; - p.client.removeAllListeners('turn'); + p.client.removeAllListeners('flip'); + resolve(); + }; + }); + } + async giveup() { // Give up a card + const p = this.players[this.lastPlayed ? this.lastPlayedPlayer : this.playerTurn]; + this.broadcastGameState(); + await new Promise(resolve => { + p.client.once('giveup', card => { + delete p.disconnectListener; + (() => { + p.cards.splice(card); // Remove card, may want to check if it is valid + p.client.socket.disconnect(); + logSocket(p.client.socket, 'Bad cards argument on turn'); + })(); + resolve(); + }); + p.disconnectListener = () => { + delete p.disconnectListener; + p.client.removeAllListeners('giveup'); resolve(); }; });