From 3fe70fa7392bcf5c2bcaf9daa53d9034e63bf53d Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Fri, 11 Feb 2022 17:40:22 -0800 Subject: [PATCH] House settlement is now shaped during selection Signed-off-by: James Ketrenos --- client/src/Board.css | 14 ++++++++++- client/src/Table.css | 55 ++++++++++++++++++++++++++++++++++++++++++ client/src/Table.js | 48 +++++++++++++++++++++++++++++++++++- server/routes/games.js | 52 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 166 insertions(+), 3 deletions(-) diff --git a/client/src/Board.css b/client/src/Board.css index 35c75cf..335fa3b 100644 --- a/client/src/Board.css +++ b/client/src/Board.css @@ -40,6 +40,10 @@ filter: drop-shadow(0px 0px 5px rgba(255, 255, 0, 0.9)); } +.Pip.Active.Option { + filter: brightness(150%) drop-shadow(0px 0px 5px rgba(255, 255, 0, 0.9)); +} + .Pips[disabled], .Tiles[disabled], .Roads[disabled], @@ -71,6 +75,7 @@ bottom: 0px; } +.Corner:not([data-type]) .Corner-Shape, .Corner[data-type="settlement"] .Corner-Shape { clip-path: polygon(50% 0%,70% 15%,70% 2%,90% 2%,90% 30%,100% 40%,100% 100%,65% 100%,65% 65%,35% 65%,35% 100%,0% 100%,0% 40%); } @@ -128,6 +133,13 @@ filter: brightness(150%); } +.Option .Pip-Shape, +.Option .Tile-Shape, +.Option .Corner-Shape, +.Option .Road-Shape { + background-color: rgba(255, 255, 255, 0.5); +} + .Robber .Pip-Shape, .Pip-Shape:hover { clip-path: circle(45%); /* show through the border */ @@ -140,7 +152,7 @@ .Tile-Shape:hover, .Corner-Shape:hover, .Road-Shape:hover { -/* background-color: white;*/ + background-color: white; filter: brightness(150%); } diff --git a/client/src/Table.css b/client/src/Table.css index 8873a54..d85b7af 100755 --- a/client/src/Table.css +++ b/client/src/Table.css @@ -12,6 +12,7 @@ display: flex; margin-right: 40vw; justify-content: space-between; + align-items: flex-end; } .WaitingForPlayer { @@ -81,6 +82,60 @@ margin: 0 0.25em; } +.SelectPlayer { + display: flex; + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + justify-content: center; + align-items: center; + background: rgba(0,0,0,0.5); + z-index: 1000; +} + +.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; +} + + .Display { display: inline-block; position: absolute; diff --git a/client/src/Table.js b/client/src/Table.js index 7180e97..d21d2d0 100755 --- a/client/src/Table.js +++ b/client/src/Table.js @@ -336,6 +336,41 @@ const GameOrder = ({table}) => { ); }; +const SelectPlayer = ({table, players}) => { + const playerClick = (event) => { + table.stealResource(event.currentTarget.getAttribute('data-color')); + } + + if (!table.game) { + return (<>); + } + + let list = players.map(color => { + let item = { + color: color, + name: getPlayerName(table.game.sessions, color) + }; + return
+ +
{item.name}
+
; + }); + + return ( +
+ { table.game && +
Select Player to Steal From
+
+ { list } +
+
} +
+ ); +}; + const Action = ({ table }) => { const discardClick = (event) => { const nodes = document.querySelectorAll('.Hand .Selected'), @@ -695,6 +730,10 @@ class Table extends React.Component { return this.sendAction('place-road', road); } + stealResource(color) { + return this.sendAction('steal-resource', color); + } + throwDice() { return this.rollDice(); @@ -856,7 +895,7 @@ class Table extends React.Component { message = <>{message} {name} needs to discard {discard} resources.; } } - if (move) { + if (move && (this.game.turn && !this.game.turn.placedRobber)) { message = <>{message} {this.game.turn.name} needs to move the robber. } } @@ -992,6 +1031,13 @@ class Table extends React.Component { } + { game && game.state === 'normal' && + game.turn && + game.turn.color == game.color && + game.turn.actions && game.turn.actions.indexOf('steal-resource') !== -1 && + + } + { game && game.turn && game.turn.color !== game.color && (game.state === 'initial-placement' || game.state === 'normal') && (!game.player || !game.player.mustDiscard) && diff --git a/server/routes/games.js b/server/routes/games.js index 78e3532..3eaaae9 100755 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -354,6 +354,7 @@ const processRoll = (game, dice) => { game.turn.roll = game.dice[0] + game.dice[1]; if (game.turn.roll === 7) { addChatMessage(game, null, `ROBBER! ROBBER! ROBBER!`); + delete game.turn.placedRobber; for (let id in game.sessions) { const player = game.sessions[id].player; if (player) { @@ -906,7 +907,54 @@ router.put("/:id/:action/:value?", async (req, res) => { game.robber = robber; game.turn.placedRobber = true; addChatMessage(game, session, `Robber has been moved!`); - addChatMessage(game, null, 'TODO: Look up which players are on tile, then allow robber-roller to select which player to steal from.'); + + let colors = []; + 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 (colors.length) { + game.turn.actions = [ 'steal-resource' ], + game.turn.limits = { players: colors }; + addChatMessage(game, session, `${session.name} must select player to steal resource from.`); + } else { + game.turn.actions = []; + delete game.turn.limits; + addChatMessage(game, session, `The Robber was moved to a terrain with no other players.`); + } + + break; + case 'steal-resource': + if (game.turn.actions.indexOf('steal-resource') === -1) { + error = `You can only steal a resource when it is valid to do so!`; + break; + } + if (game.turn.limits.players.indexOf(value) === -1) { + error = `You can only steal a resource from a player on this terrain!`; + break; + } + let victim = game.players[value]; + const cards = []; + [ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].forEach(field => { + for (let i = 0; i < victim[field]; i++) { + cards.push(field); + } + }); + if (cards.length === 0) { + addChatMessage(game, session, `Victim did not have any cards to steal.`); + } else { + let index = Math.floor(Math.random() * cards.length), + type = cards[index]; + victim[type]--; + session.player[type]++ + game.turn.actions = []; + game.turn.limits = {}; + addChatMessage(game, session, + `${session.name} randomly stole ${type} from ${playerNameFromColor(game, value)}.`); + } break; case 'place-settlement': if (game.state !== 'initial-placement' && game.state !== 'normal') { @@ -1157,8 +1205,10 @@ const sendGame = async (req, res, game, error) => { game.turn.limits.pips.push(i); } } else { +/* game.turn.limits = {}; game.turn.actions = []; +*/ } }