1
0

Fixed lots of trading bugs

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-03-05 16:29:48 -08:00
parent 1345e1a658
commit 315d55ad72
5 changed files with 267 additions and 183 deletions

View File

@ -36,6 +36,7 @@
font-size: 0.8rem;
display: flex;
flex-wrap: wrap;
align-items: center;
}
.ChatList .System .MuiTypography-body1 {

View File

@ -274,8 +274,7 @@ const Action = ({ table }) => {
robberActions = (game && game.turn && game.turn.robberInAction),
haveResources = player ? player.haveResources : false,
placement = (game.state === 'initial-placement' || game.turn.active === 'road-building'),
placeRoad = placement && game.turn && game.turn.actions && game.turn.actions.indexOf('place-road') !== -1,
mustStealResource = game.turn && game.turn.actions && game.turn.actions.indexOf('steal-resource') !== -1;
placeRoad = placement && game.turn && game.turn.actions && game.turn.actions.indexOf('place-road') !== -1;
return (
<Paper className="Action">
@ -793,12 +792,6 @@ class Table extends React.Component {
this.ws = new WebSocket(new_uri);
this.lastPing = this.game.timestamp;
this.ws.addEventListener('open', (event) => {
console.log(`${this.game.name} WebSocket open: Sending game-update request: ${(Date.now() - this.lastPing) / 1000}`);
this.ws.send(JSON.stringify({ type: 'game-update' }));
this.resetKeepAlive();
});
this.ws.addEventListener('message', (event) => {
this.resetKeepAlive();
@ -840,6 +833,13 @@ class Table extends React.Component {
this.setState({ error: event.message });
this.resetKeepAlive(true);
});
this.ws.addEventListener('open', (event) => {
console.log(`${this.game.name} WebSocket open: Sending game-update request: ${(Date.now() - this.lastPing) / 1000}`);
this.ws.send(JSON.stringify({ type: 'game-update' }));
this.resetKeepAlive();
});
}
componentDidMount() {

View File

@ -103,9 +103,10 @@
}
.Trade .PlayerColor {
width: 0.5em;
height: 0.5em;
margin: 0 0.25em 0 0;
align-self: flex-start;
width: 0.75em;
height: 0.75em;
margin: 1rem 0.25em 0 0;
}
.Trade .Transfer {
@ -121,6 +122,15 @@
justify-items: flex-start;
}
.Trade .Transfers .GiveGet {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
font-weight: bold;
font-size: 1.5rem;
}
.Trade .TradeLine {
width: 100%;
user-select: none;
@ -137,13 +147,18 @@
flex-direction: row;
align-items: center;
}
/*
.Trade .TradeLine > div {
.Trade .TradeText > span {
display: inline-flex;
align-items: center;
margin-right: 0.25rem;
width: 100%;
flex-wrap: wrap;
}
.Trade .TradeText > span:first-of-type {
min-height: 3.5rem;
}
*/
.Trade .TradeLine .Resource {
height: 1.5rem;

View File

@ -7,6 +7,7 @@ import Button from '@material-ui/core/Button';
import Resource from './Resource.js';
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'
import { alertClasses } from "@mui/material";
const empty = {
wheat: 0,
@ -93,22 +94,53 @@ const Trade = ({table}) => {
setGets(Object.assign({}, empty, _gets));
}, [setGives, setGets, gives, gets, table]);
let transfers = [];
transfers = [ 'brick', 'wood', 'wheat', 'sheep', 'stone' ].map(resource => { return createTransfer(resource); });
if (!table.game || !player || !table.game.player) {
return <></>;
}
const transfers = [ 'brick', 'wood', 'wheat', 'sheep', 'stone' ].map(resource => { return createTransfer(resource); });
player.offerRejected = player.offerRejected ? player.offerRejected: {};
const canMeetOffer = (player, offer) => {
if (offer.gets.length === 0 || offer.gives.length === 0) {
console.log(`no length`);
return false;
}
for (let i = 0; i < offer.gets.length; i++) {
const get = offer.gets[i];
if (get.type === 'bank') {
if (player[player.gives[0].type] < get.count) {
if (offer.name === 'The bank') {
const _gives = [], _gets = [];
for (let type in gives) {
if (gives[type] > 0) {
_gives.push({ type, count: gives[type] });
}
}
for (let type in gets) {
if (gets[type] > 0) {
_gets.push({ type, count: gets[type] });
}
}
if (_gives.length !== 1 || _gets.length !== 1) {
return false;
}
if (_gives[0].count < get.count) {
return false;
}
if (get.type !== 'bank') {
if (gives[get.type] < get.count) {
return false;
}
}
if (_gets[0].count !== 1) {
return false;
}
} else if (player[get.type] < get.count) {
console.log(`cannot meet count`);
return false;
}
}
@ -172,7 +204,13 @@ const Trade = ({table}) => {
}
const acceptClicked = (offer) => {
table.acceptTrade(offer);
if (offer.name === 'The bank') {
table.acceptTrade(Object.assign({}, { name: offer.name, gives: trade.gets, gets: trade.gives }));
} else if (offer.self) {
table.acceptTrade(offer);
} else {
table.acceptTrade(Object.assign({}, offer, { gives: offer.gets, gets: offer.gives }));
}
};
const cancelClicked = (event) => {
@ -190,22 +228,19 @@ const Trade = ({table}) => {
for (let color in table.game.players) {
const item = table.game.players[color],
name = getPlayerName(table.game.sessions, color);
item.offerRejected = item.offerRejected ? item.offerRejected : {};
if (item.status !== 'Active') {
continue;
}
/* Only list players with an offer, unless it is the active player (see
* that you haven't submitted an offer) or the current turn player,
* or the player explicitly rejected the player's offer */
if (table.game.turn.name !== name && table.game.name !== name &&
!item.offerRejected &&
(!item.gets || item.gets.length === 0
|| !item.gives || item.gives.length === 0)) {
if (table.game.turn.name !== name && table.game.name !== name
&& !(color in player.offerRejected)
&& (!item.gets || item.gets.length === 0 || !item.gives || item.gives.length === 0)) {
continue;
}
/* If the active player already rejected this offer, hide it */
if (table.game.turn.name === name && item.negotiatorRejectedOffer) {
continue;
}
const tmp = {
self: table.game.name === name,
name: name,
@ -213,10 +248,11 @@ const Trade = ({table}) => {
valid: false,
gets: item.gets ? item.gets : [],
gives: item.gives ? item.gives : [],
offerRejected: (table.game.turn.name !== name) ? (item.offerRejected ? true : false) : false,
negotiatorRejectedOffer: item.negotiatorRejectedOffer
offerRejected: item.offerRejected,
};
tmp.canSubmit = (tmp.gets.length && tmp.gives.length);
players.push(tmp);
}
@ -238,7 +274,7 @@ const Trade = ({table}) => {
const isOfferSubmitted = isCompatibleOffer(table.game.player, trade),
isNegiatorSubmitted = table.game.turn && table.game.turn.offer && isCompatibleOffer(table.game.player, table.game.turn.offer),
isOfferValid = trade.gives.length && trade.gets.length;
isOfferValid = trade.gives.length && trade.gets.length ? true : false;
if (isTurn && table.game.player && table.game.player.banks) {
table.game.player.banks.forEach(bank => {
@ -248,7 +284,8 @@ const Trade = ({table}) => {
color: undefined,
gives: [ { count: 1, type: '*' } ],
gets: [ { count: count, type: bank } ],
valid: false
valid: false,
offerRejected: {}
});
});
@ -257,39 +294,40 @@ const Trade = ({table}) => {
color: undefined,
gives: [ { count: 1, type: '*' } ],
gets: [ { count: 4, type: 'bank' } ],
valid: false
valid: false,
offerRejected: {}
});
}
if (table.game.turn.offer) {
if (isTurn) {
players.forEach(trade => trade.valid = canMeetOffer(player, trade));
} else {
const found = players.find(item => item.name === table.game.turn.name);
if (found) {
found.valid = canMeetOffer(player, table.game.turn.offer);
}
if (isTurn) {
players.forEach(offer => offer.valid = !(table.game.turn.color in offer.offerRejected) && canMeetOffer(player, offer));
} else {
const found = players.find(item => item.name === table.game.turn.name);
if (found) {
found.valid = !(table.game.color in found.offerRejected) && canMeetOffer(player, found);
}
}
players = players.map((item, index) => {
/*
if (item.negotiatorRejectedOffer && isTurn) {
return <></>;
}
*/
let youWereRejected = item.negotiatorRejectedOffer;
let youRejectedOffer;
if (isTurn && !item.self) {
youRejectedOffer = item.negotiatorRejectedOffer;
youWereRejected = item.offerRejected;
const youRejectedOffer = table.game.color in item.offerRejected;
let youWereRejected;
if (isTurn) {
youWereRejected = item.color && item.color in player.offerRejected;
} else {
youRejectedOffer = player.offerRejected;
youWereRejected = Object.getOwnPropertyNames(player.offerRejected).length !== 0;
}
const isNewOffer = item.self && !isOfferSubmitted;
let isSameOffer;
const isBank = (item.name === 'The bank');
let isNewOffer = item.self && !isOfferSubmitted;
console.log(`Trade from ${item.name} is new self: ${item.self}, new offer: ${isNewOffer}`);
if (isTurn) {
isSameOffer = isCompatibleOffer(player, item);
} else {
isSameOffer = table.game.turn.offer &&
isCompatibleOffer(player, table.game.turn.offer);
}
let source;
if (item.self) {
@ -302,46 +340,63 @@ const Trade = ({table}) => {
} else {
source = item;
}
const _gets = source.gets.length ? source.gets.map((get, index) => <div key={`get-${get.type}-${index}`}>
{ get.type === 'bank' && <div key={`get-bank-${index}`}><b>4</b> of any resource </div>}
const _gets = source.gets.length ? source.gets.map((get, index) => <>
{ get.type === 'bank' && <span key={`get-bank-${index}`}><b>4</b> of any resource </span>}
{ get.type !== 'bank' && <Resource key={`get-${get.type}-${index}`} disabled label type={get.type} count={get.count}/> }
</div>) : 'nothing',
_gives = source.gives.length ? source.gives.map((give, index) => <div key={`give-${give.type}-${index}`}>
{ give.type === '*' && <><b>1</b> of any resource </>}
{ give.type !== '*' && <Resource disabled label type={give.type} count={give.count}/> }
</div>) : 'nothing';
</>) : 'nothing',
_gives = source.gives.length ? source.gives.map((give, index) => <>
{ give.type === '*' && <span key={`give-bank-${index}`}><b>1</b> of any resource </span>}
{ give.type !== '*' && <Resource key={`give-${give.type}-${index}`} disabled label type={give.type} count={give.count}/> }
</>) : 'nothing';
return (
<div className="TradeLine" key={`player-${item.name}-${index}`}>
<PlayerColor color={item.color}/>
<div className="TradeText">
{ item.self && <>
{ youWereRejected && !isNewOffer && <>Your offer was rejected.&nbsp;</> }
{ (!youWereRejected || isNewOffer) && (_gets !== 'nothing' || _gives !== 'nothing') && <>
You want {_gets} and will give {_gives}.&nbsp;
</> }
{ !youWereRejected && _gets === 'nothing' && _gives === 'nothing' && <>
You have not started a trade offer.&nbsp;
</>}
{ (_gets !== 'nothing' || _gives !== 'nothing') && <span>
You want {_gets} and will give {_gives}.
</span> }
{ youWereRejected && !isNewOffer && <span>
{ table.game.turn.name } rejected your offer.
</span> }
{ !youWereRejected && _gets === 'nothing' && _gives === 'nothing' && <span>
You have not s a trade offer.
</span>}
{ !isTurn && isSameOffer && isOfferValid && _gets !== 'nothing' && _gives !== 'nothing' && <span style={{fontWeight: 'bold'}}>
Your submitted offer agrees with {table.game.turn.name}'s terms.
</span> }
</> }
{ !item.self && <>
{ !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && <>
{item.name} wants {_gets} and will give {_gives}.&nbsp;
</> }
{ (!isTurn || !isSameOffer || isBank) && !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && <span>
{item.name} wants {_gets} and will give {_gives}.
</span> }
{ (_gets === 'nothing' || _gives === 'nothing') &&
<>{item.name} has not submitted a trade offer.&nbsp;</>
}
{ !isBank && <>
{ isTurn && !isSameOffer && isOfferValid && _gets !== 'nothing' && _gives !== 'nothing' && <span style={{fontWeight: 'bold'}}>
This is a counter offer.
</span> }
{ youRejectedOffer && <>
You rejected {item.name}'s offer.&nbsp;
</> }
{ isTurn && isSameOffer && !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && <span>
{item.name} will meet your terms.
</span> }
{ youWereRejected && <>
{item.name} rejected your offer.&nbsp;
</>}
{ (_gets === 'nothing' || _gives === 'nothing') && <span>
{item.name} has not submitted a trade offer.
</span> }
{ youRejectedOffer && <span>
You rejected {item.name}'s offer.
</span> }
{ isTurn && youWereRejected && <span>
{ item.name} rejected your offer.
</span> }
</> }
</>}
</div>
<div className="TradeActions">
@ -383,11 +438,12 @@ const Trade = ({table}) => {
{ players }
</div>
{ !player.haveResources && <b>You have no resources to participate in this trade.</b> }
<Button
<Button disabled={isOfferSubmitted || !isOfferValid}
onClick={offerClicked}>Offer</Button>
{ player.haveResources &&
<div className="Transfers">
<div className="GiveGet"><div>Give</div><div>Get</div></div>
{ transfers }
</div>
}

View File

@ -222,7 +222,7 @@ const processGameOrder = (game, player, dice) => {
color: getPlayerColor(game, players[0])
};
placeSettlement(game, getValidCorners(game));
addChatMessage(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`);
addActivity(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`);
addChatMessage(game, null, `Initial settlement placement has started!`);
message = `It is ${game.turn.name}'s turn to place a settlement.`;
} else {
@ -302,9 +302,9 @@ const distributeResources = (session, game, roll) => {
let index = game.pipOrder[i];
if (staticData.pips[index].roll === roll) {
if (game.robber === i) {
addChatMessage(game, null, `That pesky ${game.robberName} Roberson stole resources!`);
tiles.push({ robber: true, index: i });
} else {
tiles.push(i);
tiles.push({ robber: false, index: i });
}
}
}
@ -316,35 +316,54 @@ const distributeResources = (session, game, roll) => {
"R": { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
"W": { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
"B": { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
"robber": { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 }
};
/* Find which corners are on each tile */
tiles.forEach(index => {
let shuffle = game.tileOrder[index];
console.log(index, game.tiles[shuffle]);
tiles.forEach(tile => {
let shuffle = game.tileOrder[tile.index];
const resource = game.tiles[shuffle];
layout.tiles[index].corners.forEach(cornerIndex => {
console.log(tile.index, resource);
layout.tiles[tile.index].corners.forEach(cornerIndex => {
const active = game.placements.corners[cornerIndex];
if (active && active.color) {
receives[active.color][resource.type] += active.type === 'settlement' ? 1 : 2;
if (!tile.robber) {
receives[active.color][resource.type] += active.type === 'settlement' ? 1 : 2;
} else {
receives.robber[resource.type] += active.type === 'settlement' ? 1 : 2;
}
}
})
});
const robber = [];
for (let color in receives) {
const entry = receives[color];
if (!entry.wood && !entry.brick && !entry.sheep && !entry.wheat && !entry.stone) {
continue;
}
let message = [];
for (let type in receives[color]) {
const player = playerFromColor(game, color);
player[type] += receives[color][type];
if (receives[color][type]) {
message.push(`${receives[color][type]} ${type}`);
for (let type in entry) {
if (entry[type] === 0) {
continue;
}
if (color !== 'robber') {
const player = playerFromColor(game, color);
player[type] += entry[type];
message.push(`${entry[type]} ${type}`);
} else {
robber.push(`${entry[type]} ${type}`);
}
}
addChatMessage(game, sessionFromColor(game, color), `${playerNameFromColor(game, color)} receives ${message.join(', ')}.`);
if (color !== 'robber') {
addChatMessage(game, sessionFromColor(game, color), `${playerNameFromColor(game, color)} receives ${message.join(', ')}.`);
}
}
if (robber.length) {
addChatMessage(game, null, `That pesky ${game.robberName} Robber Roberson stole ${robber.join(', ')}!`);
}
}
@ -375,7 +394,7 @@ const processRoll = (game, dice) => {
return;
}
game.dice = dice;
addActivity(game, session, `${session.name} rolled ${game.dice[0]}, ${game.dice[1]}.`);
addChatMessage(game, session, `${session.name} rolled ${game.dice[0]}, ${game.dice[1]}.`);
game.turn.roll = game.dice[0] + game.dice[1];
if (game.turn.roll === 7) {
game.turn.robberInAction = true;
@ -898,7 +917,7 @@ const addActivity = (game, session, message) => {
if (game.activities.length && game.activities[game.activities.length - 1].date === date) {
date++;
}
game.activities.push({ color: session.color, message, date });
game.activities.push({ color: session ? session.color : undefined, message, date });
}
const addChatMessage = (game, session, message) => {
@ -1308,21 +1327,7 @@ const getValidRoads = (game, color) => {
return limits;
}
const canMeetOffer = (player, offer) => {
for (let i = 0; i < offer.gets.length; i++) {
const get = offer.gets[i];
if (get.type === 'bank') {
if (player[player.gives[0].type] < get.count) {
return false;
}
} else if (player[get.type] < get.count) {
return false;
}
}
return true;
};
const isCompatibleOffer = (game, player, offer) => {
const isCompatibleOffer = (player, offer) => {
const isBank = offer.name === 'The bank';
let valid = player.gets.length === offer.gives.length &&
player.gives.length === offer.gets.length;
@ -1332,8 +1337,8 @@ const isCompatibleOffer = (game, player, offer) => {
return false;
}
console.log({
player: getPlayerName(game, player),
console.log({
player: 'Submitting player',
gets: player.gets,
gives: player.gives
}, {
@ -1393,13 +1398,14 @@ const isSameOffer = (player, offer) => {
return same;
};
/* Verifies player can make the offer */
/* Verifies player can meet the offer */
const checkPlayerOffer = (game, player, offer) => {
let error = undefined;
const name = getPlayerName(game, player);
console.log({
console.log({ checkPlayerOffer: {
name: name,
player: player,
gets: offer.gets,
gives: offer.gives,
sheep: player.sheep,
@ -1407,7 +1413,8 @@ const checkPlayerOffer = (game, player, offer) => {
brick: player.brick,
stone: player.stone,
wood: player.wood,
});
description: offerToString(offer)
} });
offer.gives.forEach(give => {
if (!error) {
@ -1442,6 +1449,20 @@ const checkPlayerOffer = (game, player, offer) => {
return error;
};
const canMeetOffer = (player, offer) => {
for (let i = 0; i < offer.gets.length; i++) {
const get = offer.gets[i];
if (get.type === 'bank') {
if (player[player.gives[0].type] < get.count) {
return false;
}
} else if (player[get.type] < get.count) {
return false;
}
}
return true;
};
const gameSignature = (game) => {
if (!game) {
return "";
@ -1591,7 +1612,6 @@ router.put("/:id/:action/:value?", async (req, res) => {
game.players[key].gives = [];
game.players[key].gets = [];
delete game.players[key].offerRejected;
delete game.players[key].negotiatorRejectedOffer;
}
addActivity(game, session, `${name} requested to begin trading negotiations.`);
break;
@ -1627,19 +1647,31 @@ router.put("/:id/:action/:value?", async (req, res) => {
session.player.gives = offer.gives;
session.player.gets = offer.gets;
/* This offer is new for the negotiator, but don't clear the flag indicating
* if this player regected the negotiator's offer */
/* delete session.player.offerRejected; */
delete session.player.negotiatorRejectedOffer;
if (game.turn.name === name) {
/* This is a new offer from the active player -- reset everyone's
* 'offerRejected' flag */
for (let key in game.players) {
delete game.players[key].offerRejected;
}
session.player.offerRejected = {};
if (game.turn.color === session.color) {
game.turn.offer = offer;
}
/* If this offer matches what another player wants, clear rejection
* on of that other player's offer */
for (let color in game.players) {
if (color === session.color) {
continue;
}
const other = game.players[color];
if (other.status !== 'Active') {
continue;
}
/* Comparison reverses give/get order */
if (isSameOffer(other, { gives: offer.gets, gets: offer.gives }) && other.offerRejected) {
console.log('clear rejection', other, offer);
delete other.offerRejected[session.color];
} else {
console.log('do not clear rejection', other, offer);
}
}
addActivity(game, session, `${session.name} submitted an offer to give ${offerToString(offer)}.`);
break;
}
@ -1649,20 +1681,13 @@ router.put("/:id/:action/:value?", async (req, res) => {
const offer = req.body;
/* If the active player rejected an offer, they rejected another player */
if (game.turn.name === name) {
console.log(`Rejected `, offer);
const other = playerFromName(game, offer.name);
if (other) {
other.negotiatorRejectedOffer = true;
} else {
console.log(`Could not find ${offer.name}`);
}
addActivity(game, session, `${session.name} rejected ${offer.name}'s offer.`);
} else {
session.player.offerRejected = true;
addActivity(game, session, `${session.name} rejected ${game.turn.name}'s offer.`);
const other = playerFromName(game, offer.name);
if (!other.offerRejected) {
other.offerRejected = {};
}
other.offerRejected[session.color] = true;
addActivity(game, session, `${session.name} rejected ${offer.name}'s offer.`);
break;
}
@ -1676,7 +1701,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
const offer = req.body;
let target;
console.log(offer);
console.log({ offer, description: offerToString(offer) });
error = checkPlayerOffer(game, session.player, offer);
if (error) {
@ -1688,31 +1713,26 @@ router.put("/:id/:action/:value?", async (req, res) => {
if (!offer.name || offer.name !== 'The bank') {
let mismatch = false;
target = game.players[offer.color];
offer.gives.forEach(item => {
const isOffered = target.gives.find(
match => match.type === item.type && match.count === item.count);
if (!isOffered) {
mismatch = true;
}
});
offer.gets.forEach(item => {
const isOffered = target.gets.find(
match => match.type === item.type && match.count === item.count);
if (!isOffered) {
mismatch = true;
}
});
if (mismatch) {
if (offer.color in target.offerRejected) {
error = `${getPlayerName(game, target)} rejected this offer.`;
break;
}
if (!isCompatibleOffer(target, offer)) {
error = `Unfortunately, trades were re-negotiated in transit and the deal is invalid!`;
break;
}
error = checkPlayerOffer(game, target, offer);
error = checkPlayerOffer(game, target, { gives: offer.gets, gets: offer.gives });
if (error) {
break;
}
if (!isSameOffer(target, { gives: offer.gets, gets: offer.gives })) {
console.log( { target, offer });
error = `These terms were not agreed to by ${getPlayerName(game, target)}!`;
break;
}
if (!canMeetOffer(target, player)) {
error = `${playerNameFromColor(game, offer.color)} cannot meet the terms.`;
break;
@ -1721,24 +1741,16 @@ router.put("/:id/:action/:value?", async (req, res) => {
target = offer;
}
/* Verify the requesting offer wasn't jacked --\
* make sure the target.gives === player.gets and target.gives === player.gets */
if (!canMeetOffer(player, target)) {
error = `You cannot meet these terms!`;
break;
}
debugChat(game, 'Before trade');
/* Transfer goods */
player.gets.forEach(item => {
offer.gets.forEach(item => {
if (target.name !== 'The bank') {
target[item.type] -= item.count;
}
player[item.type] += item.count;
});
player.gives.forEach(item => {
offer.gives.forEach(item => {
if (target.name !== 'The bank') {
target[item.type] += item.count;
}
@ -1747,7 +1759,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
const from = (offer.name === 'The bank') ? 'the bank' : offer.name;
addChatMessage(game, session, `${session.name} traded ` +
` ${offerToString(session.player)} ` +
` ${offerToString(offer)} ` +
`from ${from}.`);
addActivity(game, session, `${session.name} accepted a trade from ${from}.`)
delete game.turn.offer;
@ -1836,7 +1848,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
game.turn.placedRobber = true;
pickRobber(game);
addChatMessage(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`);
addActivity(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`);
let colors = [];
layout.tiles[robber].corners.forEach(cornerIndex => {
@ -1997,18 +2009,18 @@ router.put("/:id/:action/:value?", async (req, res) => {
case 'road-2':
const allowed = Math.min(player.roads, 2);
if (!allowed) {
addActivity(game, session, `${session.name} played a Road Building card, but has no roads to build.`);
addChatMessage(game, session, `${session.name} played a Road Building card, but has no roads to build.`);
break;
}
let roads = getValidRoads(game, session.color);
if (roads.length === 0) {
addActivity(game, session, `${session.name} played a Road Building card, but they do not have any valid locations to place them.`);
addChatMessage(game, session, `${session.name} played a Road Building card, but they do not have any valid locations to place them.`);
break;
}
game.turn.active = 'road-building';
game.turn.free = true;
game.turn.freeRoads = allowed;
addActivity(game, session, `${session.name} played a Road Building card. They now place ${allowed} roads for free.`);
addChatMessage(game, session, `${session.name} played a Road Building card. They now place ${allowed} roads for free.`);
placeRoad(game, roads);
break;
case 'monopoly':
@ -2031,7 +2043,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
if (card.type === 'army') {
player.army++;
addActivity(game, session, `${session.name} played a Kaniget!`);
addChatMessage(game, session, `${session.name} played a Knight and must move the robber!`);
if (player.army > 2 &&
(!game.largestArmy || game.players[game.largestArmy].army < player.army)) {
@ -2669,7 +2681,7 @@ const ping = (session) => {
}
session.ping = Date.now();
console.log(`Sending ping to ${session.name}`);
// console.log(`Sending ping to ${session.name}`);
session.ws.send(JSON.stringify({ type: 'ping', ping: session.ping }));
if (session.keepAlive) {
clearTimeout(session.keepAlive);
@ -2749,7 +2761,7 @@ router.ws("/ws/:id", async (ws, req) => {
const data = JSON.parse(message);
switch (data.type) {
case 'pong':
console.log(`Latency for ${session.name ? session.name : 'Unammed'} is ${Date.now() - data.timestamp}`);
// console.log(`Latency for ${session.name ? session.name : 'Unammed'} is ${Date.now() - data.timestamp}`);
resetDisconnectCheck(game, req);
break;
case 'game-update':