1
0

Added Activity feed

Fixed some more WebSocket timeouts

Changed Resource to support a label=true mode which puts a bubble lable instead of creating a stack

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-03-01 20:19:48 -08:00
parent 2fa436081b
commit 4ff9ad015e
8 changed files with 214 additions and 81 deletions

View File

@ -18,12 +18,36 @@
.Activities .PlayerColor { .Activities .PlayerColor {
display: inline-flex; display: inline-flex;
width: 0.8em; width: 1rem;
height: 0.8em; height: 1rem;
padding: 0; padding: 0;
margin: 0; margin: 0 0.2rem;
} }
.Activities > div { .Activities > div {
padding: 0.5em; padding: 0.25rem 0.5rem;
display: flex;
align-items: center;
}
.Activity b,
.Activity .Dice {
margin-left: 0.25em;
}
.Activities > div:last-child {
border-top: 1px solid black;
}
.Activity.open{
opacity: 1;
}
.Activity.close{
animation: bounce-out 1s ease-in;
}
@keyframes bounce-out{
0% {opacity: 1; }
100% {opacity: 0; };
} }

View File

@ -1,10 +1,58 @@
import React from "react"; import React, { useState, useCallback, useEffect } from "react";
import "./Activities.css"; import "./Activities.css";
import Paper from '@material-ui/core/Paper'; import Paper from '@material-ui/core/Paper';
import Resource from './Resource.js'; import Resource from './Resource.js';
import { getPlayerName } from './Common.js'; import { getPlayerName } from './Common.js';
import PlayerColor from './PlayerColor.js'; import PlayerColor from './PlayerColor.js';
import Dice from './Dice.js';
const Activity = ({ activity }) => {
const [animation, setAnimation] = useState('open');
const [display, setDisplay] = useState(true)
const hide = async (ms) => {
await new Promise(r => setTimeout(r, ms));
setAnimation('close')
await new Promise(r => setTimeout(r, 1000));
setDisplay(false)
};
if (display) {
setTimeout(() => hide(10000), 0);
}
let message;
/* If the date is in the future, set it to now */
const dice = activity.message.match(/^(.*rolled )([1-6])(, ([1-6]))?(.*)$/);
if (dice) {
if (dice[4]) {
const sum = parseInt(dice[2]) + parseInt(dice[4]);
message = <>{dice[1]}<b>{sum}</b>: <Dice pips={dice[2]}/>, <Dice pips={dice[4]}/>{dice[5]}</>;
} else {
message = <>{dice[1]}<Dice pips={dice[2]}/>{dice[5]}</>;
}
} else {
message = activity.message; /*
let start = activity.message;
while (start) {
const resource = start.match(/^(.*)(([0-9]+) (wood|sheep|wheat|stone|brick),?)(.*)$/);
if (resource) {
const count = resource[3] ? parseInt(resource[3]) : 1;
message = <><Resource count={count} type={resource[4]}/>{resource[5]}{message}</>;
start = resource[1];
} else {
message = <>{start}{message}</>;
start = '';
}
}*/
}
return <>{ display &&
<div className={`Activity ${animation}`}>
<PlayerColor color={activity.color}/>{message}
</div>
}</>;
}
const Activities = ({ table }) => { const Activities = ({ table }) => {
if (!table.game) { if (!table.game) {
@ -14,20 +62,31 @@ const Activities = ({table }) => {
const const
game = table.game, game = table.game,
isTurn = (game.turn && game.turn.color === game.color) ? true : false, isTurn = (game.turn && game.turn.color === game.color) ? true : false,
normalPlay = (game.state === 'initial-placement' || game.state === 'normal'); normalPlay = (game.state === 'initial-placement' || game.state === 'normal'),
mustDiscard = game.player ? (parseInt(game.player.mustDiscard ? game.player.mustDiscard : 0) !== 0) : false;
const list = game.activities
.filter(activity => game.timestamp - activity.date < 11000)
.map(activity => {
return <Activity key={activity.date} activity={activity}/>;
});
return ( return (
<Paper className="Activities"> <div className="Activities">
{ !isTurn && normalPlay && (!game.player || !game.player.mustDiscard) && { list }
<div>Waiting for {table.game.turn.name} to complete their turn.</div>
{ !isTurn && normalPlay && !mustDiscard &&
<div>Waiting for <PlayerColor color={table.game.turn.color}/> {table.game.turn.name} to complete their turn.</div>
} }
{ isTurn && normalPlay && game.player && game.player.mustDiscard &&
{ isTurn && normalPlay && game.player && mustDiscard &&
<div>You must discard.</div> <div>You must discard.</div>
} }
{ isTurn && normalPlay && (!game.player || !game.player.mustDiscard) &&
<div>It is your turn.</div> { isTurn && normalPlay &&
<div><PlayerColor color={game.turn.color}/> It is your turn.</div>
} }
</Paper> </div>
); );
}; };

View File

@ -35,6 +35,7 @@
.ChatList .MuiTypography-body1 { .ChatList .MuiTypography-body1 {
font-size: 0.8rem; font-size: 0.8rem;
display: flex; display: flex;
flex-wrap: wrap;
} }
.ChatList .System .MuiTypography-body1 { .ChatList .System .MuiTypography-body1 {
@ -61,19 +62,32 @@
.ChatList .Resource { .ChatList .Resource {
display: inline-flex; display: inline-flex;
width: 3em; align-items: center;
height: 4.3em; justify-content: space-around;
height: 1.5rem;
width: 1.5rem;
min-width: 1.5rem;
min-height: 1.5rem;
pointer-events: none; pointer-events: none;
margin: 0 0.125rem;
background-size: 130%;
border: 2px solid #444;
border-radius: 2px;
margin-right: 0.5rem;
} }
.ChatList .Stack { .ChatList .Resource > div {
margin-left: 0; position: absolute;
transition: none; top: -0.625rem;
} right: -0.625rem;
border-radius: 50%;
.ChatList .Stack > *:not(:first-child) { border: 1px solid white;
margin-left: 0; background-color: rgb(36, 148, 46);
transition: none; font-size: 0.75rem;
width: 1rem;
height: 1rem;
text-align: center;
line-height: 1rem;
} }
.ChatList .Dice { .ChatList .Dice {

View File

@ -96,7 +96,7 @@ const Chat = ({ table }) => {
const resource = start.match(/^(.*)(([0-9]+) (wood|sheep|wheat|stone|brick),?)(.*)$/); const resource = start.match(/^(.*)(([0-9]+) (wood|sheep|wheat|stone|brick),?)(.*)$/);
if (resource) { if (resource) {
const count = resource[3] ? parseInt(resource[3]) : 1; const count = resource[3] ? parseInt(resource[3]) : 1;
message = <><Resource count={count} type={resource[4]}/>{resource[5]}{message}</>; message = <><Resource label={true} count={count} type={resource[4]}/>{resource[5]}{message}</>;
start = resource[1]; start = resource[1];
} else { } else {
message = <>{start}{message}</>; message = <>{start}{message}</>;

View File

@ -8,6 +8,11 @@
background-size: cover; background-size: cover;
margin: 0.25em; margin: 0.25em;
cursor: pointer; cursor: pointer;
display: inline-flex;
justify-content: space-around;
align-items: center;
color: white;
font-weight: bold;
} }
.Resource:hover { .Resource:hover {

View File

@ -2,13 +2,23 @@ import React from "react";
import "./Resource.css"; import "./Resource.css";
import { assetsPath } from './Common.js'; import { assetsPath } from './Common.js';
const Resource = ({ type, select, disabled, count }) => { const Resource = ({ type, select, disabled, count, label }) => {
const array = new Array(Number(count ? count : 0)); const array = new Array(Number(count ? count : 0));
const click = select ? select : (event) => { const click = select ? select : (event) => {
if (!disabled) { if (!disabled) {
event.target.classList.toggle('Selected'); event.target.classList.toggle('Selected');
} }
}; };
if (label) {
return <div className="Resource"
data-type={type}
onClick={click}
style={{backgroundImage:`url(${assetsPath}/gfx/card-${type}.png)`}}>
<div>{count}</div>
</div>;
}
return ( return (
<> <>
{ array.length > 0 && { array.length > 0 &&

View File

@ -266,6 +266,7 @@ const Action = ({ table }) => {
const game = table.game, const game = table.game,
inLobby = game.state === 'lobby', inLobby = game.state === 'lobby',
inGame = game.state === 'normal',
player = game ? game.player : undefined, player = game ? game.player : undefined,
hasRolled = (game && game.turn && game.turn.roll) ? true : false, hasRolled = (game && game.turn && game.turn.roll) ? true : false,
isTurn = (game && game.turn && game.turn.color === game.color) ? true : false, isTurn = (game && game.turn && game.turn.color === game.color) ? true : false,
@ -279,7 +280,7 @@ const Action = ({ table }) => {
<Button disabled={game.color ? false : true} onClick={newTableClick}>New table</Button> <Button disabled={game.color ? false : true} onClick={newTableClick}>New table</Button>
<Button disabled={game.color ? true : false} onClick={() => {table.setState({ pickName: true})}}>Change name</Button> </> } <Button disabled={game.color ? true : false} onClick={() => {table.setState({ pickName: true})}}>Change name</Button> </> }
{ !inLobby && <> { !inLobby && <>
<Button disabled={robberActions || !isTurn || hasRolled} onClick={rollClick}>Roll Dice</Button> <Button disabled={robberActions || !isTurn || hasRolled || !inGame} onClick={rollClick}>Roll Dice</Button>
<Button disabled={robberActions || !isTurn || !hasRolled || !haveResources} onClick={tradeClick}>Trade</Button> <Button disabled={robberActions || !isTurn || !hasRolled || !haveResources} onClick={tradeClick}>Trade</Button>
<Button disabled={robberActions || !isTurn || !hasRolled || !haveResources} onClick={buildClicked}>Build</Button> <Button disabled={robberActions || !isTurn || !hasRolled || !haveResources} onClick={buildClicked}>Build</Button>
{ game.turn.roll === 7 && player && player.mustDiscard > 0 && { game.turn.roll === 7 && player && player.mustDiscard > 0 &&
@ -734,30 +735,33 @@ class Table extends React.Component {
} }
resetKeepAlive(isDead) { resetKeepAlive(isDead) {
if (isDead) {
console.log(`Short circuiting keep-alive`);
} else {
console.log(`Resetting keep-alive`);
}
if (this.keepAlive) { if (this.keepAlive) {
clearTimeout(this.keepAlive); clearTimeout(this.keepAlive);
this.keepAlive = 0; this.keepAlive = 0;
} else {
console.log(`No keep-alive active`);
} }
this.keepAlive = setTimeout(() => {
console.error(`No server ping after 10 seconds (or connection closed by server)!`);
this.setState({ noNetwork: true });
if (this.ws) {
this.ws.close();
}
this.connectWebSocket();
}, isDead ? 3000 : 10000);
if (this.state.noNetwork !== false && !isDead) { if (this.state.noNetwork !== false && !isDead) {
this.setState({ noNetwork: false }); this.setState({ noNetwork: false });
} else if (this.state.noNetwork !== true && isDead) { } else if (this.state.noNetwork !== true && isDead) {
this.setState({ noNetwork: true }); this.setState({ noNetwork: true });
} }
this.keepAlive = setTimeout(() => {
console.error(`No server ping!`);
this.setState({ noNetwork: true });
if (this.ws) {
this.ws.close();
}
if (!this.websocketReconnect) {
this.websocketReconnect = setTimeout(() => {
delete this.websocketReconnect;
this.connectWebSocket();
}, 1000);
}
}, isDead ? 1000 : 5000);
} }
connectWebSocket() { connectWebSocket() {
@ -907,10 +911,6 @@ class Table extends React.Component {
clearTimeout(this.keepAlive); clearTimeout(this.keepAlive);
this.keepAlive = 0; this.keepAlive = 0;
} }
if (this.websocketReconnect) {
clearTimeout(this.websocketReconnect);
this.websocketReconnect = 0;
}
if (this.updateSizeTimer) { if (this.updateSizeTimer) {
clearTimeout(this.updateSizeTimer); clearTimeout(this.updateSizeTimer);
this.updateSizeTimer = 0; this.updateSizeTimer = 0;

View File

@ -365,7 +365,7 @@ const processRoll = (game, dice) => {
return; return;
} }
game.dice = dice; game.dice = dice;
addChatMessage(game, session, `${session.name} rolled ${game.dice[0]}, ${game.dice[1]}.`); addActivity(game, session, `${session.name} rolled ${game.dice[0]}, ${game.dice[1]}.`);
game.turn.roll = game.dice[0] + game.dice[1]; game.turn.roll = game.dice[0] + game.dice[1];
if (game.turn.roll === 7) { if (game.turn.roll === 7) {
game.turn.robberInAction = true; game.turn.robberInAction = true;
@ -388,7 +388,7 @@ const processRoll = (game, dice) => {
if (mustDiscard.length === 0) { if (mustDiscard.length === 0) {
addChatMessage(game, null, `ROBBER! ${game.robberName} Robber Roberson has fled, and no one had to discard!`); addChatMessage(game, null, `ROBBER! ${game.robberName} Robber Roberson has fled, and no one had to discard!`);
addChatMessage(game, null, `But drat! A new robber has arrived and must be placed by ${game.turn.name}.`); addChatMessage(game, null, `A new robber has arrived and must be placed by ${game.turn.name}.`);
game.turn.actions = [ 'place-robber' ]; game.turn.actions = [ 'place-robber' ];
game.turn.limits = { pips: [] }; game.turn.limits = { pips: [] };
for (let i = 0; i < 19; i++) { for (let i = 0; i < 19; i++) {
@ -677,7 +677,7 @@ const adminActions = (game, action, value) => {
case 'game-order': case 'game-order':
game.dice = dice; game.dice = dice;
message = `${game.turn.name} rolled ${game.dice[0]}.`; message = `${game.turn.name} rolled ${game.dice[0]}.`;
addChatMessage(game, session, message); addActivity(game, session, message);
message = undefined; message = undefined;
processGameOrder(game, session.player, game.dice[0]); processGameOrder(game, session.player, game.dice[0]);
break; break;
@ -717,7 +717,7 @@ const adminActions = (game, action, value) => {
continue; continue;
} }
console.log(`Kicking ${value} from ${game.id}.`); console.log(`Kicking ${value} from ${game.id}.`);
const preamble = session.name ? `${session.name}, playing as ${color},` : color; const preamble = session.name ? `${session.name}, playing as ${colorToWord(color)},` : colorToWord(color);
addChatMessage(game, null, `${preamble} was kicked from game by the Admin.`); addChatMessage(game, null, `${preamble} was kicked from game by the Admin.`);
if (player) { if (player) {
session.player = undefined; session.player = undefined;
@ -726,7 +726,7 @@ const adminActions = (game, action, value) => {
session.color = undefined; session.color = undefined;
return; return;
} }
return `Unable to find active session for ${color} (${value})`; return `Unable to find active session for ${colorToWord(color)} (${value})`;
default: default:
return `Invalid admin action ${action}.`; return `Invalid admin action ${action}.`;
@ -774,6 +774,17 @@ const setPlayerName = (game, session, name) => {
return undefined; return undefined;
} }
const colorToWord = (color) => {
switch (color) {
case 'O': return 'orange';
case 'W': return 'white';
case 'B': return 'blue';
case 'R': return 'red';
default:
return undefined;
}
}
const setPlayerColor = (game, session, color) => { const setPlayerColor = (game, session, color) => {
if (!game) { if (!game) {
return `No game found`; return `No game found`;
@ -793,10 +804,10 @@ const setPlayerColor = (game, session, color) => {
/* Deselect currently active player for this session */ /* Deselect currently active player for this session */
clearPlayer(player); clearPlayer(player);
if (game.state !== 'lobby') { if (game.state !== 'lobby') {
message = `${name} has exited to the lobby and is no longer playing as ${session.color}.` message = `${name} has exited to the lobby and is no longer playing as ${colorToWord(session.color)}.`
addChatMessage(game, null, message); addChatMessage(game, null, message);
} else { } else {
message = `${name} is no longer ${session.color}.`; message = `${name} is no longer ${colorToWord(session.color)}.`;
} }
session.player = undefined; session.player = undefined;
session.color = undefined; session.color = undefined;
@ -824,7 +835,7 @@ const setPlayerColor = (game, session, color) => {
for (let key in game.sessions) { for (let key in game.sessions) {
const tmp = game.sessions[key].player; const tmp = game.sessions[key].player;
if (tmp && tmp.color === color) { if (tmp && tmp.color === color) {
return `${game.sessions[key].name} already has ${color}`; return `${game.sessions[key].name} already has ${colorToWord(color)}`;
} }
} }
@ -834,7 +845,7 @@ const setPlayerColor = (game, session, color) => {
session.player.status = `Active`; session.player.status = `Active`;
session.player.lastActive = Date.now(); session.player.lastActive = Date.now();
session.color = color; session.color = color;
addChatMessage(game, session, `${session.name} has chosen to play as ${color}.`); addChatMessage(game, session, `${session.name} has chosen to play as ${colorToWord(color)}.`);
const afterActive = getActiveCount(game); const afterActive = getActiveCount(game);
if (afterActive !== priorActive) { if (afterActive !== priorActive) {
@ -845,6 +856,14 @@ const setPlayerColor = (game, session, color) => {
} }
}; };
const addActivity = (game, session, message) => {
let date = Date.now();
if (game.activities.length && game.activities[game.activities.length - 1].date === date) {
date++;
}
game.activities.push({ color: session.color, message, date });
}
const addChatMessage = (game, session, message) => { const addChatMessage = (game, session, message) => {
game.chat.push({ game.chat.push({
from: session ? session.name : undefined, from: session ? session.name : undefined,
@ -1521,7 +1540,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
game.players[key].gets = []; game.players[key].gets = [];
delete game.players[key].offerRejected; delete game.players[key].offerRejected;
} }
addChatMessage(game, session, `${name} requested to begin trading negotiations.`); addActivity(game, session, `${name} requested to begin trading negotiations.`);
break; break;
} }
@ -1534,7 +1553,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
} }
game.turn.actions = []; game.turn.actions = [];
game.turn.limits = {}; game.turn.limits = {};
addChatMessage(game, session, `${name} has cancelled trading negotiations.`); addActivity(game, session, `${name} has cancelled trading negotiations.`);
break; break;
} }
@ -1564,14 +1583,14 @@ router.put("/:id/:action/:value?", async (req, res) => {
} }
game.turn.offer = offer; game.turn.offer = offer;
} }
addChatMessage(game, session, `${session.name} submitted an offer to give ${offerToString(offer)}.`); // addActivity(game, session, `${session.name} submitted an offer to give ${offerToString(offer)}.`);
break; break;
} }
/* Any player can reject an offer */ /* Any player can reject an offer */
if (value === 'reject') { if (value === 'reject') {
session.player.offerRejected = true; session.player.offerRejected = true;
addChatMessage(game, session, `${session.name} rejected ${game.turn.name}'s offer.`); addActivity(game, session, `${session.name} rejected ${game.turn.name}'s offer.`);
break; break;
} }
@ -1699,7 +1718,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
color: getColorFromName(game, next) color: getColorFromName(game, next)
}; };
game.turns++; game.turns++;
addChatMessage(game, session, `${name} passed their turn.`); addActivity(game, session, `${name} passed their turn.`);
addChatMessage(game, null, `It is ${next}'s turn.`); addChatMessage(game, null, `It is ${next}'s turn.`);
break; break;
@ -1774,7 +1793,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
debugChat(game, 'Before steal'); debugChat(game, 'Before steal');
if (cards.length === 0) { if (cards.length === 0) {
addChatMessage(game, session, `${playerNameFromColor(game, value)} did not have any cards to steal.`); addActivity(game, session, `${playerNameFromColor(game, value)} did not have any cards to steal.`);
game.turn.actions = []; game.turn.actions = [];
game.turn.limits = {}; game.turn.limits = {};
} else { } else {
@ -1824,7 +1843,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
} }
debugChat(game, 'Before development purchase'); debugChat(game, 'Before development purchase');
addChatMessage(game, session, `${session.name} purchased a development card.`); addActivity(game, session, `${session.name} purchased a development card.`);
player.stone--; player.stone--;
player.wheat--; player.wheat--;
player.sheep--; player.sheep--;
@ -1882,29 +1901,29 @@ router.put("/:id/:action/:value?", async (req, res) => {
error = `You can not play victory point cards until you can reach 10!`; error = `You can not play victory point cards until you can reach 10!`;
break; break;
} }
addChatMessage(game, session, `${session.name} played a Victory Point card.`); addActivity(game, session, `${session.name} played a Victory Point card.`);
} }
if (card.type === 'progress') { if (card.type === 'progress') {
switch (card.card) { switch (card.card) {
case 'road-1': case 'road-1':
case 'road-2': case 'road-2':
addChatMessage(game, session, `${session.name} played a Road Building card. The server is giving them 2 brick and 2 wood to build those roads!`); addActivity(game, session, `${session.name} played a Road Building card. The server is giving them 2 brick and 2 wood to build those roads!`);
player.brick += 2; player.brick += 2;
player.wood += 2; player.wood += 2;
break; break;
case 'monopoly': case 'monopoly':
game.turn.actions = [ 'select-resource' ]; game.turn.actions = [ 'select-resource' ];
game.turn.active = 'monopoly'; game.turn.active = 'monopoly';
addChatMessage(game, session, `${session.name} played the Monopoly card, and is selecting their resource type to claim.`); addActivity(game, session, `${session.name} played the Monopoly card, and is selecting their resource type to claim.`);
break; break;
case 'year-of-plenty': case 'year-of-plenty':
game.turn.actions = [ 'select-resource' ]; game.turn.actions = [ 'select-resource' ];
game.turn.active = 'year-of-plenty'; game.turn.active = 'year-of-plenty';
addChatMessage(game, session, `${session.name} played the Year of Plenty card.`); addActivity(game, session, `${session.name} played the Year of Plenty card.`);
break; break;
default: default:
addChatMessage(game, session, `Oh no! ${card.card} isn't impmented yet!`); addActivity(game, session, `Oh no! ${card.card} isn't impmented yet!`);
break; break;
} }
} }
@ -1913,7 +1932,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
if (card.type === 'army') { if (card.type === 'army') {
player.army++; player.army++;
addChatMessage(game, session, `${session.name} played a Kaniget!`); addActivity(game, session, `${session.name} played a Kaniget!`);
if (player.army > 2 && if (player.army > 2 &&
(!game.largestArmy || game.players[game.largestArmy].army < player.army)) { (!game.largestArmy || game.players[game.largestArmy].army < player.army)) {
@ -1967,7 +1986,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
if (error) { if (error) {
break; break;
} }
addChatMessage(game, session, `${session.name} has chosen ${type}!`); addActivity(game, session, `${session.name} has chosen ${type}!`);
switch (game.turn.active) { switch (game.turn.active) {
case 'monopoly': case 'monopoly':
@ -1992,7 +2011,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
if (gave.length) { if (gave.length) {
addChatMessage(game, session, `Players ${gave.join(', ')}. In total, ${session.name} received ${total} ${type}.`); addChatMessage(game, session, `Players ${gave.join(', ')}. In total, ${session.name} received ${total} ${type}.`);
} else { } else {
addChatMessage(game, session, 'No players had that resource. Wa-waaaa.'); addActivity(game, session, 'No players had that resource. Wa-waaaa.');
} }
break; break;
@ -2038,7 +2057,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
break; break;
} }
placeSettlement(game, corners); placeSettlement(game, corners);
addChatMessage(game, session, `${game.turn.name} is considering placing a settlement.`); addActivity(game, session, `${game.turn.name} is considering placing a settlement.`);
break; break;
case 'place-settlement': case 'place-settlement':
@ -2118,10 +2137,10 @@ router.put("/:id/:action/:value?", async (req, res) => {
game.turn.actions = []; game.turn.actions = [];
game.turn.limits = {}; game.turn.limits = {};
if (bankType) { if (bankType) {
addChatMessage(game, session, addActivity(game, session,
`${name} placed a settlement by a maritime bank that trades ${bankType}.`); `${name} placed a settlement by a maritime bank that trades ${bankType}.`);
} else { } else {
addChatMessage(game, session, `${name} placed a settlement.`); addActivity(game, session, `${name} placed a settlement.`);
} }
calculateRoadLengths(game, session); calculateRoadLengths(game, session);
} else if (game.state === 'initial-placement') { } else if (game.state === 'initial-placement') {
@ -2151,11 +2170,11 @@ router.put("/:id/:action/:value?", async (req, res) => {
} }
player.settlements--; player.settlements--;
if (bankType) { if (bankType) {
addChatMessage(game, session, addActivity(game, session,
`${name} placed a settlement by a maritime bank that trades ${bankType}. ` + `${name} placed a settlement by a maritime bank that trades ${bankType}. ` +
`Next, they need to place a road.`); `Next, they need to place a road.`);
} else { } else {
addChatMessage(game, session, `${name} placed a settlement. ` + addActivity(game, session, `${name} placed a settlement. ` +
`Next, they need to place a road.`); `Next, they need to place a road.`);
} }
placeRoad(game, layout.corners[index].roads); placeRoad(game, layout.corners[index].roads);
@ -2195,7 +2214,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
break; break;
} }
placeCity(game, corners); placeCity(game, corners);
addChatMessage(game, session, `${game.turn.name} is considering upgrading a settlement to a city.`); addActivity(game, session, `${game.turn.name} is considering upgrading a settlement to a city.`);
break; break;
case 'place-city': case 'place-city':
@ -2252,7 +2271,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
debugChat(game, 'After city purchase'); debugChat(game, 'After city purchase');
game.turn.actions = []; game.turn.actions = [];
game.turn.limits = {}; game.turn.limits = {};
addChatMessage(game, session, `${name} upgraded a settlement to a city!`); addActivity(game, session, `${name} upgraded a settlement to a city!`);
break; break;
case 'buy-road': case 'buy-road':
@ -2288,7 +2307,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
break; break;
} }
placeRoad(game, roads); placeRoad(game, roads);
addChatMessage(game, session, `${game.turn.name} is considering building a road.`); addActivity(game, session, `${game.turn.name} is considering building a road.`);
break; break;
case 'place-road': case 'place-road':
@ -2340,12 +2359,12 @@ router.put("/:id/:action/:value?", async (req, res) => {
road.color = session.color; road.color = session.color;
game.turn.actions = []; game.turn.actions = [];
game.turn.limits = {}; game.turn.limits = {};
addChatMessage(game, session, `${name} placed a road.`); addActivity(game, session, `${name} placed a road.`);
calculateRoadLengths(game, session); calculateRoadLengths(game, session);
} else if (game.state === 'initial-placement') { } else if (game.state === 'initial-placement') {
road.color = session.color; road.color = session.color;
addChatMessage(game, session, `${name} placed a road.`); addActivity(game, session, `${name} placed a road.`);
calculateRoadLengths(game, session); calculateRoadLengths(game, session);
let next; let next;
@ -2402,7 +2421,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
player[type] += receives[type]; player[type] += receives[type];
message.push(`${receives[type]} ${type}`); message.push(`${receives[type]} ${type}`);
} }
addChatMessage(game, session, `${session.name} receives ${message.join(', ')}.`); addActivity(game, session, `${session.name} receives ${message.join(', ')}.`);
} }
} }
addChatMessage(game, null, `It is ${name}'s turn.`); addChatMessage(game, null, `It is ${name}'s turn.`);
@ -2491,6 +2510,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
const ping = (session) => { const ping = (session) => {
session.ping = Date.now(); session.ping = Date.now();
console.log(`Sending ping to ${session.name}`);
session.ws.send(JSON.stringify({ type: 'ping', ping: session.ping })); session.ws.send(JSON.stringify({ type: 'ping', ping: session.ping }));
if (session.keepAlive) { if (session.keepAlive) {
clearTimeout(session.keepAlive); clearTimeout(session.keepAlive);
@ -2783,6 +2803,7 @@ const resetGame = (game) => {
}, },
developmentCards: [], developmentCards: [],
chat: [], chat: [],
activities: [],
pipOrder: game.pipOrder, pipOrder: game.pipOrder,
borderOrder: game.borderOrder, borderOrder: game.borderOrder,
tileOrder: game.tileOrder, tileOrder: game.tileOrder,