Fixed lots of trading bugs
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
1345e1a658
commit
315d55ad72
@ -36,6 +36,7 @@
|
|||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ChatList .System .MuiTypography-body1 {
|
.ChatList .System .MuiTypography-body1 {
|
||||||
|
@ -274,8 +274,7 @@ const Action = ({ table }) => {
|
|||||||
robberActions = (game && game.turn && game.turn.robberInAction),
|
robberActions = (game && game.turn && game.turn.robberInAction),
|
||||||
haveResources = player ? player.haveResources : false,
|
haveResources = player ? player.haveResources : false,
|
||||||
placement = (game.state === 'initial-placement' || game.turn.active === 'road-building'),
|
placement = (game.state === 'initial-placement' || game.turn.active === 'road-building'),
|
||||||
placeRoad = placement && game.turn && game.turn.actions && game.turn.actions.indexOf('place-road') !== -1,
|
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;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper className="Action">
|
<Paper className="Action">
|
||||||
@ -793,12 +792,6 @@ class Table extends React.Component {
|
|||||||
this.ws = new WebSocket(new_uri);
|
this.ws = new WebSocket(new_uri);
|
||||||
this.lastPing = this.game.timestamp;
|
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.ws.addEventListener('message', (event) => {
|
||||||
this.resetKeepAlive();
|
this.resetKeepAlive();
|
||||||
|
|
||||||
@ -840,6 +833,13 @@ class Table extends React.Component {
|
|||||||
this.setState({ error: event.message });
|
this.setState({ error: event.message });
|
||||||
this.resetKeepAlive(true);
|
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() {
|
componentDidMount() {
|
||||||
|
@ -103,9 +103,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Trade .PlayerColor {
|
.Trade .PlayerColor {
|
||||||
width: 0.5em;
|
align-self: flex-start;
|
||||||
height: 0.5em;
|
width: 0.75em;
|
||||||
margin: 0 0.25em 0 0;
|
height: 0.75em;
|
||||||
|
margin: 1rem 0.25em 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Trade .Transfer {
|
.Trade .Transfer {
|
||||||
@ -121,6 +122,15 @@
|
|||||||
justify-items: flex-start;
|
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 {
|
.Trade .TradeLine {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@ -137,13 +147,18 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
.Trade .TradeLine > div {
|
.Trade .TradeText > span {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: 0.25rem;
|
margin-right: 0.25rem;
|
||||||
|
width: 100%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Trade .TradeText > span:first-of-type {
|
||||||
|
min-height: 3.5rem;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
.Trade .TradeLine .Resource {
|
.Trade .TradeLine .Resource {
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
|
@ -7,6 +7,7 @@ import Button from '@material-ui/core/Button';
|
|||||||
import Resource from './Resource.js';
|
import Resource from './Resource.js';
|
||||||
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'
|
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'
|
||||||
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'
|
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'
|
||||||
|
import { alertClasses } from "@mui/material";
|
||||||
|
|
||||||
const empty = {
|
const empty = {
|
||||||
wheat: 0,
|
wheat: 0,
|
||||||
@ -93,22 +94,53 @@ const Trade = ({table}) => {
|
|||||||
setGets(Object.assign({}, empty, _gets));
|
setGets(Object.assign({}, empty, _gets));
|
||||||
}, [setGives, setGets, gives, gets, table]);
|
}, [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) {
|
if (!table.game || !player || !table.game.player) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const transfers = [ 'brick', 'wood', 'wheat', 'sheep', 'stone' ].map(resource => { return createTransfer(resource); });
|
||||||
|
|
||||||
|
player.offerRejected = player.offerRejected ? player.offerRejected: {};
|
||||||
|
|
||||||
const canMeetOffer = (player, offer) => {
|
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++) {
|
for (let i = 0; i < offer.gets.length; i++) {
|
||||||
const get = offer.gets[i];
|
const get = offer.gets[i];
|
||||||
if (get.type === 'bank') {
|
if (offer.name === 'The bank') {
|
||||||
if (player[player.gives[0].type] < get.count) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (player[get.type] < get.count) {
|
} else if (player[get.type] < get.count) {
|
||||||
|
console.log(`cannot meet count`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,7 +204,13 @@ const Trade = ({table}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const acceptClicked = (offer) => {
|
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) => {
|
const cancelClicked = (event) => {
|
||||||
@ -190,22 +228,19 @@ const Trade = ({table}) => {
|
|||||||
for (let color in table.game.players) {
|
for (let color in table.game.players) {
|
||||||
const item = table.game.players[color],
|
const item = table.game.players[color],
|
||||||
name = getPlayerName(table.game.sessions, 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
|
/* 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,
|
* that you haven't submitted an offer) or the current turn player,
|
||||||
* or the player explicitly rejected the player's offer */
|
* or the player explicitly rejected the player's offer */
|
||||||
if (table.game.turn.name !== name && table.game.name !== name &&
|
if (table.game.turn.name !== name && table.game.name !== name
|
||||||
!item.offerRejected &&
|
&& !(color in player.offerRejected)
|
||||||
(!item.gets || item.gets.length === 0
|
&& (!item.gets || item.gets.length === 0 || !item.gives || item.gives.length === 0)) {
|
||||||
|| !item.gives || item.gives.length === 0)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the active player already rejected this offer, hide it */
|
|
||||||
if (table.game.turn.name === name && item.negotiatorRejectedOffer) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tmp = {
|
const tmp = {
|
||||||
self: table.game.name === name,
|
self: table.game.name === name,
|
||||||
name: name,
|
name: name,
|
||||||
@ -213,10 +248,11 @@ const Trade = ({table}) => {
|
|||||||
valid: false,
|
valid: false,
|
||||||
gets: item.gets ? item.gets : [],
|
gets: item.gets ? item.gets : [],
|
||||||
gives: item.gives ? item.gives : [],
|
gives: item.gives ? item.gives : [],
|
||||||
offerRejected: (table.game.turn.name !== name) ? (item.offerRejected ? true : false) : false,
|
offerRejected: item.offerRejected,
|
||||||
negotiatorRejectedOffer: item.negotiatorRejectedOffer
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tmp.canSubmit = (tmp.gets.length && tmp.gives.length);
|
tmp.canSubmit = (tmp.gets.length && tmp.gives.length);
|
||||||
|
|
||||||
players.push(tmp);
|
players.push(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +274,7 @@ const Trade = ({table}) => {
|
|||||||
|
|
||||||
const isOfferSubmitted = isCompatibleOffer(table.game.player, trade),
|
const isOfferSubmitted = isCompatibleOffer(table.game.player, trade),
|
||||||
isNegiatorSubmitted = table.game.turn && table.game.turn.offer && isCompatibleOffer(table.game.player, table.game.turn.offer),
|
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) {
|
if (isTurn && table.game.player && table.game.player.banks) {
|
||||||
table.game.player.banks.forEach(bank => {
|
table.game.player.banks.forEach(bank => {
|
||||||
@ -248,7 +284,8 @@ const Trade = ({table}) => {
|
|||||||
color: undefined,
|
color: undefined,
|
||||||
gives: [ { count: 1, type: '*' } ],
|
gives: [ { count: 1, type: '*' } ],
|
||||||
gets: [ { count: count, type: bank } ],
|
gets: [ { count: count, type: bank } ],
|
||||||
valid: false
|
valid: false,
|
||||||
|
offerRejected: {}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -257,39 +294,40 @@ const Trade = ({table}) => {
|
|||||||
color: undefined,
|
color: undefined,
|
||||||
gives: [ { count: 1, type: '*' } ],
|
gives: [ { count: 1, type: '*' } ],
|
||||||
gets: [ { count: 4, type: 'bank' } ],
|
gets: [ { count: 4, type: 'bank' } ],
|
||||||
valid: false
|
valid: false,
|
||||||
|
offerRejected: {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (table.game.turn.offer) {
|
if (isTurn) {
|
||||||
if (isTurn) {
|
players.forEach(offer => offer.valid = !(table.game.turn.color in offer.offerRejected) && canMeetOffer(player, offer));
|
||||||
players.forEach(trade => trade.valid = canMeetOffer(player, trade));
|
} else {
|
||||||
} else {
|
const found = players.find(item => item.name === table.game.turn.name);
|
||||||
const found = players.find(item => item.name === table.game.turn.name);
|
if (found) {
|
||||||
if (found) {
|
found.valid = !(table.game.color in found.offerRejected) && canMeetOffer(player, found);
|
||||||
found.valid = canMeetOffer(player, table.game.turn.offer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
players = players.map((item, index) => {
|
players = players.map((item, index) => {
|
||||||
/*
|
const youRejectedOffer = table.game.color in item.offerRejected;
|
||||||
if (item.negotiatorRejectedOffer && isTurn) {
|
let youWereRejected;
|
||||||
return <></>;
|
if (isTurn) {
|
||||||
}
|
youWereRejected = item.color && item.color in player.offerRejected;
|
||||||
*/
|
|
||||||
|
|
||||||
let youWereRejected = item.negotiatorRejectedOffer;
|
|
||||||
let youRejectedOffer;
|
|
||||||
if (isTurn && !item.self) {
|
|
||||||
youRejectedOffer = item.negotiatorRejectedOffer;
|
|
||||||
youWereRejected = item.offerRejected;
|
|
||||||
} else {
|
} 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;
|
if (isTurn) {
|
||||||
console.log(`Trade from ${item.name} is new self: ${item.self}, new offer: ${isNewOffer}`);
|
isSameOffer = isCompatibleOffer(player, item);
|
||||||
|
} else {
|
||||||
|
isSameOffer = table.game.turn.offer &&
|
||||||
|
isCompatibleOffer(player, table.game.turn.offer);
|
||||||
|
}
|
||||||
|
|
||||||
let source;
|
let source;
|
||||||
if (item.self) {
|
if (item.self) {
|
||||||
@ -302,46 +340,63 @@ const Trade = ({table}) => {
|
|||||||
} else {
|
} else {
|
||||||
source = item;
|
source = item;
|
||||||
}
|
}
|
||||||
const _gets = source.gets.length ? source.gets.map((get, index) => <div key={`get-${get.type}-${index}`}>
|
const _gets = source.gets.length ? source.gets.map((get, index) => <>
|
||||||
{ get.type === 'bank' && <div key={`get-bank-${index}`}><b>4</b> of any resource </div>}
|
{ 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}/> }
|
{ get.type !== 'bank' && <Resource key={`get-${get.type}-${index}`} disabled label type={get.type} count={get.count}/> }
|
||||||
</div>) : 'nothing',
|
</>) : 'nothing',
|
||||||
_gives = source.gives.length ? source.gives.map((give, index) => <div key={`give-${give.type}-${index}`}>
|
_gives = source.gives.length ? source.gives.map((give, index) => <>
|
||||||
{ give.type === '*' && <><b>1</b> of any resource </>}
|
{ give.type === '*' && <span key={`give-bank-${index}`}><b>1</b> of any resource </span>}
|
||||||
{ give.type !== '*' && <Resource disabled label type={give.type} count={give.count}/> }
|
{ give.type !== '*' && <Resource key={`give-${give.type}-${index}`} disabled label type={give.type} count={give.count}/> }
|
||||||
</div>) : 'nothing';
|
</>) : 'nothing';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="TradeLine" key={`player-${item.name}-${index}`}>
|
<div className="TradeLine" key={`player-${item.name}-${index}`}>
|
||||||
<PlayerColor color={item.color}/>
|
<PlayerColor color={item.color}/>
|
||||||
<div className="TradeText">
|
<div className="TradeText">
|
||||||
{ item.self && <>
|
{ item.self && <>
|
||||||
{ youWereRejected && !isNewOffer && <>Your offer was rejected. </> }
|
{ (_gets !== 'nothing' || _gives !== 'nothing') && <span>
|
||||||
{ (!youWereRejected || isNewOffer) && (_gets !== 'nothing' || _gives !== 'nothing') && <>
|
You want {_gets} and will give {_gives}.
|
||||||
You want {_gets} and will give {_gives}.
|
</span> }
|
||||||
</> }
|
|
||||||
{ !youWereRejected && _gets === 'nothing' && _gives === 'nothing' && <>
|
{ youWereRejected && !isNewOffer && <span>
|
||||||
You have not started a trade offer.
|
{ 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 && <>
|
{ !item.self && <>
|
||||||
{ !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && <>
|
{ (!isTurn || !isSameOffer || isBank) && !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && <span>
|
||||||
{item.name} wants {_gets} and will give {_gives}.
|
{item.name} wants {_gets} and will give {_gives}.
|
||||||
</> }
|
</span> }
|
||||||
|
|
||||||
{ (_gets === 'nothing' || _gives === 'nothing') &&
|
{ !isBank && <>
|
||||||
<>{item.name} has not submitted a trade offer. </>
|
{ isTurn && !isSameOffer && isOfferValid && _gets !== 'nothing' && _gives !== 'nothing' && <span style={{fontWeight: 'bold'}}>
|
||||||
}
|
This is a counter offer.
|
||||||
|
</span> }
|
||||||
|
|
||||||
{ youRejectedOffer && <>
|
{ isTurn && isSameOffer && !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && <span>
|
||||||
You rejected {item.name}'s offer.
|
{item.name} will meet your terms.
|
||||||
</> }
|
</span> }
|
||||||
|
|
||||||
{ youWereRejected && <>
|
{ (_gets === 'nothing' || _gives === 'nothing') && <span>
|
||||||
{item.name} rejected your offer.
|
{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>
|
||||||
<div className="TradeActions">
|
<div className="TradeActions">
|
||||||
@ -383,11 +438,12 @@ const Trade = ({table}) => {
|
|||||||
{ players }
|
{ players }
|
||||||
</div>
|
</div>
|
||||||
{ !player.haveResources && <b>You have no resources to participate in this trade.</b> }
|
{ !player.haveResources && <b>You have no resources to participate in this trade.</b> }
|
||||||
<Button
|
<Button disabled={isOfferSubmitted || !isOfferValid}
|
||||||
onClick={offerClicked}>Offer</Button>
|
onClick={offerClicked}>Offer</Button>
|
||||||
|
|
||||||
{ player.haveResources &&
|
{ player.haveResources &&
|
||||||
<div className="Transfers">
|
<div className="Transfers">
|
||||||
|
<div className="GiveGet"><div>Give</div><div>Get</div></div>
|
||||||
{ transfers }
|
{ transfers }
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ const processGameOrder = (game, player, dice) => {
|
|||||||
color: getPlayerColor(game, players[0])
|
color: getPlayerColor(game, players[0])
|
||||||
};
|
};
|
||||||
placeSettlement(game, getValidCorners(game));
|
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!`);
|
addChatMessage(game, null, `Initial settlement placement has started!`);
|
||||||
message = `It is ${game.turn.name}'s turn to place a settlement.`;
|
message = `It is ${game.turn.name}'s turn to place a settlement.`;
|
||||||
} else {
|
} else {
|
||||||
@ -302,9 +302,9 @@ const distributeResources = (session, game, roll) => {
|
|||||||
let index = game.pipOrder[i];
|
let index = game.pipOrder[i];
|
||||||
if (staticData.pips[index].roll === roll) {
|
if (staticData.pips[index].roll === roll) {
|
||||||
if (game.robber === i) {
|
if (game.robber === i) {
|
||||||
addChatMessage(game, null, `That pesky ${game.robberName} Roberson stole resources!`);
|
tiles.push({ robber: true, index: i });
|
||||||
} else {
|
} 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 },
|
"R": { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
|
||||||
"W": { 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 },
|
"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 */
|
/* Find which corners are on each tile */
|
||||||
tiles.forEach(index => {
|
tiles.forEach(tile => {
|
||||||
let shuffle = game.tileOrder[index];
|
let shuffle = game.tileOrder[tile.index];
|
||||||
console.log(index, game.tiles[shuffle]);
|
|
||||||
const resource = game.tiles[shuffle];
|
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];
|
const active = game.placements.corners[cornerIndex];
|
||||||
if (active && active.color) {
|
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) {
|
for (let color in receives) {
|
||||||
const entry = receives[color];
|
const entry = receives[color];
|
||||||
if (!entry.wood && !entry.brick && !entry.sheep && !entry.wheat && !entry.stone) {
|
if (!entry.wood && !entry.brick && !entry.sheep && !entry.wheat && !entry.stone) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let message = [];
|
let message = [];
|
||||||
for (let type in receives[color]) {
|
for (let type in entry) {
|
||||||
const player = playerFromColor(game, color);
|
if (entry[type] === 0) {
|
||||||
player[type] += receives[color][type];
|
continue;
|
||||||
if (receives[color][type]) {
|
}
|
||||||
message.push(`${receives[color][type]} ${type}`);
|
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
game.dice = dice;
|
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];
|
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;
|
||||||
@ -898,7 +917,7 @@ const addActivity = (game, session, message) => {
|
|||||||
if (game.activities.length && game.activities[game.activities.length - 1].date === date) {
|
if (game.activities.length && game.activities[game.activities.length - 1].date === 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) => {
|
const addChatMessage = (game, session, message) => {
|
||||||
@ -1308,21 +1327,7 @@ const getValidRoads = (game, color) => {
|
|||||||
return limits;
|
return limits;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canMeetOffer = (player, offer) => {
|
const isCompatibleOffer = (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 isBank = offer.name === 'The bank';
|
const isBank = offer.name === 'The bank';
|
||||||
let valid = player.gets.length === offer.gives.length &&
|
let valid = player.gets.length === offer.gives.length &&
|
||||||
player.gives.length === offer.gets.length;
|
player.gives.length === offer.gets.length;
|
||||||
@ -1332,8 +1337,8 @@ const isCompatibleOffer = (game, player, offer) => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log({
|
console.log({
|
||||||
player: getPlayerName(game, player),
|
player: 'Submitting player',
|
||||||
gets: player.gets,
|
gets: player.gets,
|
||||||
gives: player.gives
|
gives: player.gives
|
||||||
}, {
|
}, {
|
||||||
@ -1393,13 +1398,14 @@ const isSameOffer = (player, offer) => {
|
|||||||
return same;
|
return same;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Verifies player can make the offer */
|
/* Verifies player can meet the offer */
|
||||||
const checkPlayerOffer = (game, player, offer) => {
|
const checkPlayerOffer = (game, player, offer) => {
|
||||||
let error = undefined;
|
let error = undefined;
|
||||||
const name = getPlayerName(game, player);
|
const name = getPlayerName(game, player);
|
||||||
|
|
||||||
console.log({
|
console.log({ checkPlayerOffer: {
|
||||||
name: name,
|
name: name,
|
||||||
|
player: player,
|
||||||
gets: offer.gets,
|
gets: offer.gets,
|
||||||
gives: offer.gives,
|
gives: offer.gives,
|
||||||
sheep: player.sheep,
|
sheep: player.sheep,
|
||||||
@ -1407,7 +1413,8 @@ const checkPlayerOffer = (game, player, offer) => {
|
|||||||
brick: player.brick,
|
brick: player.brick,
|
||||||
stone: player.stone,
|
stone: player.stone,
|
||||||
wood: player.wood,
|
wood: player.wood,
|
||||||
});
|
description: offerToString(offer)
|
||||||
|
} });
|
||||||
|
|
||||||
offer.gives.forEach(give => {
|
offer.gives.forEach(give => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
@ -1442,6 +1449,20 @@ const checkPlayerOffer = (game, player, offer) => {
|
|||||||
return error;
|
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) => {
|
const gameSignature = (game) => {
|
||||||
if (!game) {
|
if (!game) {
|
||||||
return "";
|
return "";
|
||||||
@ -1591,7 +1612,6 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
game.players[key].gives = [];
|
game.players[key].gives = [];
|
||||||
game.players[key].gets = [];
|
game.players[key].gets = [];
|
||||||
delete game.players[key].offerRejected;
|
delete game.players[key].offerRejected;
|
||||||
delete game.players[key].negotiatorRejectedOffer;
|
|
||||||
}
|
}
|
||||||
addActivity(game, session, `${name} requested to begin trading negotiations.`);
|
addActivity(game, session, `${name} requested to begin trading negotiations.`);
|
||||||
break;
|
break;
|
||||||
@ -1627,19 +1647,31 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
|
|
||||||
session.player.gives = offer.gives;
|
session.player.gives = offer.gives;
|
||||||
session.player.gets = offer.gets;
|
session.player.gets = offer.gets;
|
||||||
/* This offer is new for the negotiator, but don't clear the flag indicating
|
session.player.offerRejected = {};
|
||||||
* if this player regected the negotiator's offer */
|
|
||||||
/* delete session.player.offerRejected; */
|
if (game.turn.color === session.color) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
game.turn.offer = offer;
|
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)}.`);
|
addActivity(game, session, `${session.name} submitted an offer to give ${offerToString(offer)}.`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1649,20 +1681,13 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
const offer = req.body;
|
const offer = req.body;
|
||||||
|
|
||||||
/* If the active player rejected an offer, they rejected another player */
|
/* If the active player rejected an offer, they rejected another player */
|
||||||
if (game.turn.name === name) {
|
const other = playerFromName(game, offer.name);
|
||||||
console.log(`Rejected `, offer);
|
if (!other.offerRejected) {
|
||||||
const other = playerFromName(game, offer.name);
|
other.offerRejected = {};
|
||||||
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.`);
|
|
||||||
}
|
}
|
||||||
|
other.offerRejected[session.color] = true;
|
||||||
|
addActivity(game, session, `${session.name} rejected ${offer.name}'s offer.`);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1676,7 +1701,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
const offer = req.body;
|
const offer = req.body;
|
||||||
let target;
|
let target;
|
||||||
|
|
||||||
console.log(offer);
|
console.log({ offer, description: offerToString(offer) });
|
||||||
|
|
||||||
error = checkPlayerOffer(game, session.player, offer);
|
error = checkPlayerOffer(game, session.player, offer);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -1688,31 +1713,26 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
if (!offer.name || offer.name !== 'The bank') {
|
if (!offer.name || offer.name !== 'The bank') {
|
||||||
let mismatch = false;
|
let mismatch = false;
|
||||||
target = game.players[offer.color];
|
target = game.players[offer.color];
|
||||||
offer.gives.forEach(item => {
|
if (offer.color in target.offerRejected) {
|
||||||
const isOffered = target.gives.find(
|
error = `${getPlayerName(game, target)} rejected this offer.`;
|
||||||
match => match.type === item.type && match.count === item.count);
|
break;
|
||||||
if (!isOffered) {
|
}
|
||||||
mismatch = true;
|
if (!isCompatibleOffer(target, offer)) {
|
||||||
}
|
|
||||||
});
|
|
||||||
offer.gets.forEach(item => {
|
|
||||||
const isOffered = target.gets.find(
|
|
||||||
match => match.type === item.type && match.count === item.count);
|
|
||||||
if (!isOffered) {
|
|
||||||
mismatch = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (mismatch) {
|
|
||||||
error = `Unfortunately, trades were re-negotiated in transit and the deal is invalid!`;
|
error = `Unfortunately, trades were re-negotiated in transit and the deal is invalid!`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = checkPlayerOffer(game, target, offer);
|
error = checkPlayerOffer(game, target, { gives: offer.gets, gets: offer.gives });
|
||||||
if (error) {
|
if (error) {
|
||||||
break;
|
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)) {
|
if (!canMeetOffer(target, player)) {
|
||||||
error = `${playerNameFromColor(game, offer.color)} cannot meet the terms.`;
|
error = `${playerNameFromColor(game, offer.color)} cannot meet the terms.`;
|
||||||
break;
|
break;
|
||||||
@ -1721,24 +1741,16 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
target = offer;
|
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');
|
debugChat(game, 'Before trade');
|
||||||
|
|
||||||
/* Transfer goods */
|
/* Transfer goods */
|
||||||
player.gets.forEach(item => {
|
offer.gets.forEach(item => {
|
||||||
if (target.name !== 'The bank') {
|
if (target.name !== 'The bank') {
|
||||||
target[item.type] -= item.count;
|
target[item.type] -= item.count;
|
||||||
}
|
}
|
||||||
player[item.type] += item.count;
|
player[item.type] += item.count;
|
||||||
});
|
});
|
||||||
player.gives.forEach(item => {
|
offer.gives.forEach(item => {
|
||||||
if (target.name !== 'The bank') {
|
if (target.name !== 'The bank') {
|
||||||
target[item.type] += item.count;
|
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;
|
const from = (offer.name === 'The bank') ? 'the bank' : offer.name;
|
||||||
addChatMessage(game, session, `${session.name} traded ` +
|
addChatMessage(game, session, `${session.name} traded ` +
|
||||||
` ${offerToString(session.player)} ` +
|
` ${offerToString(offer)} ` +
|
||||||
`from ${from}.`);
|
`from ${from}.`);
|
||||||
addActivity(game, session, `${session.name} accepted a trade from ${from}.`)
|
addActivity(game, session, `${session.name} accepted a trade from ${from}.`)
|
||||||
delete game.turn.offer;
|
delete game.turn.offer;
|
||||||
@ -1836,7 +1848,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
game.turn.placedRobber = true;
|
game.turn.placedRobber = true;
|
||||||
|
|
||||||
pickRobber(game);
|
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 = [];
|
let colors = [];
|
||||||
layout.tiles[robber].corners.forEach(cornerIndex => {
|
layout.tiles[robber].corners.forEach(cornerIndex => {
|
||||||
@ -1997,18 +2009,18 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
case 'road-2':
|
case 'road-2':
|
||||||
const allowed = Math.min(player.roads, 2);
|
const allowed = Math.min(player.roads, 2);
|
||||||
if (!allowed) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
let roads = getValidRoads(game, session.color);
|
let roads = getValidRoads(game, session.color);
|
||||||
if (roads.length === 0) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
game.turn.active = 'road-building';
|
game.turn.active = 'road-building';
|
||||||
game.turn.free = true;
|
game.turn.free = true;
|
||||||
game.turn.freeRoads = allowed;
|
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);
|
placeRoad(game, roads);
|
||||||
break;
|
break;
|
||||||
case 'monopoly':
|
case 'monopoly':
|
||||||
@ -2031,7 +2043,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
|
|
||||||
if (card.type === 'army') {
|
if (card.type === 'army') {
|
||||||
player.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 &&
|
if (player.army > 2 &&
|
||||||
(!game.largestArmy || game.players[game.largestArmy].army < player.army)) {
|
(!game.largestArmy || game.players[game.largestArmy].army < player.army)) {
|
||||||
@ -2669,7 +2681,7 @@ const ping = (session) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
session.ping = Date.now();
|
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 }));
|
session.ws.send(JSON.stringify({ type: 'ping', ping: session.ping }));
|
||||||
if (session.keepAlive) {
|
if (session.keepAlive) {
|
||||||
clearTimeout(session.keepAlive);
|
clearTimeout(session.keepAlive);
|
||||||
@ -2749,7 +2761,7 @@ router.ws("/ws/:id", async (ws, req) => {
|
|||||||
const data = JSON.parse(message);
|
const data = JSON.parse(message);
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case 'pong':
|
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);
|
resetDisconnectCheck(game, req);
|
||||||
break;
|
break;
|
||||||
case 'game-update':
|
case 'game-update':
|
||||||
|
Loading…
x
Reference in New Issue
Block a user