diff --git a/client/src/Trade.css b/client/src/Trade.css
index 78042e3..4f6fc3d 100644
--- a/client/src/Trade.css
+++ b/client/src/Trade.css
@@ -135,12 +135,7 @@
display: flex;
flex-wrap: wrap;
flex-direction: row;
-}
-
-.Trade .TradeLine .TradeText > div {
- display: flex;
align-items: center;
- flex-wrap: wrap;
}
/*
.Trade .TradeLine > div {
diff --git a/client/src/Trade.js b/client/src/Trade.js
index bf6cb76..3b899b4 100644
--- a/client/src/Trade.js
+++ b/client/src/Trade.js
@@ -1,4 +1,4 @@
-import React, { useState, useCallback } from "react";
+import React, { useState, useCallback, useEffect } from "react";
import "./Trade.css";
import { getPlayerName } from './Common.js';
import PlayerColor from './PlayerColor.js';
@@ -65,6 +65,19 @@ const Trade = ({table}) => {
;
}, [ gives, gets, transfer, player]);
+ useEffect(useCallback(() => {
+ if (table.game && table.game.player && table.game.player.gives) {
+ const _gives = {};
+ table.game.player.gives.forEach(give => _gives[give.type] = give.count);
+ setGives(Object.assign({}, empty, _gives));
+ }
+ if (table.game && table.game.player && table.game.player.gets) {
+ const _gets = {};
+ table.game.player.gets.forEach(get => _gets[get.type] = get.count);
+ setGets(Object.assign({}, empty, _gets));
+ }
+ }), [ setGets, setGives, table.game ]);
+
const agreeClicked = useCallback((offer) => {
const trade = {
gives: offer.gets.slice(),
@@ -84,7 +97,7 @@ const Trade = ({table}) => {
transfers = [ 'brick', 'wood', 'wheat', 'sheep', 'stone' ].map(resource => { return createTransfer(resource); });
- if (!table.game || !player) {
+ if (!table.game || !player || !table.game.player) {
return <>>;
}
@@ -218,7 +231,9 @@ const Trade = ({table}) => {
trade.gives.push({ type, count: gets[type]});
}
}
+
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;
if (isTurn && table.game.player && table.game.player.banks) {
@@ -244,7 +259,7 @@ const Trade = ({table}) => {
if (table.game.turn.offer) {
if (isTurn) {
- players.forEach(trade => trade.valid = isCompatibleOffer(table.game.turn.offer, trade));
+ players.forEach(trade => trade.valid = canMeetOffer(player, trade));
} else {
const found = players.find(item => item.name === table.game.turn.name);
if (found) {
@@ -269,45 +284,58 @@ const Trade = ({table}) => {
youRejectedOffer = player.offerRejected;
}
- const _gets = item.gets.length ? item.gets.map((get, index) =>
+ let isNewOffer = item.self && !isOfferSubmitted;
+ console.log(`Trade from ${item.name} is new self: ${item.self}, new offer: ${isNewOffer}`);
+
+ let source;
+ if (item.self) {
+ /* Order direction is reversed for self */
+ source = {
+ gets: trade.gives,
+ gives: trade.gets
+ };
+ } else {
+ source = item;
+ }
+ const _gets = source.gets.length ? source.gets.map((get, index) =>
{ get.type === 'bank' &&
4 of any resource
}
{ get.type !== 'bank' &&
}
- ) : undefined,
- _gives = item.gives.length ? item.gives.map((give, index) =>
+
) : 'nothing',
+ _gives = source.gives.length ? source.gives.map((give, index) =>
{ give.type === '*' && <>1 of any resource>}
{ give.type !== '*' && }
-
) : undefined
+
) : 'nothing';
return (
- { item.self &&
- { youWereRejected && <>Your offer to give {_gets} in exchange for {_gives} was rejected.> }
- { !youWereRejected && _gets && _gives && <>You want {_gets} and will give {_gives}.> }
- { !youWereRejected && (_gets === undefined || _gives === undefined) && <>
- You have not submitted a trade offer.
+ { item.self && <>
+ { youWereRejected && !isNewOffer && <>Your offer was rejected. > }
+ { (!youWereRejected || isNewOffer) && (_gets !== 'nothing' || _gives !== 'nothing') && <>
+ You want {_gets} and will give {_gives}.
+ > }
+ { !youWereRejected && _gets === 'nothing' && _gives === 'nothing' && <>
+ You have not started a trade offer.
>}
-
}
+ > }
{ !item.self && <>
-
- { !youRejectedOffer && _gets && _gives && <>
- {item.name} wants {_gets} and will give {_gives}.
+ { !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && <>
+ {item.name} wants {_gets} and will give {_gives}.
> }
- { (_gets === undefined || _gives === undefined) &&
- <>{item.name} has not submitted a trade offer.>
+ { (_gets === 'nothing' || _gives === 'nothing') &&
+ <>{item.name} has not submitted a trade offer. >
}
{ youRejectedOffer && <>
- You rejected {item.name}'s offer to receive {_gets} in exchange for {_gives}.
+ You rejected {item.name}'s offer.
> }
-
- { youWereRejected &&
- {item.name} rejected your offer.
-
}
+ { youWereRejected && <>
+ {item.name} rejected your offer.
+ >}
>}
@@ -318,7 +346,7 @@ const Trade = ({table}) => {
}
{ !isTurn && item.color === table.game.turn.color &&
-
}
diff --git a/server/routes/games.js b/server/routes/games.js
index 439d97a..3859da5 100755
--- a/server/routes/games.js
+++ b/server/routes/games.js
@@ -1296,6 +1296,16 @@ 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 (player[get.type] < get.count) {
+ return false;
+ }
+ }
+ return true;
+};
+
const isCompatibleOffer = (game, player, offer) => {
const isBank = offer.name === 'The bank';
let valid = player.gets.length === offer.gives.length &&
@@ -1370,9 +1380,10 @@ const isSameOffer = (player, offer) => {
/* Verifies player can make the offer */
const checkPlayerOffer = (game, player, offer) => {
let error = undefined;
+ const name = getPlayerName(game, player);
console.log({
- name: getPlayerName(game, player),
+ name: name,
gets: offer.gets,
gives: offer.gives,
sheep: player.sheep,
@@ -1393,12 +1404,12 @@ const checkPlayerOffer = (game, player, offer) => {
}
if (player[give.type] < give.count) {
- error = `You do not have ${give.count} ${give.type}!`;
+ error = `${name} does do not have ${give.count} ${give.type}!`;
return;
}
if (offer.gets.find(get => give.type === get.type)) {
- error = `You can not give and get the same resource type!`;
+ error = `${name} can not give and get the same resource type!`;
return;
}
});
@@ -1408,7 +1419,7 @@ const checkPlayerOffer = (game, player, offer) => {
return;
}
if (offer.gives.find(give => get.type === give.type)) {
- error = `You can not give and get the same resource type!`;
+ error = `${name} can not give and get the same resource type!`;
};
})
@@ -1600,7 +1611,9 @@ router.put("/:id/:action/:value?", async (req, res) => {
session.player.gives = offer.gives;
session.player.gets = offer.gets;
- delete session.player.offerRejected;
+ /* 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) {
@@ -1647,6 +1660,8 @@ router.put("/:id/:action/:value?", async (req, res) => {
const offer = req.body;
let target;
+ console.log(offer);
+
error = checkPlayerOffer(game, session.player, offer);
if (error) {
break;
@@ -1671,31 +1686,43 @@ router.put("/:id/:action/:value?", async (req, res) => {
mismatch = true;
}
});
+
if (mismatch) {
error = `Unfortunately, trades were re-negotiated in transit and the deal is invalid!`;
break;
}
+
+ error = checkPlayerOffer(game, target, offer);
+ if (error) {
+ break;
+ }
+
+ if (!canMeetOffer(target, player)) {
+ error = `${playerNameFromColor(game, offer.color)} cannot meet the terms.`;
+ break;
+ }
} else {
target = offer;
}
/* Verify the requesting offer wasn't jacked --\
* make sure the target.gives === player.gets and target.gives === player.gets */
- if (!isCompatibleOffer(game, player, target)) {
- error = `The requested offer does not match the negotiated terms!`;
+ if (!canMeetOffer(player, target)) {
+ error = `You cannot meet these terms!`;
break;
}
+
debugChat(game, 'Before trade');
/* Transfer goods */
- player.gets.forEach(item => {
+ target.gives.forEach(item => {
if (target.name !== 'The bank') {
target[item.type] -= item.count;
}
player[item.type] += item.count;
});
- player.gives.forEach(item => {
+ target.gets.forEach(item => {
if (target.name !== 'The bank') {
target[item.type] += item.count;
}