From d01ab17e135e00317c57cd1e92a7b30b8ae35a5f Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Sat, 12 Mar 2022 16:57:21 -0800 Subject: [PATCH] Implemented place-robber, pass, and steal-resource. Added SelectPlayer. Signed-off-by: James Ketrenos --- client/src/App.css | 1 + client/src/App.js | 14 ++--- client/src/GameOrder.css | 3 +- client/src/SelectPlayer.css | 53 +++++++++++++++++++ client/src/SelectPlayer.js | 84 +++++++++++++++++++++++++++++ client/src/Table.js | 35 ------------- server/routes/games.js | 102 +++++++++++++++++++++++++++++++----- 7 files changed, 232 insertions(+), 60 deletions(-) create mode 100644 client/src/SelectPlayer.css create mode 100644 client/src/SelectPlayer.js diff --git a/client/src/App.css b/client/src/App.css index 2dd8b20..585af2e 100755 --- a/client/src/App.css +++ b/client/src/App.css @@ -60,6 +60,7 @@ body { } .Table .Game { + position: relative; display: flex; flex-direction: column; flex-grow: 1; diff --git a/client/src/App.js b/client/src/App.js index 5e8fcb1..3ffb29d 100755 --- a/client/src/App.js +++ b/client/src/App.js @@ -19,6 +19,7 @@ import { Actions } from "./Actions.js"; import { base, gamesPath } from './Common.js'; import { GameOrder } from "./GameOrder.js"; import { Activities } from "./Activities.js"; +import { SelectPlayer } from "./SelectPlayer.js"; import history from "./history.js"; import "./App.css"; @@ -291,10 +292,10 @@ const Table = () => { } { warning &&
{ warning }
} + { state === 'normal' && } + { color && state === 'game-order' && } + - { color && state === 'game-order' && - - } { /* state === 'winner' && @@ -311,12 +312,7 @@ const Table = () => { { isTurn && turn && turn.actions && game.turn.actions.indexOf('select-resources') !== -1 && - } - - { game.state === 'normal' && - turn && isTurn && turn.actions && turn.actions.indexOf('steal-resource') !== -1 && - - */ } + */ }
todo: player's hand
diff --git a/client/src/GameOrder.css b/client/src/GameOrder.css index 62384e5..7a0bbed 100644 --- a/client/src/GameOrder.css +++ b/client/src/GameOrder.css @@ -2,13 +2,12 @@ display: flex; position: absolute; left: 0; - right: 30vw; + right: 0; bottom: 0; top: 0; justify-content: center; align-items: center; z-index: 1000; - max-height: 100vh; overflow: auto; } diff --git a/client/src/SelectPlayer.css b/client/src/SelectPlayer.css new file mode 100644 index 0000000..27b6e4f --- /dev/null +++ b/client/src/SelectPlayer.css @@ -0,0 +1,53 @@ +.SelectPlayer { + display: flex; + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + justify-content: center; + align-items: center; + overflow: auto; + background-color: #40404020; + z-index: 10000; +} + +.SelectPlayer .Title { + align-self: center; + padding: 2px; + font-weight: bold; +} + +.SelectPlayer .SelectPlayerList { + display: flex; + flex-direction: column; + justify-content: flex-start; + padding: 0.5em; + background-color:rgba(224, 224, 224); + margin: 0.5em 0; +} + +.SelectPlayer > * { + width: 20em; + display: inline-flex; + padding: 0.5em; + flex-direction: column; +} + +.SelectPlayer .PlayerColor { + width: 1em; + height: 1em; +} + +.SelectPlayer .SelectPlayerItem { + display: flex; + flex-direction: row; + width: 100%; + align-items: center; + padding: 2px 0; + cursor: pointer; +} + +.SelectPlayer > * { + margin: 0 0.25em; +} diff --git a/client/src/SelectPlayer.js b/client/src/SelectPlayer.js new file mode 100644 index 0000000..b57eb25 --- /dev/null +++ b/client/src/SelectPlayer.js @@ -0,0 +1,84 @@ +import React, { useState, useEffect, useContext, useRef, useMemo } from "react"; +import Paper from '@material-ui/core/Paper'; +import equal from "fast-deep-equal"; + +import { PlayerColor } from "./PlayerColor.js"; + +import "./SelectPlayer.css"; + +import { GlobalContext } from "./GlobalContext.js"; + +const SelectPlayer = () => { + const { ws } = useContext(GlobalContext); + const [turn, setTurn] = useState(undefined); + const [color, setColor] = useState(undefined); + const fields = useMemo(() => [ + 'turn', 'color' + ], []); + + const onWsMessage = (event) => { + const data = JSON.parse(event.data); + switch (data.type) { + case 'game-update': + console.log(`select-players - game-update: `, data.update); + if ('turn' in data.update && !equal(turn, data.update.turn)) { + setTurn(data.update.turn); + } + if ('color' in data.update && data.update.color !== color) { + setColor(data.update.color); + } + break; + default: + break; + } + }; + const refWsMessage = useRef(onWsMessage); + useEffect(() => { refWsMessage.current = onWsMessage; }); + useEffect(() => { + if (!ws) { return; } + const cbMessage = e => refWsMessage.current(e); + ws.addEventListener('message', cbMessage); + return () => { ws.removeEventListener('message', cbMessage); } + }, [ws, refWsMessage]); + useEffect(() => { + if (!ws) { return; } + ws.send(JSON.stringify({ + type: 'get', + fields + })); + }, [ws, fields]); + + const playerClick = (event) => { + ws.send(JSON.stringify({ + type: 'steal-resource', + color: event.currentTarget.getAttribute('data-color') + })); + } + + if (!color || !turn || turn.color !== color || !turn.limits || !turn.limits.players) { + return (<>); + } + + const list = turn.limits.players.map(item => +
+ +
{item.name}
+
+ ); + + return ( +
+ +
Select Player to Steal From
+
+ { list } +
+
+
+ ); +}; + +export { SelectPlayer }; \ No newline at end of file diff --git a/client/src/Table.js b/client/src/Table.js index 4dbc654..d86ea7d 100755 --- a/client/src/Table.js +++ b/client/src/Table.js @@ -67,41 +67,6 @@ const StartButton = ({ table, game }) => { ); }; -const SelectPlayer = ({table, game, players}) => { - const playerClick = (event) => { - table.stealResource(event.currentTarget.getAttribute('data-color')); - } - - if (!game.id) { - return (<>); - } - - let list = players.map(color => { - let item = { - color: color, - name: getPlayerName(game.sessions, color) - }; - return
- -
{item.name}
-
; - }); - - return ( -
- { game && -
Select Player to Steal From
-
- { list } -
-
} -
- ); -}; - const PlayerName = ({table, game}) => { const [name, setName] = useState(game.name ? game.name : ""); diff --git a/server/routes/games.js b/server/routes/games.js index 25c6fac..38977fa 100755 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -246,6 +246,7 @@ const roll = (game, session) => { return `You already rolled this turn.`; } processRoll(game, session, [ Math.ceil(Math.random() * 6), Math.ceil(Math.random() * 6) ]); + sendUpdateToPlayers(game, { chat: game.chat }); return; default: @@ -361,6 +362,7 @@ const processRoll = (game, session, dice) => { players: game.players, chat: game.chat }); + return; } /* ROBBER Robber Robinson! */ @@ -1020,8 +1022,8 @@ const addChatMessage = (game, session, message) => { if (game.chat.length) { lastTime = game.chat[game.chat.length - 1].date; } - if (now === lastTime) { - now++; + if (now <= lastTime) { + now = lastTime + 1; } const entry = { @@ -1870,10 +1872,17 @@ const pass = (game, session) => { game.turns++; addActivity(game, session, `${name} passed their turn.`); addChatMessage(game, null, `It is ${next}'s turn.`); + + sendUpdateToPlayers(game, { + turn: game.turn, + chat: game.chat, + activites: game.activities + }); } -const placeRobber = (game, session, value) => { +const placeRobber = (game, session, robber) => { const name = session.name; + robber = parseInt(robber); if (game.state !== 'normal' && game.turn.roll !== 7) { return `You cannot place robber unless 7 was rolled!`; @@ -1890,7 +1899,7 @@ const placeRobber = (game, session, value) => { return `You cannot place the robber until everyone has discarded!`; } } - const robber = parseInt(value ? value : 0); + if (game.robber === robber) { return `You must move the robber to a new location!`; } @@ -1900,17 +1909,22 @@ const placeRobber = (game, session, value) => { pickRobber(game); addActivity(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`); - let colors = []; + let targets = []; layout.tiles[robber].corners.forEach(cornerIndex => { const active = game.placements.corners[cornerIndex]; - if (active && active.color && active.color !== game.turn.color && colors.indexOf(active.color) == -1) { - colors.push(active.color); + if (active && active.color + && active.color !== game.turn.color + && targets.findIndex(item => item.color === active.color) === -1) { + targets.push({ + color: active.color, + name: game.players[active.color].name + }); } }); - if (colors.length) { + if (targets.length) { game.turn.actions = [ 'steal-resource' ], - game.turn.limits = { players: colors }; + game.turn.limits = { players: targets }; } else { game.turn.actions = []; game.turn.robberInAction = false; @@ -1920,18 +1934,29 @@ const placeRobber = (game, session, value) => { `with no other players, ` + `so ${game.turn.name} does not steal resources from anyone.`); } + + sendUpdateToPlayers(game, { + placements: game.placements, + turn: game.turn, + chat: game.chat, + robber: game.robber, + robberName: game.robberName, + activities: game.activities + }); + sendUpdateToPlayer(session, { + private: game.player + }); } -const stealResource = (game, session, value) => { - const name = session.name; +const stealResource = (game, session, color) => { if (game.turn.actions.indexOf('steal-resource') === -1) { return `You can only steal a resource when it is valid to do so!`; } - if (game.turn.limits.players.indexOf(value) === -1) { + if (game.turn.limits.players.findIndex(item => item.color === color) === -1) { return `You can only steal a resource from a player on this terrain!`; } - let victim = game.players[value]; - cards = []; + const victim = game.players[color]; + const cards = []; [ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].forEach(field => { for (let i = 0; i < victim[field]; i++) { cards.push(field); @@ -1962,6 +1987,14 @@ const stealResource = (game, session, value) => { debugChat(game, 'After steal'); game.turn.robberInAction = false; + sendUpdateToPlayers(game, { + turn: game.turn, + chat: game.chat, + activities: game.activities + }); + sendUpdateToPlayer(session, { + private: game.player + }); } const buyDevelopment = (game, session, value) => { @@ -2005,6 +2038,15 @@ const buyDevelopment = (game, session, value) => { card = game.developmentCards.pop(); card.turn = game.turns; player.development.push(card); + + sendUpdateToPlayers(game, { + chat: game.chat, + activities: game.activities, + players: getFilteredPlayers(game) + }); + sendUpdateToPlayer(session, { + private: game.player + }); } const playCard = (game, session, { card }) => { @@ -2115,6 +2157,17 @@ const playCard = (game, session, { card }) => { game.turn.limits.pips.push(i); } } + + sendUpdateToPlayers(game, { + chat: game.chat, + activities: game.activities, + largestArmy: game.largestArmy, + largestArmySize: game.largestArmySize, + turn: game.turn + }); + sendUpdateToPlayer(session, { + private: game.player + }); } const placeSettlement = (game, session, index) => { @@ -3344,6 +3397,27 @@ const wsConnect = async (ws, req) => { sendWarning(session, warning); } break; + case 'place-robber': + console.log(`${short}: <- place-robber:${getName(session)} ${data.index}`); + warning = placeRobber(game, session, data.index); + if (warning) { + sendWarning(session, warning); + } + break; + case 'steal-resource': + console.log(`${short}: <- steal-resource:${getName(session)} ${data.color}`); + warning = stealResource(game, session, data.color); + if (warning) { + sendWarning(session, warning); + } + break; + case 'pass': + console.log(`${short}: <- pass:${getName(session)}`); + warning = pass(game, session); + if (warning) { + sendWarning(session, warning); + } + break; default: console.warn(`Unsupported request: ${data.type}`); break;