From ad62fb8a8eab63711b8c47a552a76600bdd8e137 Mon Sep 17 00:00:00 2001 From: Chris Karle Date: Mon, 27 Apr 2020 22:52:31 -0400 Subject: [PATCH] Lobby, CardTable, TrumpPicker Add force-rejoin support in 'end' phase. Remove Rejoin button if player instead changes their name in Lobby page. Add GameOver panel which submits restart_game if "play again" button clicked. Add and currently default to true on new options: hard_order = play alone if you order your partner hard_pick = dealer can only pick kitty if has suit --- assets/app.js | 7 ++++--- assets/app.scss | 21 ++++++++++++++++++++- assets/components/CardTable.js | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- assets/components/Lobby.js | 4 ++-- assets/components/TrumpPicker.js | 8 +++++--- 5 files changed, 128 insertions(+), 19 deletions(-) diff --git a/assets/app.js b/assets/app.js index 7ae6744..a8ee056 100644 --- a/assets/app.js +++ b/assets/app.js @@ -44,9 +44,10 @@ class App extends React.Component { } setPlayerName = name => { - this.setState( - { playerName: name } - ); + this.setState({ + playerName: name, + uniqueError: false + }); } // need to only showTable if no user-not-unique diff --git a/assets/app.scss b/assets/app.scss index 949fe22..ada9f07 100644 --- a/assets/app.scss +++ b/assets/app.scss @@ -4,7 +4,26 @@ margin-top: 3rem; margin-left: 3rem; } - +.unique__error { + margin-top: 1.2rem; + color: red; +} +.gover__outer { + display: flex; + flex-direction: column; + align-items: center; + background-color: bisque; + padding: 15px; +} +.gover__inwin { + font-size: 2rem; + font-weight: bold; +} +.gover__inst { + font-size: 1.2rem; + margin-top: 10px; + margin-bottom: 10px; +} .textRow { display: flex; align-items: flex-start; diff --git a/assets/components/CardTable.js b/assets/components/CardTable.js index 988e7a5..f5fa7bb 100644 --- a/assets/components/CardTable.js +++ b/assets/components/CardTable.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import _ from 'lodash'; import {Button, Grid, Row, Column} from 'carbon-components-react'; -import {Logout32} from '@carbon/icons-react'; +import {Logout32, Redo32} from '@carbon/icons-react'; import SeatPicker from './SeatPicker'; import MainHand from './MainHand'; import HiddenHand from './HiddenHand'; @@ -16,6 +16,9 @@ const suit = { C: 'Clubs' } +const hard_order = true; +const hard_pick = true; + export default class CardTable extends React.Component { constructor(props) { @@ -49,7 +52,10 @@ export default class CardTable extends React.Component { score: [0, 0], trickWinner:'', tricks:[], - bannerMsg: '' + bannerMsg: '', + innerWinMsg: '', + onlyAlone: false, + noPick: false }; }; @@ -120,10 +126,27 @@ export default class CardTable extends React.Component { case 'play': this.processFirstMsgPlay(msg); break; + case 'end': + this.processFirstMsgEnd(msg); + break; } } } + // NOTE the processFirstMsgXyz functions are needed to handle the case + // of a user dropping connection and doing a force-rejoin back to the + // same table. + // In normal game play, firstMsg will be a 'lobby', and none of the other + // processFirst* variants will be called + + processFirstMsgEnd = msg => { + // timer use in these processFirst* is to allow sequence of setState to complete + this.initMySeat(msg); + setTimeout(this.gameStartSetup, 300, msg); + setTimeout(this.handStartSetup, 600, msg); + setTimeout(this.processEnd, 900, msg); + } + processFirstMsgPlay = msg => { this.initMySeat(msg); setTimeout(this.gameStartSetup, 300, msg); @@ -147,7 +170,8 @@ export default class CardTable extends React.Component { processLobby = (msg) => { this.initMySeat(msg); this.setState({ - phase: 'lobby' + phase: 'lobby', + score: [0,0] }); }; @@ -162,6 +186,17 @@ export default class CardTable extends React.Component { }; } + haveSuit = (hand, trumpNom) => { + const targetSuit = trumpNom.substring(1); + for (let i=0; i < hand.length; i++) { + if (hand[i].substring(1) == targetSuit) { + console.log('targetSuit:' + targetSuit + ' matched by ' + hand[i]); + return true; + } + } + return false; + } + processVote = (msg) => { if (this.state.phase == 'lobby') { this.gameStartSetup(msg); @@ -170,14 +205,19 @@ export default class CardTable extends React.Component { // second condition is for all players pass trump twice this.trumpStartSetup(msg); } - const {leftSeat, rightSeat, partnerSeat, mySeat} = this.state; - const phaseString = msg.game.pass_count > 3 ? 'vote2' : 'vote'; + const {leftSeat, rightSeat, partnerSeat, mySeat, dealSeat} = this.state; + const vote1phase = msg.game.pass_count < 4; + const phaseString = vote1phase ? 'vote' : 'vote2'; + const onlyAlone = hard_order && vote1phase && dealSeat == partnerSeat; + const noPick = hard_pick && vote1phase && (dealSeat == mySeat) && !this.haveSuit(msg.hand, msg.game.trump_nominee); let turnInfo = ['', '', '', '']; turnInfo[msg.game.turn] = 'trump?'; this.setState({ phase: phaseString, myCards: msg.hand, turnSeat: msg.game.turn, + onlyAlone: onlyAlone, + noPick: noPick, leftTurnInfo: turnInfo[leftSeat], rightTurnInfo: turnInfo[rightSeat], partnerTurnInfo: turnInfo[partnerSeat], @@ -267,10 +307,12 @@ export default class CardTable extends React.Component { const winMsg = finalScore[0] > finalScore[1] ? 'You and ' + playerNames[partnerSeat] + ' win the game!!' : playerNames[leftSeat] + ' and ' + playerNames[rightSeat] + ' win this one...'; + const innerWin = finalScore[0] > finalScore[1] ? 'You Win!!' : 'You lost...' this.setState({ phase: 'end', score: finalScore, - bannerMsg: winMsg + bannerMsg: winMsg, + innerWinMsg: innerWin }); } @@ -415,6 +457,42 @@ export default class CardTable extends React.Component { } }; + sendRestart = () => { + this.props.client.send(JSON.stringify({ + action:'restart_game' + })); + } + + genGameOver = () => { + const {innerWinMsg} = this.state; + let retVal = []; + retVal.push( +
+
{innerWinMsg}
+
+ You can play again at this table, or return to the lobby + to change your table or player name... +
+
+ + + +
+
+ ); + return retVal; + } + genTrick = () => { let retVal = []; const { table, mySeat, leftSeat, rightSeat, partnerSeat } = this.state; @@ -481,8 +559,9 @@ export default class CardTable extends React.Component { const { playerNames, mySeat, phase, myCards, myHandInfo, myTurnInfo, partnerName, partnerHandInfo, partnerTurnInfo, partnerSeat, leftName, leftTurnInfo, leftHandInfo, leftSeat, rightName, rightHandInfo, rightTurnInfo, rightSeat, trumpPlace, trumpNom, turnSeat, - dealSeat, trump, handLengths, score, trickWinner, bannerMsg } = this.state; - const showSeatPicker = phase == 'lobby' || phase == 'end'; + dealSeat, trump, handLengths, score, trickWinner, bannerMsg, noPick, onlyAlone } = this.state; + const showSeatPicker = phase == 'lobby'; + const showGameOver = phase == 'end'; const showTrump = (phase == 'vote') || (phase == 'vote2') || (phase == 'swap'); const showTrumpPicker = showTrump && (turnSeat == mySeat); const showSwap = (phase == 'swap') && (dealSeat == mySeat); @@ -491,10 +570,11 @@ export default class CardTable extends React.Component { const trumpImage = (phase != 'vote2') ? 'cards/' + trumpNom + '.svg' : 'cards/1B.svg'; const trumpMsg = phase == 'play' ? suit[trump] + ' are trump' : ''; const trickDisplay = (phase == 'play' || phase == 'pause') ? this.genTrick() : []; + const gameOverDisplay = (phase == 'end') ? this.genGameOver() : []; return (
- {showSeatPicker && ( + {(showSeatPicker || showGameOver) && (

{bannerMsg}

@@ -504,7 +584,7 @@ export default class CardTable extends React.Component {
@@ -564,6 +644,11 @@ export default class CardTable extends React.Component { { (phase=='play' || phase=='pause') && (
{trickDisplay}
)} + { showGameOver && ( +
+ {gameOverDisplay} +
+ )} {!showSeatPicker && ( @@ -590,6 +675,8 @@ export default class CardTable extends React.Component { trumpCard={trumpNom} phaseTwo={phase == 'vote2'} myDeal={dealSeat == mySeat} + onlyAlone={onlyAlone} + noPick={noPick} handleVote={this.sendVote} /> )} {showSwap && ( diff --git a/assets/components/Lobby.js b/assets/components/Lobby.js index 77ad024..4ae005b 100644 --- a/assets/components/Lobby.js +++ b/assets/components/Lobby.js @@ -111,10 +111,10 @@ export default class Lobby extends React.Component { )} {uniqueError && ( -
+

Hmm, a player named {name} is at the table...

You need a unique player name, which you can change in the top input above.

-

OR if you lost your connection and want to re-join the +

OR if you lost your connection and want to re-join the game as player "{name}" from this page, press the REJOIN button below

@@ -95,6 +95,8 @@ TrumpPicker.propTypes = { trumpCard: PropTypes.string, phaseTwo: PropTypes.bool, myDeal: PropTypes.bool, + onlyAlone: PropTypes.bool, + noPick: PropTypes.bool, handleVote: PropTypes.func, } export default TrumpPicker; -- libgit2 1.1.1