diff --git a/src/components/farm/Board.jsx b/src/components/farm/Board.jsx
index 43731d8..701c497 100644
--- a/src/components/farm/Board.jsx
+++ b/src/components/farm/Board.jsx
@@ -32,9 +32,9 @@ import ReactDOM from 'react-dom'
import { connect } from 'react-redux'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faUser, faUsers, faTractor, faWindowRestore,
- faDollarSign, faTimes, faAsterisk, faExchangeAlt,
+ faDollarSign, faTimes, faExchangeAlt,
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 SpaceNode from './SpaceNode.jsx'
@@ -48,7 +48,7 @@ import { setSelectedCard, setMessagePanelSpace, setMPDims, movePlayer,
import { buy, roll, endTurn, loan, trade, submitTradeAccept,
submitTradeDeny, submitTradeCancel, audit,
buyUncleBert, skip, endAiTurn, startGame, readyToStart,
- leaveGame, kickPlayer } from './interface.js'
+ leaveGame, kickPlayer, toggleRevealForTrade } from './interface.js'
function netWorth(player) {
return ((player.assets.hay + player.assets.grain) * 2000) +
@@ -65,116 +65,6 @@ function assetsValue(player) {
((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 (
ERROR: {this.props.player.trade.error}
);
- } else if (this.props.player.trade.player === undefined) {
- return (You GAIN something if it is POSITIVE and you GIVE something if it is NEGATIVE.
);
- } else if (this.props.player.trade.originator === this.props.player.name) {
- return (You proposed a trade with {this.props.player.trade.player} for
- {'\u00A0'}{tradeString(this.props.player, false)}.
);
- } else {
- return ({this.props.player.trade.originator} proposed a trade for
- {'\u00A0'}{tradeString(this.props.player, true)}.
);
- }
- }
-}
-
-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 ();
- } else {
- return (
-
-
- );
- }
- }
-}
-
class ResourceUnit extends React.Component {
render () {
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 (
- );
- }
-}
-
class PlayerResources extends React.Component {
render () {
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 = ();
+ } else {
+ action = (
+
+
+
+
+
+
+
+ );
+ }
+ return (
+
+ );
+ }
+}
+
+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() {
+ const { player, cardsBeingTraded } = this.props;
+ const isMe = this.props.me.name === player.name;
return (
-
-
-
+ <>
+
+
+
+
+ {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'}
+ />
+
+ >
);
}
}
@@ -531,7 +428,16 @@ const makeDefaultToTrade = () => {
};
}
-class TradeContainer2 extends React.Component {
+
+/*
+ *
+ * this.tradeAsset('cards', e.target.value)} />
+ *
+ *
*/
+
+class TradeContainer extends React.Component {
resources = [{ img: HayImg,
h: '120',
s: '100',
@@ -584,11 +490,16 @@ class TradeContainer2 extends React.Component {
state = {
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 => {
- this.setState({ otherPlayer: findPlayer(this.props.game, e.target.value) });
+ this.setState({ otherPlayer: findPlayer(this.props.game, e.target.value),
+ receiveCards: [] });
}
componentDidUpdate(prevProps) {
@@ -596,8 +507,10 @@ class TradeContainer2 extends React.Component {
prevProps.game.otherPlayers.length !== this.props.game.otherPlayers.length) {
this.setState({ otherPlayer: findPlayer(this.props.game,
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) {
- this.setState({ otherPlayer: findPlayer(this.props.game, this.state.otherPlayer.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),
+ receiveCards: [],
+ sendCards: [] });
}
if (prevProps.player.trade.originator && !this.props.player.trade.originator) {
this.setState({ otherPlayer: findPlayer(this.props.game,
@@ -624,14 +537,22 @@ class TradeContainer2 extends React.Component {
} else {
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({
toTrade: {
...makeDefaultToTrade(),
...tradeObj,
money: tradeObj.money ? tradeObj.money / 1000 : 0
},
- otherPlayer: findPlayer(this.props.game, isOriginator ?
- this.props.player.trade.player : this.props.player.trade.originator)
+ receiveCards: otherPlayer.cards.filter(c => cards.includes(c.id) && !myCardsIds.includes(c.id)),
+ sendCards: myCards,
+ otherPlayer
});
}
}
@@ -659,11 +580,35 @@ class TradeContainer2 extends React.Component {
propose = () => {
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,
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() {
const player = this.props.player,
otherPlayer = this.state.otherPlayer,
@@ -671,59 +616,78 @@ class TradeContainer2 extends React.Component {
tradeProposed = !!player.trade.originator;
return (
-
-
-
-
{player.name}
- {Object.keys(player.ridges).map((ridge, idx) => (
-
- {!tradeProposed && (player.ridges[ridge] > 0) && !toTrade[ridge] ? (
-
- ) : (<>>)}
- {' '}
-
- ))}
-
- {this.resources.map((o, i) => {
- let amount = o.key === 'money' ? Math.floor(player.cash / 1000) : player.assets[o.key];
- if (o.key === 'cows') { amount = player.assets.cows - playerRidgeCows(player); }
- return (
-
- {o.icon ? (
- <>
- (K)
-
- >
- ) : ''}
- {amount + Math.min(0, toTrade[o.key])}
- {o.icon ? (
) : ''}
- {!tradeProposed && ((amount + Math.min(0, toTrade[o.key])) > 0 || toTrade[o.key] > 0) ? (
- <>
-
- {o.key === 'money' && (amount + Math.min(0, toTrade[o.key])) >= 10 ? (
-
- ) : ''}
- >
- ) : (<>>)}
-
- );
- })}
-
-
+ {this.state.showCards ? (
+ c.id).concat(this.state.receiveCards.map(c => c.id))}
+ />
+ ) : (
+ <>
+
+
+
+
+ {Object.keys(player.ridges).map((ridge, idx) => (
+
+ {!tradeProposed && (player.ridges[ridge] > 0) && !toTrade[ridge] ? (
+
+ ) : (<>>)}
+ {' '}
+
+ ))}
+
+ {this.resources.map((o, i) => {
+ let amount = o.key === 'money' ? Math.floor(player.cash / 1000) : player.assets[o.key];
+ if (o.key === 'cows') { amount = player.assets.cows - playerRidgeCows(player); }
+ return (
+
+ {o.icon ? (
+ <>
+ (K)
+
+ >
+ ) : ''}
+ {amount + Math.min(0, toTrade[o.key])}
+ {o.icon ? (
) : ''}
+ {!tradeProposed && ((amount + Math.min(0, toTrade[o.key])) > 0 || toTrade[o.key] > 0) ? (
+ <>
+
+ {o.key === 'money' && (amount + Math.min(0, toTrade[o.key])) >= 10 ? (
+
+ ) : ''}
+ >
+ ) : (<>>)}
+
+ );
+ })}
+
+
@@ -739,6 +703,13 @@ class TradeContainer2 extends React.Component {
{' '}
))}
+ {this.state.receiveCards.map((card, idx) => (
+
+ ))}
@@ -769,6 +740,13 @@ class TradeContainer2 extends React.Component {
{' '}
))}
+ {this.state.sendCards.map((card, idx) => (
+
+ ))}
@@ -825,24 +803,21 @@ class TradeContainer2 extends React.Component {
))}
+ {otherPlayer && otherPlayer.revealedCards.length > 0 ? (
+ this.viewPlayerCards(e, otherPlayer)}>
+ Trade Cards
+
+ ) : (<>>)}
-
-
- this.tradeAsset('cards', e.target.value)} />
-
-
{player.trade.error ? (
@@ -862,6 +837,7 @@ class TradeContainer2 extends React.Component {
) : (<>>)}
+ >)}
);
}
@@ -1988,7 +1964,7 @@ const SCREENS = { summary: 'summary', misc: 'misc', farms: 'farms',
class BoardApp extends React.Component {
iconToScreen = { user: SCREENS.summary, 'window-restore': SCREENS.cards,
'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 }
unsubscribeAlert = () => null
@@ -2293,6 +2269,7 @@ class BoardApp extends React.Component {
setCardError={this.props.setCardError}
playerCash={this.props.player.displayCash}
playerDebt={this.props.player.debt}
+ revealedCards={this.props.player.revealedCards}
card={this.state.card}
cost={this.state.card.total / 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} />
-
+
@@ -2419,7 +2396,11 @@ class Card extends React.Component {
) : (<>>)}
-
+
@@ -2451,7 +2432,7 @@ class CardListComp extends React.Component {
case 'fruit': return '5 acres Fruit';
case 'grain': return '10 acres Grain'}};
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) =>
(
{ this.props.setCard(c); this.props.setCardError(false); }}>
@@ -2459,7 +2440,7 @@ class CardListComp extends React.Component {
));
return (
-
+
diff --git a/src/components/farm/interface.js b/src/components/farm/interface.js
index a21b62c..a2d270d 100644
--- a/src/components/farm/interface.js
+++ b/src/components/farm/interface.js
@@ -31,7 +31,7 @@ import { itemCard, fateCard } from 'game.js'
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
submitTradeDeny, submitTradeCancel, audit, handleMessage,
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
- startGame, readyToStart, leaveGame, kickPlayer }
+ startGame, readyToStart, leaveGame, kickPlayer, toggleRevealForTrade }
let store;
let movingTimer = 0;
@@ -217,6 +217,10 @@ function kickPlayer(name) {
sendCommand({ type: 'kick-player', name });
}
+function toggleRevealForTrade(id) {
+ sendCommand({ type: 'toggle-reveal-for-trading', id });
+}
+
// TODO share with Board.jsx
// http://stackoverflow.com/questions/149055
function formatMoney(n) {
diff --git a/src/components/farm/reducers.js b/src/components/farm/reducers.js
index 2ae0baa..8e79603 100644
--- a/src/components/farm/reducers.js
+++ b/src/components/farm/reducers.js
@@ -91,6 +91,8 @@ const initialState = {
assets: { hay: 10, grain: 10, fruit: 0, cows: 0, harvester: 0, tractor: 0, birthday: 0 },
color: '',
name: '',
+ cards: [],
+ revealedCards: [],
ridges: { ridge1: 0, ridge2: 0, ridge3: 0, ridge4: 0 },
space: 0,
hayDoubled: false,
diff --git a/src/components/join-game/JoinGame.jsx b/src/components/join-game/JoinGame.jsx
index 653247d..9d71f83 100644
--- a/src/components/join-game/JoinGame.jsx
+++ b/src/components/join-game/JoinGame.jsx
@@ -86,7 +86,7 @@ class JoinGame extends React.Component {
return (
-
+
Join Game
diff --git a/src/server/farm.scm b/src/server/farm.scm
index 6627b7f..2073fb1 100644
--- a/src/server/farm.scm
+++ b/src/server/farm.scm
@@ -115,6 +115,7 @@
(harvest-mult initform: 1 accessor: player-harvest-mult)
(otbs initform: '() accessor: player-otbs)
(farmers-fates initform: '() accessor: player-farmers-fates)
+ (revealed-cards initform: '() accessor: player-revealed-cards)
(year-rules initform: '() accessor: player-year-rules)
(next-year-rules initform: '() accessor: player-next-year-rules)
(color initform: #f accessor: player-color)
@@ -182,7 +183,8 @@
(harvest-mult . ,(player-harvest-mult player))
(otbs . ,(player-otbs 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))
(color . ,(player-color player))
(name . ,(player-name player))
@@ -306,18 +308,21 @@
(set! *app* (sexp->app (read))))))
(define (sexp->player x)
- (apply make
- 'farmers-fates (let ((ffs (alist-ref 'farmers-fates x)))
- (list-copy
- (filter (lambda (card)
- (member (alist-ref 'id card) ffs))
- *farmers-fates-cards*)))
- (fold (lambda (k r) (cons k (cons (alist-ref k x) r)))
- '()
- '(cash debt space previous-space state assets ridges
- harvest-mult otbs user-id
- year-rules next-year-rules hay-doubled corn-doubled
- color name trade last-updated last-cash))))
+ (let ((p (apply make
+ 'farmers-fates (let ((ffs (alist-ref 'farmers-fates x)))
+ (list-copy
+ (filter (lambda (card)
+ (member (alist-ref 'id card) ffs))
+ *farmers-fates-cards*)))
+ (fold (lambda (k r) (cons k (cons (alist-ref k x) r)))
+ '()
+ '(cash debt space previous-space state assets ridges
+ harvest-mult otbs user-id revealed-cards
+ year-rules next-year-rules hay-doubled corn-doubled
+ color name trade last-updated last-cash)))))
+ (when (not (player-revealed-cards p))
+ (safe-set! (player-revealed-cards p) '()))
+ p))
(define (shuffle l)
(map cdr
@@ -521,6 +526,7 @@
(state . ,(symbol->string (player-state p)))
(cards . ,(list->vector (append (player-farmers-fates p)
(player-otbs p))))
+ (revealedCards . ,(list->vector (player-revealed-cards p)))
(color . ,(symbol->string (player-color p)))
(name . ,(player-name p))
(user-id . ,(player-user-id p))
@@ -1334,6 +1340,16 @@
(message-players! game player '() type: "update"))
(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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
((string=? type "main-init")
(create-start-response "start-init"))
@@ -2384,3 +2400,4 @@
;; TODO
;; make sure two players can't have the same name
;; "your turn to roll" showing up on mobile when on action screen
+;; trade cards better