import React, { useState, useCallback, useEffect } from "react"; import "./Trade.css"; import { getPlayerName } from './Common.js'; import PlayerColor from './PlayerColor.js'; import Paper from '@material-ui/core/Paper'; 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' const empty = { wheat: 0, brick: 0, wood: 0, stone: 0, sheep: 0 }; const Trade = ({table}) => { const [gives, setGives] = useState(Object.assign({}, empty)); const [gets, setGets] = useState(Object.assign({}, empty)); const player = (table.game && table.game.player) ? table.game.player : undefined; const transfer = useCallback((type, direction) => { if (direction === 'give') { /* give clicked */ if (gets[type]) { gets[type]--; gives[type] = 0; } else { if (gives[type] < player[type]) { gives[type]++; } gets[type] = 0; } } else if (direction === 'get') { /* get clicked */ if (gives[type]) { gives[type]--; gets[type] = 0; } else { if (gets[type] < 15) { gets[type]++; } gives[type] = 0; } } setGets({...gets}); setGives({...gives}); }, [setGets, setGives, gets, gives, player]); const createTransfer = useCallback(resource => { return
transfer(resource, 'get')} label={true} type={resource} count={gets[resource]}/>
{ gets[resource] === gives[resource] ? '' : (gets[resource] > gives[resource] ? : )}
transfer(resource, 'give')} label={true} type={resource} available={player ? player[resource] - gives[resource] : undefined} count={gives[resource]}/>
; }, [ gives, gets, transfer, player]); useEffect(() => { 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(), gets: offer.gives.slice() }; let _gives = {}, _gets = {}; console.log(gives, gets); trade.gives.forEach(give => _gives[give.type] = give.count); trade.gets.forEach(get => _gets[get.type] = get.count); table.offerTrade(trade); console.log(_gives, _gets); setGives(Object.assign({}, empty, _gives)); setGets(Object.assign({}, empty, _gets)); }, [setGives, setGets, gives, gets, table]); 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) { return false; } for (let i = 0; i < offer.gets.length; i++) { const get = offer.gets[i]; 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; } } return true; }; const isCompatibleOffer = (player, offer) => { let valid = player.gets && player.gives && offer.gets && offer.gives && player.gets.length === offer.gives.length && player.gives.length === offer.gets.length; if (!valid) { return false; } player.gets.forEach(get => { if (!valid) { return; } valid = offer.gives.find(item => (item.type === get.type || item.type === '*') && item.count === get.count) !== undefined; }); if (valid) player.gives.forEach(give => { if (!valid) { return; } valid = offer.gets.find(item => (item.type === give.type || item.type === 'bank') && item.count === give.count) !== undefined; }); return valid; }; const isTurn = (table.game.turn && table.game.turn.color === table.game.color) ? true : false; const offerClicked = (event) => { const trade = { gives: [], gets: [] }; for (let key in gives) { if (gives[key] !== 0) { trade.gives.push({type: key, count: gives[key]}); } } for (let key in gets) { if (gets[key] !== 0) { trade.gets.push({type: key, count: gets[key]}); } } table.offerTrade(trade); } const cancelOffer = (offer) => { table.cancelTrade(offer); } const acceptClicked = (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) => { table.cancelTrading(); } /* Player has rejected the active player's bid or active player rejected * the other player's bid */ const rejectClicked = (trade) => { table.rejectTrade(trade); } /* Create list of players with active trades */ let players = []; 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 && !(color in player.offerRejected) && (!item.gets || item.gets.length === 0 || !item.gives || item.gives.length === 0)) { continue; } const tmp = { negotiator: table.game.turn.name === name, self: table.game.name === name, name: name, color: color, valid: false, gets: item.gets ? item.gets : [], gives: item.gives ? item.gives : [], offerRejected: item.offerRejected, }; tmp.canSubmit = (tmp.gets.length && tmp.gives.length); players.push(tmp); } players.sort((A, B) => { if (A.negotiator) { return -1; } if (B.negotiator) { return +1; } if (A.self) { return -1; } if (B.self) { return +1; } return A.name.localeCompare(B.name); }); const trade = {gives: [], gets: []}; for (let type in gives) { if (gives[type]) { trade.gets.push({ type, count: gives[type]}); } } for (let type in gets) { if (gets[type]) { 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 ? true : false; if (isTurn && table.game.player && table.game.player.banks) { table.game.player.banks.forEach(bank => { const count = (bank === 'bank') ? 3 : 2; players.push({ name: `The bank`, color: undefined, gives: [ { count: 1, type: '*' } ], gets: [ { count: count, type: bank } ], valid: false, offerRejected: {} }); }); players.push({ name: `The bank`, color: undefined, gives: [ { count: 1, type: '*' } ], gets: [ { count: 4, type: 'bank' } ], valid: false, offerRejected: {} }); } 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) => { const youRejectedOffer = table.game.color in item.offerRejected; let youWereRejected; if (isTurn) { youWereRejected = item.color && item.color in player.offerRejected; } else { youWereRejected = Object.getOwnPropertyNames(player.offerRejected).length !== 0; } const isNewOffer = item.self && !isOfferSubmitted; let isSameOffer; const isBank = (item.name === 'The bank'); if (isTurn) { isSameOffer = isCompatibleOffer(trade, { gets: item.gives, gives: item.gets }); } else { isSameOffer = table.game.turn.offer && isCompatibleOffer(player, table.game.turn.offer); } let source; if (item.self) { /* Order direction is reversed for self */ source = { name: item.name, gets: trade.gives, gives: trade.gets }; } else { source = item; } const _gets = source.gets.length ? source.gets.map((get, index) => { if (get.type === 'bank') { return {get.count} of any resource ; } return ; }) : 'nothing'; const _gives = source.gives.length ? source.gives.map((give, index) => { if (give.type === '*') { return 1 of any resource ; } return ; }) : 'nothing'; return (
{ item.self && <> { (_gets !== 'nothing' || _gives !== 'nothing') && You want {_gets} and will give {_gives}. } { youWereRejected && !isNewOffer && { table.game.turn.name } rejected your offer. } { !youWereRejected && _gets === 'nothing' && _gives === 'nothing' && You have not made a trade offer. } { !isTurn && isSameOffer && isOfferValid && _gets !== 'nothing' && _gives !== 'nothing' && Your submitted offer agrees with {table.game.turn.name}'s terms. } } { !item.self && <> { (!isTurn || !isSameOffer || isBank) && !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && {item.name} wants {_gets} and will give {_gives}. } { !isBank && <> { isTurn && !isSameOffer && isOfferValid && !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && This is a counter offer. } { isTurn && isSameOffer && !youRejectedOffer && _gets !== 'nothing' && _gives !== 'nothing' && {item.name} will meet your terms. } { (!isTurn || !youWereRejected) && (_gets === 'nothing' || _gives === 'nothing') && {item.name} has not submitted a trade offer. } { youRejectedOffer && You rejected {item.name}'s offer. } { isTurn && youWereRejected && { item.name} rejected your offer. } } }
{ !item.self && isTurn && } { !isTurn && item.color === table.game.turn.color && } { item.name !== 'The bank' && !item.self && (isTurn || item.name === table.game.turn.name) && } { item.self && } { item.self && }
); }); return (
Trading negotiations {isTurn ? '' : `with ${table.game.turn.name}`}
{ players }
{ !player.haveResources && You have no resources to participate in this trade. } { player.haveResources &&
Get
Give
Have
{ transfers }
} { isTurn && }
); }; export default Trade;