From 589187db388243327080ca9442cba0c1d4901f3c Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 3 Mar 2022 17:48:24 -0800 Subject: [PATCH] Lots of fixes to trading Signed-off-by: James Ketrenos --- client/src/Trade.css | 5 --- client/src/Trade.js | 76 +++++++++++++++++++++++++++++------------- server/routes/games.js | 45 ++++++++++++++++++++----- 3 files changed, 88 insertions(+), 38 deletions(-) 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; }