diff --git a/client/src/Activities.js b/client/src/Activities.js index 21cc54c..c1de151 100644 --- a/client/src/Activities.js +++ b/client/src/Activities.js @@ -140,8 +140,10 @@ const Activities = () => { placement = (state === 'initial-placement' || (turn && turn.active === 'road-building')), placeRoad = placement && turn && turn.actions && turn.actions.indexOf('place-road') !== -1, mustStealResource = turn && turn.actions && turn.actions.indexOf('steal-resource') !== -1, - rollForVolcano = (isTurn && state === 'volcano'), - rollForOrder = (state === 'game-order'); + rollForVolcano = (isTurn && state === 'volcano' && turn && !turn.select), + rollForOrder = (state === 'game-order'), + selectResources = turn && turn.actions && turn.actions.indexOf('select-resources') !== -1; + console.log(`activities - `, state, turn, activities); let discarders = [], mustDiscard = false; for (let key in players) { @@ -161,13 +163,24 @@ console.log(`activities - `, state, turn, activities); }); let who; - if (isTurn) { - who = 'You'; + if (turn && turn.select) { + const selecting = []; + for (let key in turn.select) { + selecting.push({ + color: key, + name: color === key ? 'You' : players[key].name}); + } + who = selecting.map((player, index) => + <>{ player.name }{ index !== selecting.length - 1 ? ', ' : '' }); } else { - if (!turn || !turn.name) { - who = 'Everyone'; + if (isTurn) { + who = 'You'; } else { - who = <> {turn.name} + if (!turn || !turn.name) { + who = 'Everyone'; + } else { + who = <> {turn.name} + } } } @@ -190,10 +203,14 @@ console.log(`activities - `, state, turn, activities);
{who} must roll for game order.
} - {rollForVolcano && + { rollForVolcano &&
{who} must roll for Volcano devastation!
} + { selectResources && +
{who} must select resources!
+ } + { normalPlay && mustDiscard && <> { discarders } } { !isTurn && normalPlay && turn && diff --git a/client/src/App.css b/client/src/App.css index d2e13a1..a653e88 100755 --- a/client/src/App.css +++ b/client/src/App.css @@ -68,10 +68,6 @@ body { background-color: #00000060; } -.Table .PlayersStatus { - z-index: 5000; -} - .Table .Game { position: relative; display: flex; diff --git a/client/src/App.js b/client/src/App.js index 260d76c..daccbd6 100755 --- a/client/src/App.js +++ b/client/src/App.js @@ -31,6 +31,17 @@ import { Dice } from "./Dice.js"; import history from "./history.js"; import "./App.css"; import equal from "fast-deep-equal"; +/* +const Pip = () => { +
+} +*/ const Table = () => { const params = useParams(); diff --git a/client/src/Board.js b/client/src/Board.js index 79bbef8..7d97c37 100644 --- a/client/src/Board.js +++ b/client/src/Board.js @@ -1,5 +1,4 @@ -import React, { useEffect, useState, useContext, useRef, useMemo, - useCallback } from "react"; +import React, { useEffect, useState, useContext, useRef, useMemo } from "react"; import equal from "fast-deep-equal"; import { assetsPath } from "./Common.js"; import "./Board.css"; @@ -510,20 +509,23 @@ const Board = () => { const tile = Object.assign({}, tiles[order], { index: index++, left: x, top: y}); - if ('volcano' in rules - && rules[`volcano`].enabled - && tile.type === 'desert') { - tile.type = 'volcano'; - tile.card = 0; - } + const volcanoActive = 'volcano' in rules + && rules[`volcano`].enabled; + if ('tiles-start-facing-down' in rules && rules[`tiles-start-facing-down`].enabled && state !== 'normal' && state !== 'volcano' - && state !== 'winner') { + && state !== 'winner' + && (volcanoActive && tile.type !== 'desert')) { tile.type = 'jungle'; tile.card = 0; } + if (volcanoActive + && tile.type === 'desert') { + tile.type = 'volcano'; + tile.card = 0; + } let div = { if (resource) { const count = resource[3] ? parseInt(resource[3]) : 1; message = <>{resource[5]}{message}; + type={resource[4]} disabled/>{resource[5]}{message}; start = resource[1]; } else { message = <>{start}{message}; @@ -169,7 +169,7 @@ const Chat = () => { } Date.now() ? + secondary={item.color && Date.now() ? Date.now() : item.date} interval={1000}/>} /> ); @@ -188,10 +188,11 @@ const Chat = () => { Game duration: } + date={startTime}/>} variant="outlined"/> ); diff --git a/client/src/ChooseCard.js b/client/src/ChooseCard.js index 63d33a6..ddbe513 100644 --- a/client/src/ChooseCard.js +++ b/client/src/ChooseCard.js @@ -80,8 +80,6 @@ const ChooseCard = () => { } const selectCard = useCallback((event) => { - event.target.classList.toggle('Selected'); - const selected = document.querySelectorAll('.ChooseCard .Selected'); if (selected.length > count) { for (let i = 0; i < selected.length; i++) { diff --git a/client/src/Common.js b/client/src/Common.js index a37125d..21a79f3 100644 --- a/client/src/Common.js +++ b/client/src/Common.js @@ -1,14 +1,4 @@ -const getPlayerName = (sessions, color) => { - for (let i = 0; i < sessions.length; i++) { - const session = sessions[i]; - if (session.color === color) { - return session.name; - } - } - return null; -} - function debounce(fn, ms) { let timer; return _ => { @@ -25,4 +15,4 @@ const base = process.env.PUBLIC_URL; const assetsPath = `${base}/assets`; const gamesPath = `${base}`; -export { base, debounce, assetsPath, gamesPath, getPlayerName }; \ No newline at end of file +export { base, debounce, assetsPath, gamesPath }; \ No newline at end of file diff --git a/client/src/Hand.css b/client/src/Hand.css index 64d6928..be3bf60 100644 --- a/client/src/Hand.css +++ b/client/src/Hand.css @@ -11,6 +11,20 @@ flex-shrink: 1; } +.Hand .CardsSelected { + display: flex; + position: absolute; + bottom: 1rem; + left: 2rem; + padding: 0.25rem 0.5rem; + border-radius: 0.25rem; + background-color: white; + border: 2px solid black; + z-index: 500; /* above cards */ + pointer-events: none; + opacity: 0.75; +} + .Hand .CardGroup { display: flex; min-height: calc(7.2em + 0.5em); diff --git a/client/src/Hand.js b/client/src/Hand.js index a8d369f..9c6cda1 100644 --- a/client/src/Hand.js +++ b/client/src/Hand.js @@ -27,6 +27,7 @@ const Hand = ({buildActive, setBuildActive, setCardActive}) => { const [development, setDevelopment] = useState([]); const [mostPorts, setMostPorts] = useState(undefined); const [mostDeveloped, setMostDeveloped] = useState(undefined); + const [selected, setSelected] = useState(0); const fields = useMemo(() => [ 'private', 'turn', 'color', 'longestRoad', 'largestArmy', 'mostPorts', 'mostDeveloped' @@ -115,18 +116,35 @@ const Hand = ({buildActive, setBuildActive, setCardActive}) => { } setDevelopment(development); }, [priv, setDevelopment, setCardActive]); - + + useEffect(() => { + const count = document.querySelectorAll('.Hand .CardGroup .Selected'); + if (count.length !== selected) { + setSelected(count.length); + } + }, [setSelected, selected]); + if (!priv) { return <>; } + const cardSelected = (event) => { + const count = document.querySelectorAll('.Hand .CardGroup .Selected'); + setSelected(count.length); + } + + return
-
- - - - - + {
+ {selected} cards selected +
} +
+ + + + +
{ development } diff --git a/client/src/PlayersStatus.css b/client/src/PlayersStatus.css index d8adf42..dffae0e 100644 --- a/client/src/PlayersStatus.css +++ b/client/src/PlayersStatus.css @@ -19,7 +19,7 @@ align-items: flex-start; pointer-events: all; right: auto; - bottom: 7rem; /* 1rem over top of Resource cards in hand */ + bottom: 8rem; /* 1rem over top of Resource cards in hand */ } .PlayersStatus .Player:not(:last-child) { diff --git a/client/src/Resource.js b/client/src/Resource.js index 88924cf..db0b18b 100644 --- a/client/src/Resource.js +++ b/client/src/Resource.js @@ -2,19 +2,22 @@ import React from "react"; import "./Resource.css"; import { assetsPath } from './Common.js'; -const Resource = ({ type, select, disabled, available, count, label, onClick }) => { +const Resource = ({ type, disabled, available, count, label, onClick }) => { const array = new Array(Number(count ? count : 0)); - const click = select ? select : (event) => { + const click = (event) => { if (!disabled) { event.target.classList.toggle('Selected'); } + if (onClick) { + onClick(event); + } }; if (label) { return
{ available !== undefined &&
{available}
}
{count}
@@ -29,7 +32,7 @@ const Resource = ({ type, select, disabled, available, count, label, onClick })
)) } diff --git a/client/src/Trade.js b/client/src/Trade.js index 1c9e524..fafee08 100644 --- a/client/src/Trade.js +++ b/client/src/Trade.js @@ -104,12 +104,14 @@ const Trade = () => { onClick={() => transfer(resource, 'get')} label={true} type={resource} + disabled count={gets[resource]}/>
{ gets[resource] === gives[resource] ? '' : (gets[resource] > gives[resource] ? : )}
transfer(resource, 'give')} label={true} type={resource} + disabled available={priv ? priv[resource] - gives[resource] : undefined} count={gives[resource]}/>
; diff --git a/client/src/Winner.js b/client/src/Winner.js index c8ca94e..d962418 100644 --- a/client/src/Winner.js +++ b/client/src/Winner.js @@ -105,7 +105,7 @@ const Winner = ({ winnerDismissed, setWinnerDismissed }) => { } const count = stats.robber.stole[type]; robber = <>{robber} - + ; } robber =
@@ -137,7 +137,7 @@ const Winner = ({ winnerDismissed, setWinnerDismissed }) => { } const count = stats[player].stolen[type]; stolen = <>{stolen} - + ; } if (stolen) { diff --git a/server/routes/games.js b/server/routes/games.js index 95cc776..6a74239 100755 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -391,7 +391,7 @@ const distributeResources = (game, roll) => { } if (session) { - addChatMessage(game, session, `${session.name} receives ${message.join(', ')}.`); + addChatMessage(game, session, `${session.name} receives ${message.join(', ')} for pip ${roll}.`); } } @@ -476,7 +476,6 @@ const processRoll = (game, session, dice) => { game.turn.select = {}; const volcano = layout.tiles.find((tile, index) => staticData.tiles[game.tileOrder[index]].type === 'desert'); - console.log({ mode: 'gold', volcano }); volcano.corners.forEach(index => { const corner = game.placements.corners[index]; if (corner.color) { @@ -488,9 +487,11 @@ const processRoll = (game, session, dice) => { count += corner.type === 'settlement' ? 1 : 2; } }); - + console.log(`Volcano! - `, { + mode: 'gold', + selected: game.turn.select + }); if (count) { - game.turn.actions = [ 'select-resources' ]; /* To gain volcano resources, you need at least 3 settlements, * so Robin Hood Robber does not apply */ if (volcano === layout.tiles[game.robber]) { @@ -499,6 +500,7 @@ const processRoll = (game, session, dice) => { delete game.turn.select; } else { addChatMessage(game, null, `House rule 'Volcanoes have minerals' activated. Players must select which resources to receive from the Volcano!`); + game.turn.actions = ['select-resources']; game.turn.active = 'volcano'; } } else { @@ -521,7 +523,8 @@ const processRoll = (game, session, dice) => { turn: game.turn, players: getFilteredPlayers(game), chat: game.chat, - dice: game.dice + dice: game.dice, + state: game.state }); return; } @@ -804,11 +807,10 @@ const adminActions = (game, action, value, query) => { if (session.player.cities === 0) { return `Player ${game.turn.name} does not have any more cities to give.`; } - corners = getValidCorners(game, session.color); + corners = getValidCorners(game, session.color, 'settlement'); if (corners.length === 0) { return `There are no valid locations for ${game.turn.name} to place a settlement.`; } - corners = getValidCorners(game, session.color, 'settlement'); game.turn.free = true; setForCityPlacement(game, corners); addChatMessage(game, null, `Admin gave a city to ${game.turn.name}. ` + @@ -2766,7 +2768,7 @@ const placeRoad = (game, session, index) => { }); message.push(`${receives[type]} ${type}`); } - addChatMessage(game, session, `${session.name} receives ${message.join(', ')}.`); + addChatMessage(game, session, `${session.name} receives ${message.join(', ')} for initial settlement placement.`); } } addChatMessage(game, null, `It is ${session.name}'s turn.`); @@ -3005,6 +3007,7 @@ const selectResources = (game, session, cards) => { count = 1; } if (game.state === 'volcano') { + console.log({ cards, turn: game.turn }); if (!game.turn.select) { count = 0; } else if (session.color in game.turn.select) { @@ -3052,8 +3055,6 @@ const selectResources = (game, session, cards) => { display.push(`${selected[card]} ${card}`); } - addActivity(game, session, `${session.name} has chosen ${display.join(', ')}!`); - switch (game.turn.active) { case 'monopoly': const gave = [], type = cards[0]; @@ -3084,10 +3085,11 @@ const selectResources = (game, session, cards) => { } if (gave.length) { - addChatMessage(game, session, `${session.name} player Monopoly and selected ${display.join(', ')}. ` + + addChatMessage(game, session, `${session.name} played Monopoly and selected ${display.join(', ')}. ` + `Players ${gave.join(', ')}. In total, they received ${total} ${type}.`); } else { - addActivity(game, session, 'No players had that resource. Wa-waaaa.'); + + addActivity(game, session, `${session.name} has chosen ${display.join(', ')}! Unfortunately, no players had that resource. Wa-waaaa.`); } delete game.turn.active; game.turn.actions = []; @@ -4039,6 +4041,25 @@ router.ws("/ws/:id", async (ws, req) => { case 'turn': case 'turns': case 'winner': + case 'placements': + case 'longestRoadLength': + case 'robber': + case 'robberName': + case 'pips': + case 'pipsOrder': + case 'borders': + case 'tileOrder': + case 'active': + case 'largestArmy': + case 'mostDeveloped': + case 'mostPorts': + case 'longestRoad': + case 'tiles': + case 'pipOrder': + case 'signature': + case 'borderOrder': + case 'dice': + case 'activities': update[field] = game[field]; break; case 'rules':