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;