Visual card trading.

master
Thomas Hintz 5 years ago
parent c34fc7dcbe
commit bea133bee4

@ -32,9 +32,9 @@ import ReactDOM from 'react-dom'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faUser, faUsers, faTractor, faWindowRestore, import { faUser, faUsers, faTractor, faWindowRestore,
faDollarSign, faTimes, faAsterisk, faExchangeAlt, faDollarSign, faTimes, faExchangeAlt,
faInfoCircle, faArrowUp, faArrowDown, faAward, faInfoCircle, faArrowUp, faArrowDown, faAward,
faTimesCircle, faBan } from '@fortawesome/free-solid-svg-icons' faBan, faArrowCircleLeft } from '@fortawesome/free-solid-svg-icons'
import { GroupBox, Row, Col, Button } from '../widgets.jsx' import { GroupBox, Row, Col, Button } from '../widgets.jsx'
import SpaceNode from './SpaceNode.jsx' import SpaceNode from './SpaceNode.jsx'
@ -48,7 +48,7 @@ import { setSelectedCard, setMessagePanelSpace, setMPDims, movePlayer,
import { buy, roll, endTurn, loan, trade, submitTradeAccept, import { buy, roll, endTurn, loan, trade, submitTradeAccept,
submitTradeDeny, submitTradeCancel, audit, submitTradeDeny, submitTradeCancel, audit,
buyUncleBert, skip, endAiTurn, startGame, readyToStart, buyUncleBert, skip, endAiTurn, startGame, readyToStart,
leaveGame, kickPlayer } from './interface.js' leaveGame, kickPlayer, toggleRevealForTrade } from './interface.js'
function netWorth(player) { function netWorth(player) {
return ((player.assets.hay + player.assets.grain) * 2000) + return ((player.assets.hay + player.assets.grain) * 2000) +
@ -65,116 +65,6 @@ function assetsValue(player) {
((player.assets.harvester + player.assets.tractor) * 10000); ((player.assets.harvester + player.assets.tractor) * 10000);
} }
function getElementValue(id) {
return document.getElementById(id).value;
}
function getString(id) {
return getElementValue(id);
}
function getInt(id) {
const i = parseInt(getElementValue(id));
return isNaN(i) ? 0 : i;
}
function getChecked(id) {
return document.getElementById(id).checked;
}
function getOption(id) {
let options = document.getElementById(id).selectedOptions;
if (options.length > 0) {
return options[0].value;
} else {
return false;
}
}
function submitTrade() {
trade({ hay: getInt('trade-hay'), grain: getInt('trade-grain'),
fruit: getInt('trade-fruit'), cows: getInt('trade-cows'),
harvester: getInt('trade-harvesters'),
tractor: getInt('trade-tractors'),
ridge1: getChecked('trade-ridge1'),
ridge2: getChecked('trade-ridge2'),
ridge3: getChecked('trade-ridge3'),
ridge4: getChecked('trade-ridge4'),
player: getOption('trade-player'),
money: getInt('trade-money'), cards: getString('trade-cards') });
}
function tradeString(player, invert) {
var r = '';
let mult = invert ? -1 : 1;
for (var k in player.trade) {
if (k !== 'player' && k !== 'originator' && k !== 'cards' && k !== 'trade-number') {
r += (player.trade[k] === true ? '' : player.trade[k] * mult) + ' ' + k + ', ';
} else if (k === 'cards') {
r += 'cards: ' + player.trade[k] + ', ';
}
}
return r.slice(0, -2); // remove last ", "
}
class PlayerTradeProposed extends React.Component {
render () {
if (this.props.player.trade.error) {
return (<p><b>ERROR:</b> {this.props.player.trade.error}</p>);
} else if (this.props.player.trade.player === undefined) {
return (<p>You GAIN something if it is POSITIVE and you GIVE something if it is NEGATIVE.</p>);
} else if (this.props.player.trade.originator === this.props.player.name) {
return (<p>You proposed a trade with <b>{this.props.player.trade.player}</b> for
{'\u00A0'}<b>{tradeString(this.props.player, false)}</b>.</p>);
} else {
return (<p><b>{this.props.player.trade.originator}</b> proposed a trade for
{'\u00A0'}<b>{tradeString(this.props.player, true)}</b>.</p>);
}
}
}
function tradeFormSubmit(e, player) {
e.preventDefault();
if (player.trade.player === undefined) {
submitTrade();
} else if (player.trade.originator === player.name) {
submitTradeCancel();
} else {
submitTradeAccept();
}
return false;
}
class PlayerTradeButton extends React.Component {
tradeDeny = e => {
e.preventDefault();
submitTradeDeny();
}
render() {
var text = '';
var receiver = false;
if (this.props.player.trade.player === undefined) {
text = 'Propose';
} else if (this.props.player.trade.originator === this.props.player.name) {
text = 'Cancel';
} else {
text = 'Accept';
receiver = true;
}
if (!receiver) {
return (<Button className='tiny' type='submit'>{text} Trade</Button>);
} else {
return (<Fragment>
<Button className='tiny' type='submit'>{text} Trade</Button>
<Button className='tiny' onClick={this.tradeDeny}>
Deny Trade
</Button>
</Fragment>);
}
}
}
class ResourceUnit extends React.Component { class ResourceUnit extends React.Component {
render () { render () {
const hslString = 'hsl(' + this.props.h + ', ' + this.props.s; const hslString = 'hsl(' + this.props.h + ', ' + this.props.s;
@ -197,61 +87,6 @@ class ResourceUnit extends React.Component {
} }
} }
class PlayerTradeResources extends React.Component {
render () {
let player = this.props.player;
return (
<form onSubmit={e => tradeFormSubmit(e, player)}>
<div className='player-trade-resources'>
<ResourceUnit img={HayImg} h='120' s='100' label='acres of Hay' amount={''}>
<input type='number' id='trade-hay' defaultValue='0' />
</ResourceUnit> {' '}
<ResourceUnit img={WheatImg} h='41' s='100' label='acres of Grain' amount={''}>
<input type='number' id='trade-grain' defaultValue='0' />
</ResourceUnit> {' '}
<ResourceUnit img={FruitImg} h='0' s='100' label='acres of Fruit' amount={''}>
<input type='number' id='trade-fruit' defaultValue='0' />
</ResourceUnit> {' '}
<ResourceUnit img={CowImg} h='0' s='59' label='head of Cows' amount={''}>
<input type='number' id='trade-cows' defaultValue='0' />
</ResourceUnit> {' '}
<ResourceUnit img={HarvesterImg} h='240' s='100' label='Harvesters' amount={''}>
<input type='number' id='trade-harvesters' defaultValue='0' />
</ResourceUnit> {' '}
<ResourceUnit img={TractorImg} h='240' s='100' label='Tractors' amount={''}>
<input type='number' id='trade-tractors' defaultValue='0' />
</ResourceUnit>
<br />
<b>Ridges</b>: <b>{ridgeNames[0][0]}</b>: <input type='checkbox' id='trade-ridge1' />{'\u00A0'}
<b>R</b>: <input type='checkbox' id='trade-ridge2' />{'\u00A0'}
<b>C</b>: <input type='checkbox' id='trade-ridge3' />{'\u00A0'}
<b>T</b>: <input type='checkbox' id='trade-ridge4' />{'\u00A0'}
<br /><br />
<Row>
<Col width='4 column-no-padding'>
<label htmlFor='trade-player'><b>Player</b>:</label>
<select id='trade-player'>
{this.props.otherPlayers.map(p => (
<option key={p.player.name} value={p.player.name}>{p.player.name}</option>
))}
</select>
</Col>
<Col width='4 column-no-padding'>
<label htmlFor='trade-money'><b>Money</b>: </label>
<input type='number' id='trade-money' defaultValue='0' />
</Col>
<Col width='4 column-no-padding'>
<label htmlFor='trade-cards'><b>Cards</b>: </label>
<input type='text' id='trade-cards' placeholder="12 46" />
</Col>
</Row>
<PlayerTradeProposed player={this.props.player} />
<PlayerTradeButton player={this.props.player} />
</div>
</form>);
}
}
class PlayerResources extends React.Component { class PlayerResources extends React.Component {
render () { render () {
const player = this.props.player; const player = this.props.player;
@ -495,13 +330,75 @@ class FarmsContainer extends React.Component {
} }
} }
class TradeContainer extends React.Component { class TradeCard extends React.Component {
render () {
const card = this.props.card;
let action = (null);
if (card.type === 'no-card') {
action = (<span></span>);
} else {
action = (
<div className='card-action'>
<Row>
<Col width="12">
<Button onClick={() => this.props.tradeCard(card)}>Trade Card</Button>
</Col>
</Row>
</div>
);
}
return (
<div className='game-card'>
<GroupBox title={card.title}>
<div className='card'
dangerouslySetInnerHTML={{__html: card.contents}} />
{action}
</GroupBox>
</div>
);
}
}
const makeEmptyCard = () => { return { type: 'no-card', contents: '', total: 0, id: -1 }; }
class TradeCards extends React.Component {
state = {
selectedCard: makeEmptyCard()
}
componentDidMount() {
if (this.props.player.cards.length > 0) {
this.setState({ selectedCard: this.props.player.cards[0] });
}
}
render() { render() {
const { player, cardsBeingTraded } = this.props;
const isMe = this.props.me.name === player.name;
return ( return (
<GroupBox title='Trade'> <>
<PlayerTradeResources otherPlayers={this.props.game.otherPlayers} <CardListComp ui={player}
player={this.props.player} /> title={(
</GroupBox> <>
<a onClick={this.props.goBack}>
<FontAwesomeIcon icon={faArrowCircleLeft} />
</a>
{isMe ? (
<>Your Cards</>
) : (
<>{player.name}'s Cards</>
)}
</>
)}
visibleCards={isMe ? player.cards.filter(c => !cardsBeingTraded.includes(c.id)).map(c => c.id) :
player.revealedCards.filter(c => !cardsBeingTraded.includes(c))}
cardId={this.state.selectedCard.id}
setCard={(c) => this.setState({ selectedCard: c })}
setCardError={() => 'nothing'}
/>
<TradeCard card={this.state.selectedCard}
tradeCard={this.props.tradeCard} />
</>
); );
} }
} }
@ -531,7 +428,16 @@ const makeDefaultToTrade = () => {
}; };
} }
class TradeContainer2 extends React.Component {
/* <Row>
* <Col width="12">
* <input type="text" placeholder="Cards"
* defaultValue={toTrade.cards}
* onChange={e => this.tradeAsset('cards', e.target.value)} />
* </Col>
* </Row> */
class TradeContainer extends React.Component {
resources = [{ img: HayImg, resources = [{ img: HayImg,
h: '120', h: '120',
s: '100', s: '100',
@ -584,11 +490,16 @@ class TradeContainer2 extends React.Component {
state = { state = {
otherPlayer: findPlayer(this.props.game, this.props.game.otherPlayers.length > 0 ? this.props.game.otherPlayers[0].player.name : ''), otherPlayer: findPlayer(this.props.game, this.props.game.otherPlayers.length > 0 ? this.props.game.otherPlayers[0].player.name : ''),
toTrade: makeDefaultToTrade() toTrade: makeDefaultToTrade(),
showCards: false,
showCardsPlayer: false,
sendCards: [],
receiveCards: []
} }
selectPlayer = e => { selectPlayer = e => {
this.setState({ otherPlayer: findPlayer(this.props.game, e.target.value) }); this.setState({ otherPlayer: findPlayer(this.props.game, e.target.value),
receiveCards: [] });
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
@ -596,8 +507,10 @@ class TradeContainer2 extends React.Component {
prevProps.game.otherPlayers.length !== this.props.game.otherPlayers.length) { prevProps.game.otherPlayers.length !== this.props.game.otherPlayers.length) {
this.setState({ otherPlayer: findPlayer(this.props.game, this.setState({ otherPlayer: findPlayer(this.props.game,
this.props.game.otherPlayers.length > 0 ? this.props.game.otherPlayers[0].player.name : '') }); this.props.game.otherPlayers.length > 0 ? this.props.game.otherPlayers[0].player.name : '') });
} else if (this.state.otherPlayer && this.state.otherPlayer.name !== findPlayer(this.props.game, this.state.otherPlayer.name).name) { } else if (this.state.otherPlayer && this.state.otherPlayer !== findPlayer(this.props.game, this.state.otherPlayer.name)) {
this.setState({ otherPlayer: findPlayer(this.props.game, this.state.otherPlayer.name) }); this.setState({ otherPlayer: findPlayer(this.props.game, this.state.otherPlayer.name),
receiveCards: [],
sendCards: [] });
} }
if (prevProps.player.trade.originator && !this.props.player.trade.originator) { if (prevProps.player.trade.originator && !this.props.player.trade.originator) {
this.setState({ otherPlayer: findPlayer(this.props.game, this.setState({ otherPlayer: findPlayer(this.props.game,
@ -624,14 +537,22 @@ class TradeContainer2 extends React.Component {
} else { } else {
tradeObj = this.props.player.trade; tradeObj = this.props.player.trade;
} }
const cards = tradeObj.cards.split(' ').map(i => parseInt(i)),
myCards = this.props.player.cards.filter(c => cards.includes(c.id)),
myCardsIds = myCards.map(c => c.id);
console.log(cards);
console.log(myCards)
const otherPlayer = findPlayer(this.props.game, isOriginator ?
this.props.player.trade.player : this.props.player.trade.originator);
this.setState({ this.setState({
toTrade: { toTrade: {
...makeDefaultToTrade(), ...makeDefaultToTrade(),
...tradeObj, ...tradeObj,
money: tradeObj.money ? tradeObj.money / 1000 : 0 money: tradeObj.money ? tradeObj.money / 1000 : 0
}, },
otherPlayer: findPlayer(this.props.game, isOriginator ? receiveCards: otherPlayer.cards.filter(c => cards.includes(c.id) && !myCardsIds.includes(c.id)),
this.props.player.trade.player : this.props.player.trade.originator) sendCards: myCards,
otherPlayer
}); });
} }
} }
@ -659,11 +580,35 @@ class TradeContainer2 extends React.Component {
propose = () => { propose = () => {
trade({ ...this.state.toTrade, trade({ ...this.state.toTrade,
cards: this.state.sendCards.map(c => c.id).concat(this.state.receiveCards.map(c => c.id)).join(' '),
money: this.state.toTrade.money * 1000, money: this.state.toTrade.money * 1000,
player: this.state.otherPlayer.name player: this.state.otherPlayer.name
}) })
} }
viewPlayerCards = (e, player) => {
e.preventDefault();
this.setState(state => {
return { showCards: !state.showCards,
showCardsPlayer: player };
});
}
tradeCard = (card) => {
if (this.props.player === this.state.showCardsPlayer) {
this.setState({ sendCards: [...this.state.sendCards, card],
showCards: false });
} else {
this.setState({ receiveCards: [...this.state.receiveCards, card],
showCards: false });
}
}
unTradeCard = (id) => {
this.setState({ sendCards: this.state.sendCards.filter(c => c.id !== id),
receiveCards: this.state.receiveCards.filter(c => c.id !== id) });
}
render() { render() {
const player = this.props.player, const player = this.props.player,
otherPlayer = this.state.otherPlayer, otherPlayer = this.state.otherPlayer,
@ -671,59 +616,78 @@ class TradeContainer2 extends React.Component {
tradeProposed = !!player.trade.originator; tradeProposed = !!player.trade.originator;
return ( return (
<GroupBox title='Trade'> <GroupBox title='Trade'>
<Row> {this.state.showCards ? (
<Col width="12"> <TradeCards player={this.state.showCardsPlayer}
<div className="trade-player-container"> me={player}
<h4>{player.name}</h4> tradeCard={this.tradeCard}
{Object.keys(player.ridges).map((ridge, idx) => ( goBack={this.viewPlayerCards}
<Fragment key={'player-trade' + ridge}> cardsBeingTraded={this.state.sendCards.map(c => c.id).concat(this.state.receiveCards.map(c => c.id))}
{!tradeProposed && (player.ridges[ridge] > 0) && !toTrade[ridge] ? ( />
<Button className="tiny" ) : (
onClick={() => this.tradeAsset(ridge, player.ridges[ridge], true)}> <>
<FontAwesomeIcon icon={faArrowDown} /> {ridgeNames[idx]} {'('}{player.ridges[ridge]} cows{')'} <Row>
</Button> <Col width="12">
) : (<></>)} <div className="trade-player-container">
{' '} <h4>
</Fragment> {player.name}
))} {player.cards.length > 0 ? (
<div className='resource-unit-container'> <>
{this.resources.map((o, i) => { {' - '}
let amount = o.key === 'money' ? Math.floor(player.cash / 1000) : player.assets[o.key]; <a onClick={e => this.viewPlayerCards(e, player)}>
if (o.key === 'cows') { amount = player.assets.cows - playerRidgeCows(player); } <FontAwesomeIcon icon={faWindowRestore} /> Trade Cards
return ( </a>
<ResourceUnit img={o.img ? o.img : false} h={o.h} s={o.s} label={o.label} </>
key={i} ) : (<></>)}
className={o.key === 'money' ? 'double-width' : false} </h4>
amount={amount + Math.min(0, toTrade[o.key])} {Object.keys(player.ridges).map((ridge, idx) => (
> <Fragment key={'player-trade' + ridge}>
{o.icon ? ( {!tradeProposed && (player.ridges[ridge] > 0) && !toTrade[ridge] ? (
<> <Button className="tiny"
<FontAwesomeIcon icon={o.icon} />(K) onClick={() => this.tradeAsset(ridge, player.ridges[ridge], true)}>
<br /> <FontAwesomeIcon icon={faArrowDown} /> {ridgeNames[idx]} {'('}{player.ridges[ridge]} cows{')'}
</> </Button>
) : ''} ) : (<></>)}
{amount + Math.min(0, toTrade[o.key])} {' '}
{o.icon ? (<br />) : ''} </Fragment>
{!tradeProposed && ((amount + Math.min(0, toTrade[o.key])) > 0 || toTrade[o.key] > 0) ? ( ))}
<> <div className='resource-unit-container'>
<Button className="tiny" {this.resources.map((o, i) => {
onClick={() => this.tradeAsset(o.key, o.amount * -1)}> let amount = o.key === 'money' ? Math.floor(player.cash / 1000) : player.assets[o.key];
<FontAwesomeIcon icon={faArrowDown} /> if (o.key === 'cows') { amount = player.assets.cows - playerRidgeCows(player); }
</Button> return (
{o.key === 'money' && (amount + Math.min(0, toTrade[o.key])) >= 10 ? ( <ResourceUnit img={o.img ? o.img : false} h={o.h} s={o.s} label={o.label}
<Button className="tiny" key={i}
onClick={() => this.tradeAsset(o.key, o.amount * -10)}> className={o.key === 'money' ? 'double-width' : false}
<FontAwesomeIcon icon={faArrowDown} /> amount={amount + Math.min(0, toTrade[o.key])}
<FontAwesomeIcon icon={faArrowDown} /> >
</Button> {o.icon ? (
) : ''} <>
</> <FontAwesomeIcon icon={o.icon} />(K)
) : (<></>)} <br />
</ResourceUnit> </>
); ) : ''}
})} {amount + Math.min(0, toTrade[o.key])}
</div> {o.icon ? (<br />) : ''}
</div> {!tradeProposed && ((amount + Math.min(0, toTrade[o.key])) > 0 || toTrade[o.key] > 0) ? (
<>
<Button className="tiny"
onClick={() => this.tradeAsset(o.key, o.amount * -1)}>
<FontAwesomeIcon icon={faArrowDown} />
</Button>
{o.key === 'money' && (amount + Math.min(0, toTrade[o.key])) >= 10 ? (
<Button className="tiny"
onClick={() => this.tradeAsset(o.key, o.amount * -10)}>
<FontAwesomeIcon icon={faArrowDown} />
<FontAwesomeIcon icon={faArrowDown} />
</Button>
) : ''}
</>
) : (<></>)}
</ResourceUnit>
);
})}
</div>
</div>
</Col> </Col>
</Row> </Row>
<Row> <Row>
@ -739,6 +703,13 @@ class TradeContainer2 extends React.Component {
{' '} {' '}
</Fragment> </Fragment>
))} ))}
{this.state.receiveCards.map((card, idx) => (
<Button className="tiny"
key={idx}
onClick={() => this.unTradeCard(card.id)}>
{card.summary}
</Button>
))}
</Col> </Col>
</Row> </Row>
<Row> <Row>
@ -769,6 +740,13 @@ class TradeContainer2 extends React.Component {
{' '} {' '}
</Fragment> </Fragment>
))} ))}
{this.state.sendCards.map((card, idx) => (
<Button className="tiny"
key={idx}
onClick={() => this.unTradeCard(card.id)}>
{card.summary}
</Button>
))}
</Col> </Col>
</Row> </Row>
<Row> <Row>
@ -825,24 +803,21 @@ class TradeContainer2 extends React.Component {
</Fragment> </Fragment>
))} ))}
<select onChange={this.selectPlayer} <select onChange={this.selectPlayer}
value={otherPlayer.name} value={otherPlayer.name}>
defaultValue={otherPlayer.name}>
{this.props.game.otherPlayers.map(p => ( {this.props.game.otherPlayers.map(p => (
<option key={p.player.name} value={p.player.name}> <option key={p.player.name} value={p.player.name}>
{p.player.name} {p.player.name}
</option> </option>
))} ))}
</select> </select>
{otherPlayer && otherPlayer.revealedCards.length > 0 ? (
<a onClick={e => this.viewPlayerCards(e, otherPlayer)}>
<FontAwesomeIcon icon={faWindowRestore} /> Trade Cards
</a>
) : (<></>)}
</div> </div>
</Col> </Col>
</Row> </Row>
<Row>
<Col width="12">
<input type="text" placeholder="Cards"
defaultValue={toTrade.cards}
onChange={e => this.tradeAsset('cards', e.target.value)} />
</Col>
</Row>
<Row> <Row>
<Col width="12"> <Col width="12">
{player.trade.error ? ( {player.trade.error ? (
@ -862,6 +837,7 @@ class TradeContainer2 extends React.Component {
) : (<></>)} ) : (<></>)}
</Col> </Col>
</Row> </Row>
</>)}
</GroupBox> </GroupBox>
); );
} }
@ -1988,7 +1964,7 @@ const SCREENS = { summary: 'summary', misc: 'misc', farms: 'farms',
class BoardApp extends React.Component { class BoardApp extends React.Component {
iconToScreen = { user: SCREENS.summary, 'window-restore': SCREENS.cards, iconToScreen = { user: SCREENS.summary, 'window-restore': SCREENS.cards,
'dollar-sign': SCREENS.loans, users: SCREENS.farms, 'dollar-sign': SCREENS.loans, users: SCREENS.farms,
'exchange-alt': SCREENS.trade, asterisk: SCREENS.misc, 'exchange-alt': SCREENS.trade,
tractor: SCREENS.action, 'info-circle': SCREENS.info } tractor: SCREENS.action, 'info-circle': SCREENS.info }
unsubscribeAlert = () => null unsubscribeAlert = () => null
@ -2293,6 +2269,7 @@ class BoardApp extends React.Component {
setCardError={this.props.setCardError} setCardError={this.props.setCardError}
playerCash={this.props.player.displayCash} playerCash={this.props.player.displayCash}
playerDebt={this.props.player.debt} playerDebt={this.props.player.debt}
revealedCards={this.props.player.revealedCards}
card={this.state.card} card={this.state.card}
cost={this.state.card.total / 1000} cost={this.state.card.total / 1000}
min={(this.state.card.total * this.props.game.settings.downPayment) / 1000} min={(this.state.card.total * this.props.game.settings.downPayment) / 1000}
@ -2310,7 +2287,7 @@ class BoardApp extends React.Component {
otherPlayers={this.props.game.otherPlayers} /> otherPlayers={this.props.game.otherPlayers} />
</div> </div>
<div className={this.tabClass(SCREENS.trade) + ' trade-tab'}> <div className={this.tabClass(SCREENS.trade) + ' trade-tab'}>
<TradeContainer2 player={this.props.player} game={this.props.game} /> <TradeContainer player={this.props.player} game={this.props.game} />
</div> </div>
<div className={this.tabClass(SCREENS.misc)}> <div className={this.tabClass(SCREENS.misc)}>
<Misc /> <Misc />
@ -2419,7 +2396,11 @@ class Card extends React.Component {
) : (<></>)} ) : (<></>)}
<Row collapse='true'> <Row collapse='true'>
<Col width="12"> <Col width="12">
<label className="small-text"><input type="checkbox" /> Reveal for trading</label> <label className="small-text">
<input type="checkbox"
onChange={() => toggleRevealForTrade(card.id)}
checked={this.props.revealedCards.includes(card.id)} /> Reveal for trading
</label>
</Col> </Col>
</Row> </Row>
@ -2451,7 +2432,7 @@ class CardListComp extends React.Component {
case 'fruit': return '5 acres Fruit'; case 'fruit': return '5 acres Fruit';
case 'grain': return '10 acres Grain'}}; case 'grain': return '10 acres Grain'}};
const ui = this.props.ui, const ui = this.props.ui,
cards = ui.cards, cards = ui.cards.filter(this.props.visibleCards ? (c) => this.props.visibleCards.includes(c.id) : (c) => c),
cardOps = cards.map((c, i) => cardOps = cards.map((c, i) =>
(<li key={i} className={c.id == this.props.cardId ? 'card-select-selected' : ''} (<li key={i} className={c.id == this.props.cardId ? 'card-select-selected' : ''}
onClick={() => { this.props.setCard(c); this.props.setCardError(false); }}> onClick={() => { this.props.setCard(c); this.props.setCardError(false); }}>
@ -2459,7 +2440,7 @@ class CardListComp extends React.Component {
</li>)); </li>));
return ( return (
<GroupBox title='Cards'> <GroupBox title={this.props.title ? this.props.title : 'Cards'}>
<ul className='card-select'> <ul className='card-select'>
{cardOps} {cardOps}
</ul> </ul>

@ -31,7 +31,7 @@ import { itemCard, fateCard } from 'game.js'
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept, export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
submitTradeDeny, submitTradeCancel, audit, handleMessage, submitTradeDeny, submitTradeCancel, audit, handleMessage,
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn, nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
startGame, readyToStart, leaveGame, kickPlayer } startGame, readyToStart, leaveGame, kickPlayer, toggleRevealForTrade }
let store; let store;
let movingTimer = 0; let movingTimer = 0;
@ -217,6 +217,10 @@ function kickPlayer(name) {
sendCommand({ type: 'kick-player', name }); sendCommand({ type: 'kick-player', name });
} }
function toggleRevealForTrade(id) {
sendCommand({ type: 'toggle-reveal-for-trading', id });
}
// TODO share with Board.jsx // TODO share with Board.jsx
// http://stackoverflow.com/questions/149055 // http://stackoverflow.com/questions/149055
function formatMoney(n) { function formatMoney(n) {

@ -91,6 +91,8 @@ const initialState = {
assets: { hay: 10, grain: 10, fruit: 0, cows: 0, harvester: 0, tractor: 0, birthday: 0 }, assets: { hay: 10, grain: 10, fruit: 0, cows: 0, harvester: 0, tractor: 0, birthday: 0 },
color: '', color: '',
name: '', name: '',
cards: [],
revealedCards: [],
ridges: { ridge1: 0, ridge2: 0, ridge3: 0, ridge4: 0 }, ridges: { ridge1: 0, ridge2: 0, ridge3: 0, ridge4: 0 },
space: 0, space: 0,
hayDoubled: false, hayDoubled: false,

@ -86,7 +86,7 @@ class JoinGame extends React.Component {
return ( return (
<GroupBox title={( <GroupBox title={(
<Fragment> <Fragment>
<a href="#" onClick={this.handleBack}> <a onClick={this.handleBack}>
<FontAwesomeIcon icon={faArrowCircleLeft} /> <FontAwesomeIcon icon={faArrowCircleLeft} />
</a> </a>
Join Game Join Game

@ -115,6 +115,7 @@
(harvest-mult initform: 1 accessor: player-harvest-mult) (harvest-mult initform: 1 accessor: player-harvest-mult)
(otbs initform: '() accessor: player-otbs) (otbs initform: '() accessor: player-otbs)
(farmers-fates initform: '() accessor: player-farmers-fates) (farmers-fates initform: '() accessor: player-farmers-fates)
(revealed-cards initform: '() accessor: player-revealed-cards)
(year-rules initform: '() accessor: player-year-rules) (year-rules initform: '() accessor: player-year-rules)
(next-year-rules initform: '() accessor: player-next-year-rules) (next-year-rules initform: '() accessor: player-next-year-rules)
(color initform: #f accessor: player-color) (color initform: #f accessor: player-color)
@ -182,7 +183,8 @@
(harvest-mult . ,(player-harvest-mult player)) (harvest-mult . ,(player-harvest-mult player))
(otbs . ,(player-otbs player)) (otbs . ,(player-otbs player))
(farmers-fates . ,(map (cut alist-ref 'id <>) (player-farmers-fates player))) (farmers-fates . ,(map (cut alist-ref 'id <>) (player-farmers-fates player)))
(year-rules . ,(player-year-rules player)) ;; TODO check if all are serializable (revealed-cards . ,(player-revealed-cards player))
(year-rules . ,(player-year-rules player))
(next-year-rules . ,(player-next-year-rules player)) (next-year-rules . ,(player-next-year-rules player))
(color . ,(player-color player)) (color . ,(player-color player))
(name . ,(player-name player)) (name . ,(player-name player))
@ -306,18 +308,21 @@
(set! *app* (sexp->app (read)))))) (set! *app* (sexp->app (read))))))
(define (sexp->player x) (define (sexp->player x)
(apply make <player> (let ((p (apply make <player>
'farmers-fates (let ((ffs (alist-ref 'farmers-fates x))) 'farmers-fates (let ((ffs (alist-ref 'farmers-fates x)))
(list-copy (list-copy
(filter (lambda (card) (filter (lambda (card)
(member (alist-ref 'id card) ffs)) (member (alist-ref 'id card) ffs))
*farmers-fates-cards*))) *farmers-fates-cards*)))
(fold (lambda (k r) (cons k (cons (alist-ref k x) r))) (fold (lambda (k r) (cons k (cons (alist-ref k x) r)))
'() '()
'(cash debt space previous-space state assets ridges '(cash debt space previous-space state assets ridges
harvest-mult otbs user-id harvest-mult otbs user-id revealed-cards
year-rules next-year-rules hay-doubled corn-doubled year-rules next-year-rules hay-doubled corn-doubled
color name trade last-updated last-cash)))) color name trade last-updated last-cash)))))
(when (not (player-revealed-cards p))
(safe-set! (player-revealed-cards p) '()))
p))
(define (shuffle l) (define (shuffle l)
(map cdr (map cdr
@ -521,6 +526,7 @@
(state . ,(symbol->string (player-state p))) (state . ,(symbol->string (player-state p)))
(cards . ,(list->vector (append (player-farmers-fates p) (cards . ,(list->vector (append (player-farmers-fates p)
(player-otbs p)))) (player-otbs p))))
(revealedCards . ,(list->vector (player-revealed-cards p)))
(color . ,(symbol->string (player-color p))) (color . ,(symbol->string (player-color p)))
(name . ,(player-name p)) (name . ,(player-name p))
(user-id . ,(player-user-id p)) (user-id . ,(player-user-id p))
@ -1334,6 +1340,16 @@
(message-players! game player '() type: "update")) (message-players! game player '() type: "update"))
(create-ws-response player "update" '())) (create-ws-response player "update" '()))
(begin (create-ws-response player "update" '())))) (begin (create-ws-response player "update" '()))))
((string=? type "toggle-reveal-for-trading")
(let ((id (alist-ref 'id msg)))
(if (member id (player-revealed-cards player))
(safe-set! (player-revealed-cards player)
(filter (lambda (cid) (not (eqv? cid id)))
(player-revealed-cards player)))
(safe-set! (player-revealed-cards player)
(cons id (player-revealed-cards player)))))
(message-players! game player '() type: "update")
(create-ws-response player "update" '()))
;;;;;;;;;;;;;;;;;;;;; start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;; start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
((string=? type "main-init") ((string=? type "main-init")
(create-start-response "start-init")) (create-start-response "start-init"))
@ -2384,3 +2400,4 @@
;; TODO ;; TODO
;; make sure two players can't have the same name ;; make sure two players can't have the same name
;; "your turn to roll" showing up on mobile when on action screen ;; "your turn to roll" showing up on mobile when on action screen
;; trade cards better

Loading…
Cancel
Save