diff --git a/client/src/Activities.js b/client/src/Activities.js index 722a9ff..5843ff4 100644 --- a/client/src/Activities.js +++ b/client/src/Activities.js @@ -129,7 +129,7 @@ const Activities = () => { })); }, [ws, fields]); - if (!timestamp || !color) { + if (!timestamp) { return <>; } diff --git a/client/src/App.js b/client/src/App.js index 83fc084..5afa60f 100755 --- a/client/src/App.js +++ b/client/src/App.js @@ -33,7 +33,7 @@ import { Sheep } from "./Sheep.js"; import history from "./history.js"; import "./App.css"; import equal from "fast-deep-equal"; -import { purple } from "@material-ui/core/colors"; + /* const Pip = () => {
{ switch (data.type) { case 'game-update': console.log(`chat - game update`); - if (data.update.chat && data.update.chat.length !== chat.length) { + if (data.update.chat && !equal(data.update.chat, chat)) { console.log(`chat - game update - ${data.update.chat.length} lines`); setChat(data.update.chat); } @@ -163,7 +164,7 @@ const Chat = () => { } return ( - { item.color && diff --git a/client/src/PlayersStatus.js b/client/src/PlayersStatus.js index 663cddf..7a42416 100644 --- a/client/src/PlayersStatus.js +++ b/client/src/PlayersStatus.js @@ -11,7 +11,7 @@ import { GlobalContext } from './GlobalContext.js'; const Player = ({ player, onClick, reverse, color, largestArmy, isSelf, longestRoad, mostPorts, mostDeveloped }) => { if (!player) { - return <>; + return <>You are an observer.; } const developmentCards = player.unplayed diff --git a/client/src/Sheep.js b/client/src/Sheep.js index 866a96f..052b5c7 100644 --- a/client/src/Sheep.js +++ b/client/src/Sheep.js @@ -69,6 +69,7 @@ const Sheep = ({ radius, speed, size, style }) => { return
{ ws.on('headers', headers); ws.on('close', close); ws.on('error', error); - ws.on('message', (data) => { message(ws, data); }); + ws.on('message', async (data) => { await message(ws, data); }); }); }; @@ -144,7 +144,8 @@ const tryBuild = (ws) => { ws.send(JSON.stringify(data)); }; let trying = false; - if (game.private.wood + if (game.private.settlements + && game.private.wood && game.private.brick && game.private.sheep && game.private.wheat) { @@ -154,7 +155,7 @@ const tryBuild = (ws) => { trying = true; } - if (game.private.wood && game.private.brick) { + if (game.private.wood && game.private.brick && game.private.roads) { send({ type: 'buy-road' }); @@ -164,7 +165,14 @@ const tryBuild = (ws) => { return trying; }; -const message = (ws, data) => { + +const sleep = async (delay) => { + return new Promise((resolve) => { + setTimeout(resolve, delay); + }); +}; + +const message = async (ws, data) => { const send = (data) => { console.log(`ws - send: ${data.type}`); ws.send(JSON.stringify(data)); @@ -173,14 +181,14 @@ const message = (ws, data) => { data = JSON.parse(data); switch (data.type) { case 'game-update': + + Object.assign(game, data.update); + delete data.update.chat; + delete data.update.activities; console.log(`ws - receive - `, - Object.assign({}, data.update, { - activities: 'filtered out', - chat: 'filtered out' - }) + data.update ); - Object.assign(game, data.update); console.log(`state - ${game.state}`); switch (game.state) { @@ -196,15 +204,16 @@ const message = (ws, data) => { } console.log(`game-order - `, { color: game.color, - players: game.players + players: game.players }); - if (!game.players[game.color].orderRoll) { + if (!game.players[game.color].orderRoll || game.players[game.color].tied) { console.log(`Time to roll as ${game.color}`); send({ type: 'roll' }); } break; case 'initial-placement': { + await sleep(1000 + Math.random() * 500); console.log({ color: game.color, state: game.state, turn: game.turn }); if (game.turn.color !== game.color) { break; @@ -228,9 +237,46 @@ const message = (ws, data) => { } break; case 'normal': + if (game.players[game.color].mustDiscard) { + await sleep(1000 + Math.random() * 500); + let mustDiscard = game.players[game.color].mustDiscard; + if (!mustDiscard) { + return; + } + const cards = [], + discards = {}; + const types = ['wheat', 'sheep', 'stone', 'brick', 'wood']; + types.forEach(type => { + for (let i = 0; i < game.private[type]; i++) { + cards.push(type); + } + }); + while (mustDiscard--) { + const type = cards[Math.floor(Math.random() * cards.length)]; + if (!(type in discards)) { + discards[type] = 1; + } else { + discards[type]++; + } + } + console.log(`discarding - `, discards); + send({ + type: 'discard', + discards + }); + return; + } + + if (game.turn.color !== game.color) { + console.log(`not ${name}'s turn.`) + return; + } + + await sleep(1000 + Math.random() * 500); if (game.turn.color !== game.color) { return; } + if (game.turn.actions && game.turn.actions.indexOf('place-road') !== -1) { index = game.turn.limits.roads[Math.floor( Math.random() * game.turn.limits.roads.length)]; @@ -258,32 +304,6 @@ const message = (ws, data) => { return; } - if (game.private.mustDiscard) { - let mustDiscard = game.private.mustDiscard; - const cards = [], - discards = {}; - const types = ['wheat', 'sheep', 'stone', 'brick', 'wood']; - types.forEach(type => { - for (let i = 0; i < game.private[type]; i++) { - cards.push(type); - } - }); - while (mustDiscard--) { - const type = cards[Math.floor(Math.random() * cards.length)]; - if (!(type in discards)) { - discards[type] = 1; - } else { - discards[type]++; - } - } - console.log(`discarding - `, discards); - send({ - type: 'discard', - discards - }); - return; - } - if (game.turn.actions && game.turn.actions.indexOf('place-robber') !== -1) { console.log({ pips: game.turn.limits.pips }); @@ -297,6 +317,10 @@ const message = (ws, data) => { } if (game.turn.actions && game.turn.actions.indexOf('steal-resource') !== -1) { + if (!game.turn.limits.players) { + console.warn(`No players in limits with steal-resource`); + return; + } const { color } = game.turn.limits.players[Math.floor(Math.random() * game.turn.limits.players.length)]; console.log(`stealing resouce from ${game.players[color].name}`); send({ diff --git a/server/routes/games.js b/server/routes/games.js index 011b4da..883472c 100755 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -970,6 +970,15 @@ const adminCommands = (game, action, value, query) => { return `Not enough players in game to start.`; } game.state = 'game-order'; + /* Delete any non-played colors from the player map; reduces all + * code that would otherwise have to filter out players by checking + * the 'Not active' state of player.status */ + for (let key in game.players) { + if (game.players[key].status !== 'Active') { + delete game.players[key]; + } + } + addChatMessage(game, null, `Admin requested to start the game.`); break; default: @@ -1128,7 +1137,7 @@ const setPlayerColor = (game, session, color) => { /* Verify selection is not already taken */ if (color && game.players[color].status !== 'Not active') { - return `${game.sessions[color].name} already has ${colorToWord(color)}`; + return `${game.players[color].name} already has ${colorToWord(color)}`; } let active = getActiveCount(game); @@ -1218,6 +1227,9 @@ const addActivity = (game, session, message) => { date++; } game.activities.push({ color: session ? session.color : '', message, date }); + if (game.activities.length > 30) { + game.activities.splice(0, game.activities.length - 30); + } } const addChatMessage = (game, session, message, isNormalChat) => { @@ -1244,6 +1256,9 @@ const addChatMessage = (game, session, message, isNormalChat) => { entry.color = session.color; } game.chat.push(entry); + if (game.chat.length > 50) { + game.chat.splice(0, game.chat.length - 50); + } }; const getColorFromName = (game, name) => { @@ -2953,11 +2968,10 @@ const discard = (game, session, discards) => { if (sum > player.mustDiscard) { return `You can not discard that many cards! You can only discard ${player.mustDiscard}.`; } - /* - if (sum !== player.mustDiscard) { - return `You need to discard ${player.mustDiscard} cards.`; + + if (sum === 0) { + return `You must discard at least one card.`; } - */ for (let type in discards) { const count = parseInt(discards[type]); @@ -3506,11 +3520,13 @@ const saveGame = async (game) => { /* Save per turn while debugging... */ game.step = game.step ? game.step : 0; + /* await writeFile(`games/${game.id}.${game.step++}`, JSON.stringify(reducedGame, null, 2)) .catch((error) => { console.error(`${session.id} Unable to write to games/${game.id}`); console.error(error); }); + */ await writeFile(`games/${game.id}`, JSON.stringify(reducedGame, null, 2)) .catch((error) => { console.error(`${session.id} Unable to write to games/${game.id}`); @@ -3718,6 +3734,9 @@ const getFilteredPlayers = (game) => { const player = Object.assign({}, game.players[color]); filtered[color] = player; if (player.status === 'Not active') { + if (game.state !== 'lobby') { + delete filtered[color]; + } continue; } player.resources = 0;