New trading interface and moving bug fixes.
This commit is contained in:
@@ -31,7 +31,8 @@ import { connect } from 'react-redux'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faUser, faUsers, faTractor, faWindowRestore,
|
||||
faDollarSign, faTimes, faAsterisk, faExchangeAlt,
|
||||
faInfoCircle, faArrowUp, faAward } from '@fortawesome/free-solid-svg-icons'
|
||||
faInfoCircle, faArrowUp, faArrowDown, faAward,
|
||||
faTimesCircle } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
import SpaceNode from './SpaceNode.jsx'
|
||||
@@ -40,7 +41,8 @@ import Tractor from '../tractor/Tractor.jsx'
|
||||
import { GAME_STATES, ALERTS } from '../../constants.js'
|
||||
import { itemCard, itemCardShort, fateCard, ridgeNames } from 'game.js'
|
||||
import { setSelectedCard, setMessagePanelSpace, setMPDims, movePlayer,
|
||||
nextUIAction, alert, alertHandled, setCardError } from './actions.js'
|
||||
nextUIAction, alert, alertHandled, setCardError,
|
||||
setMovingSkip } from './actions.js'
|
||||
import { buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||
submitTradeDeny, submitTradeCancel, audit,
|
||||
buyUncleBert, skip } from './interface.js'
|
||||
@@ -174,7 +176,7 @@ class ResourceUnit extends React.Component {
|
||||
render () {
|
||||
const hslString = 'hsl(' + this.props.h + ', ' + this.props.s;
|
||||
return (
|
||||
<div className='resource-unit'
|
||||
<div className={'resource-unit ' + (this.props.className ? this.props.className : '')}
|
||||
title={this.props.amount + ' ' + this.props.label}
|
||||
style={{backgroundColor: hslString + '%, 85%)',
|
||||
borderTop: '3px solid ' + hslString + '%, 55%)'}}>
|
||||
@@ -448,6 +450,363 @@ class TradeContainer extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const findPlayer = (game, name) => {
|
||||
const ret = game.otherPlayers.find(p => p.player.name === name) || false;
|
||||
return ret ? ret.player : ret;
|
||||
}
|
||||
|
||||
const playerRidgeCows = player => {
|
||||
return Object.values(player.ridges).reduce((a, b) => a + b, 0);
|
||||
}
|
||||
|
||||
const makeDefaultToTrade = () => {
|
||||
return { hay: 0,
|
||||
grain: 0,
|
||||
fruit: 0,
|
||||
cows: 0,
|
||||
harvester: 0,
|
||||
tractor: 0,
|
||||
money: 0,
|
||||
ridge1: false,
|
||||
ridge2: false,
|
||||
ridge3: false,
|
||||
ridge4: false,
|
||||
cards: ''
|
||||
};
|
||||
}
|
||||
|
||||
class TradeContainer2 extends React.Component {
|
||||
resources = [{ img: HayImg,
|
||||
h: '120',
|
||||
s: '100',
|
||||
label: 'acres of Hay',
|
||||
key: 'hay',
|
||||
amount: 10
|
||||
}, {
|
||||
img: WheatImg,
|
||||
h: '41',
|
||||
s: '100',
|
||||
label: 'acres of Grain',
|
||||
key: 'grain',
|
||||
amount: 10
|
||||
}, {
|
||||
img: FruitImg,
|
||||
h: '0',
|
||||
s: '100',
|
||||
label: 'acres of Fruit',
|
||||
key: 'fruit',
|
||||
amount: 5
|
||||
}, {
|
||||
img: CowImg,
|
||||
h: '0',
|
||||
s: '59',
|
||||
label: 'head of Cows',
|
||||
key: 'cows',
|
||||
amount: 10
|
||||
}, {
|
||||
img: HarvesterImg,
|
||||
h: '240',
|
||||
s: '100',
|
||||
label: 'Harvesters',
|
||||
key: 'harvester',
|
||||
amount: 1
|
||||
}, {
|
||||
img: TractorImg,
|
||||
h: '240',
|
||||
s: '100',
|
||||
label: 'Tractors',
|
||||
key: 'tractor',
|
||||
amount: 1
|
||||
}, {
|
||||
icon: faDollarSign,
|
||||
h: '100',
|
||||
s: '83',
|
||||
label: 'Cash',
|
||||
key: 'money',
|
||||
amount: 1
|
||||
}];
|
||||
|
||||
state = {
|
||||
otherPlayer: findPlayer(this.props.game, this.props.game.otherPlayers.length > 0 ? this.props.game.otherPlayers[0].player.name : ''),
|
||||
toTrade: makeDefaultToTrade()
|
||||
}
|
||||
|
||||
selectPlayer = e => {
|
||||
this.setState({ otherPlayer: findPlayer(this.props.game, e.target.value) });
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (!this.state.otherPlayer &&
|
||||
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 !== findPlayer(this.props.game, this.state.otherPlayer.name)) {
|
||||
this.setState({ otherPlayer: findPlayer(this.props.game, this.state.otherPlayer.name) });
|
||||
}
|
||||
if (prevProps.player.trade.originator && !this.props.player.trade.originator) {
|
||||
this.setState({ otherPlayer: findPlayer(this.props.game,
|
||||
this.props.game.otherPlayers.length > 0 ? this.props.game.otherPlayers[0].player.name : ''),
|
||||
toTrade: makeDefaultToTrade()
|
||||
});
|
||||
} else if (prevProps.player.trade.originator !== this.props.player.trade.originator) {
|
||||
const isOriginator = this.props.player.trade.originator === this.props.player.name;
|
||||
let tradeObj = {};
|
||||
if (!isOriginator) {
|
||||
Object.keys(this.props.player.trade).forEach(key => {
|
||||
const value = this.props.player.trade[key];
|
||||
switch (typeof value) {
|
||||
case 'number':
|
||||
tradeObj[key] = value * -1;
|
||||
break;
|
||||
case 'boolean':
|
||||
tradeObj[key] = value;
|
||||
break;
|
||||
default:
|
||||
tradeObj[key] = value;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
tradeObj = this.props.player.trade;
|
||||
}
|
||||
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)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
tradeClass(amount) {
|
||||
if (amount > 0) {
|
||||
return 'trade-to';
|
||||
} else if (amount < 0) {
|
||||
return 'trade-from';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
tradeAsset = (asset, amount, verbatim) => {
|
||||
this.setState(state => {
|
||||
return {
|
||||
toTrade: {
|
||||
...state.toTrade,
|
||||
[asset]: (typeof amount === 'number') && !verbatim ? (state.toTrade[asset] + amount) : amount
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
propose = () => {
|
||||
trade({ ...this.state.toTrade,
|
||||
money: this.state.toTrade.money * 1000,
|
||||
player: this.state.otherPlayer.name
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const player = this.props.player,
|
||||
otherPlayer = this.state.otherPlayer,
|
||||
toTrade = this.state.toTrade,
|
||||
tradeProposed = !!player.trade.originator;
|
||||
return (
|
||||
<GroupBox title='Trade'>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<div className="trade-player-container">
|
||||
<h4>{player.name}</h4>
|
||||
{Object.keys(player.ridges).map((ridge, idx) => (
|
||||
<Fragment key={'player-trade' + ridge}>
|
||||
{!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{')'}
|
||||
</Button>
|
||||
) : (<></>)}
|
||||
{' '}
|
||||
</Fragment>
|
||||
))}
|
||||
<div className='resource-unit-container'>
|
||||
{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 (
|
||||
<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}
|
||||
amount={amount + Math.min(0, toTrade[o.key])}
|
||||
>
|
||||
{o.icon ? (
|
||||
<>
|
||||
<FontAwesomeIcon icon={o.icon} />(K)
|
||||
<br />
|
||||
</>
|
||||
) : ''}
|
||||
{amount + Math.min(0, toTrade[o.key])}
|
||||
{o.icon ? (<br />) : ''}
|
||||
{!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>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
{Object.keys(otherPlayer ? otherPlayer.ridges : []).map((ridge, idx) => (
|
||||
<Fragment key={'to-trade' + ridge}>
|
||||
{(otherPlayer.ridges[ridge] > 0) && toTrade[ridge] ? (
|
||||
<Button className="tiny"
|
||||
onClick={() => this.tradeAsset(ridge, false)}>
|
||||
<FontAwesomeIcon icon={faArrowDown} /> {ridgeNames[idx]} {'('}{otherPlayer.ridges[ridge]} cows{')'}
|
||||
</Button>
|
||||
) : (<></>)}
|
||||
{' '}
|
||||
</Fragment>
|
||||
))}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<div className='resource-unit-container resources-to-trade'>
|
||||
{this.resources.map((o, i) => (
|
||||
<ResourceUnit h={o.h} s={o.s} label={o.label}
|
||||
key={i}
|
||||
className={(this.tradeClass(toTrade[o.key])) + (o.key === 'money' ? ' double-width' : '')}
|
||||
amount={toTrade[o.key]}
|
||||
>
|
||||
{Math.abs(toTrade[o.key])}
|
||||
</ResourceUnit>
|
||||
))}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
{Object.keys(player.ridges).map((ridge, idx) => (
|
||||
<Fragment key={'to-trade' + ridge}>
|
||||
{(player.ridges[ridge] > 0) && toTrade[ridge] ? (
|
||||
<Button className="tiny"
|
||||
onClick={() => this.tradeAsset(ridge, false)}>
|
||||
<FontAwesomeIcon icon={faArrowUp} /> {ridgeNames[idx]} {'('}{player.ridges[ridge]} cows{')'}
|
||||
</Button>
|
||||
) : (<></>)}
|
||||
{' '}
|
||||
</Fragment>
|
||||
))}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<div className="trade-player-container">
|
||||
{otherPlayer ? (
|
||||
<div className='resource-unit-container'>
|
||||
{this.resources.map((o, i) => {
|
||||
let amount = o.key === 'money' ? 99 : otherPlayer.assets[o.key];
|
||||
if (o.key === 'cows') { amount = otherPlayer.assets.cows - playerRidgeCows(otherPlayer); }
|
||||
return (
|
||||
<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}
|
||||
amount={amount - Math.max(0, toTrade[o.key])}
|
||||
>
|
||||
{o.icon ? (
|
||||
<>
|
||||
<FontAwesomeIcon icon={o.icon} />(K)
|
||||
<br />
|
||||
</>
|
||||
) : ''}
|
||||
{amount - Math.max(0, toTrade[o.key])}
|
||||
{o.icon ? (<br />) : ''}
|
||||
{!tradeProposed && ((amount - Math.max(0, toTrade[o.key])) > 0 || toTrade[o.key] < 0) ? (
|
||||
<>
|
||||
<Button className="tiny"
|
||||
onClick={() => this.tradeAsset(o.key, o.amount)}>
|
||||
<FontAwesomeIcon icon={faArrowUp} />
|
||||
</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={faArrowUp} />
|
||||
<FontAwesomeIcon icon={faArrowUp} />
|
||||
</Button>
|
||||
) : ''}
|
||||
</>
|
||||
) : (<></>)}
|
||||
</ResourceUnit>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (<></>)}
|
||||
{Object.keys(otherPlayer ? otherPlayer.ridges : []).map((ridge, idx) => (
|
||||
<Fragment key={'other-player-trade' + ridge}>
|
||||
{!tradeProposed && ((otherPlayer.ridges[ridge] > 0) && !toTrade[ridge]) ? (
|
||||
<Button className="tiny"
|
||||
onClick={() => this.tradeAsset(ridge, otherPlayer.ridges[ridge], verbatim)}>
|
||||
<FontAwesomeIcon icon={faArrowUp} /> {ridgeNames[idx]} {'('}{otherPlayer.ridges[ridge]} cows{')'}
|
||||
</Button>
|
||||
) : (<></>)}
|
||||
{' '}
|
||||
</Fragment>
|
||||
))}
|
||||
<select onChange={this.selectPlayer}>
|
||||
{this.props.game.otherPlayers.map(p => (
|
||||
<option key={p.player.name} value={p.player.name}>{p.player.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<input type="text" placeholder="Cards"
|
||||
defaultValue={toTrade.cards}
|
||||
onChange={e => this.tradeAsset('cards', e.target.value)} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
{player.trade.error ? (
|
||||
<p><b>ERROR:</b> {player.trade.error}</p>
|
||||
) : (<></>)}
|
||||
{tradeProposed && player.trade.originator === player.name ? (
|
||||
<Button onClick={submitTradeCancel}>Cancel trade</Button>
|
||||
) : (<></>)}
|
||||
{tradeProposed && player.trade.originator !== player.name ? (
|
||||
<>
|
||||
<Button onClick={submitTradeAccept}>Accept trade</Button>{' '}
|
||||
<Button onClick={submitTradeCancel}>Deny trade</Button>
|
||||
</>
|
||||
) : (<></>)}
|
||||
{!tradeProposed ? (
|
||||
<Button onClick={this.propose}>Propose Trade</Button>
|
||||
) : (<></>)}
|
||||
</Col>
|
||||
</Row>
|
||||
</GroupBox>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CCBY extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
@@ -1012,105 +1371,32 @@ class Harvest extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
// props: currentPos, moveTo, color
|
||||
// actions: movePlayer
|
||||
class Moving extends React.Component {
|
||||
endPos = 0
|
||||
color = ''
|
||||
hurtBack = false
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const to = this.props.ui.actionValue.to,
|
||||
from = this.props.ui.actionValue.from;
|
||||
const currentPlayer = this.props.player.name === this.props.game.currentPlayer ?
|
||||
this.props.player : this.props.game.otherPlayers
|
||||
.find(p => p.player.name === this.props.game.currentPlayer).player;
|
||||
const currentPos = from;
|
||||
this.state = { currentPos: currentPos < 0 ? currentPos + 49 : currentPos,
|
||||
autoSkip: typeof props.autoSkip === 'undefined' ? false :
|
||||
props.autoSkip };
|
||||
this.endPos = to;
|
||||
this.color = currentPlayer.color;
|
||||
// only for hurt back do we go backwards
|
||||
this.hurtBack = to === 2 && from === 11 ? true : false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// TODO combine with tick
|
||||
const delta = this.state.currentPos === 48 ? -48 : this.hurtBack ? -1 : 1;
|
||||
this.props.movePlayer(this.state.currentPos + delta,
|
||||
this.state.currentPos,
|
||||
this.color);
|
||||
this.setState(state => ({ currentPos: state.currentPos + delta}));
|
||||
if (this.state.currentPos + delta !== this.endPos) {
|
||||
if (this.props.timerId) {
|
||||
clearInterval(this.props.timerId);
|
||||
}
|
||||
this.props.setTimerId(setInterval(() => this.tick(), 500));
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.props.timerId) {
|
||||
clearInterval(this.props.timerId);
|
||||
this.props.setTimerId(false);
|
||||
}
|
||||
// if another player skips movement
|
||||
if (this.state.currentPos !== this.endPos) {
|
||||
this.props.movePlayer(this.endPos,
|
||||
this.state.currentPos,
|
||||
this.color);
|
||||
}
|
||||
}
|
||||
|
||||
tick() {
|
||||
const delta = this.state.currentPos === 48 ? -48 : this.hurtBack ? -1 : 1;
|
||||
this.props.movePlayer(this.state.currentPos + delta,
|
||||
this.state.currentPos,
|
||||
this.color);
|
||||
this.setState(state => ({ currentPos: state.currentPos + delta}));
|
||||
if (this.state.currentPos === this.endPos) {
|
||||
if (this.props.timerId) { clearInterval(this.props.timerId); }
|
||||
this.props.setTimerId(false);
|
||||
}
|
||||
}
|
||||
|
||||
skip(preventAutoSkip) {
|
||||
if (!preventAutoSkip) {
|
||||
skip('moving');
|
||||
}
|
||||
clearInterval(this.props.timerId);
|
||||
this.props.setTimerId(false);
|
||||
this.props.movePlayer(this.endPos, this.state.currentPos, this.color);
|
||||
this.setState({ currentPos: this.endPos });
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.autoSkip !== this.props.autoSkip) {
|
||||
if (this.state.autoSkip === false &&
|
||||
this.props.autoSkip) {
|
||||
this.skip(true);
|
||||
}
|
||||
this.setState({ autoSkip: this.props.autoSkip });
|
||||
}
|
||||
this.props.setMovingSkip(true);
|
||||
}
|
||||
|
||||
render() {
|
||||
let buttons;
|
||||
if (this.props.player.name !== this.props.game.currentPlayer) {
|
||||
buttons = (<Fragment />);
|
||||
} else if (this.state.currentPos === this.endPos) {
|
||||
} else if (this.props.ui.playerSpaces[this.props.player.color] === this.props.ui.actionValue.to) {
|
||||
buttons = (<Button onClick={() => this.props.showNextAction()}>Continue</Button>);
|
||||
} else {
|
||||
buttons = (<Button onClick={() => this.skip()}>Skip</Button>);
|
||||
}
|
||||
const currentPlayer = this.props.player.name === this.props.game.currentPlayer ?
|
||||
this.props.player : this.props.game.otherPlayers
|
||||
.find(p => p.player.name === this.props.game.currentPlayer).player;
|
||||
return (
|
||||
<Row>
|
||||
<Col width={'12'}>
|
||||
<div className='moving'>
|
||||
<div className={'action clear-background'}>
|
||||
<SpaceNode space={this.props.spaces[this.state.currentPos]}
|
||||
<SpaceNode space={this.props.spaces[this.props.ui.playerSpaces[currentPlayer.color]]}
|
||||
height={'170px'} showtitle={true} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -1242,6 +1528,7 @@ class Action extends React.Component {
|
||||
autoSkip={this.props.ui.autoSkip}
|
||||
timerId={this.props.timerId}
|
||||
setTimerId={this.props.setTimerId}
|
||||
setMovingSkip={this.props.setMovingSkip}
|
||||
ui={this.props.ui} />);
|
||||
buttons = (<Fragment />);
|
||||
break;
|
||||
@@ -1251,6 +1538,7 @@ class Action extends React.Component {
|
||||
setTimerId={this.props.setTimerId}
|
||||
player={this.props.player}
|
||||
game={this.props.game}
|
||||
setMovingSkip={this.props.setMovingSkip}
|
||||
spaces={this.props.spaces}
|
||||
movePlayer={this.props.movePlayer}
|
||||
autoSkip={this.props.ui.autoSkip}
|
||||
@@ -1705,6 +1993,7 @@ class BoardApp extends React.Component {
|
||||
otherPlayersTurn={this.props.player.name !== this.props.game.currentPlayer}
|
||||
screen={this.state.screen}
|
||||
showScreen={screen => this.showScreen(screen)}
|
||||
setMovingSkip={this.props.setMovingSkip}
|
||||
ui={this.props.ui} />);
|
||||
// faExchangeAlt -> trade icon, hidden for now
|
||||
return (
|
||||
@@ -1768,8 +2057,8 @@ class BoardApp extends React.Component {
|
||||
<FarmsContainer player={this.props.player}
|
||||
otherPlayers={this.props.game.otherPlayers} />
|
||||
</div>
|
||||
<div className={this.tabClass(SCREENS.trade)}>
|
||||
<TradeContainer player={this.props.player} game={this.props.game} />
|
||||
<div className={this.tabClass(SCREENS.trade) + ' trade-tab'}>
|
||||
<TradeContainer2 player={this.props.player} game={this.props.game} />
|
||||
</div>
|
||||
<div className={this.tabClass(SCREENS.misc)}>
|
||||
<Misc />
|
||||
@@ -1792,7 +2081,8 @@ class BoardApp extends React.Component {
|
||||
|
||||
export default connect(
|
||||
state => state.farm,
|
||||
{ setMessagePanelSpace, setMPDims, nextUIAction, movePlayer, alert, alertHandled, setCardError }
|
||||
{ setMessagePanelSpace, setMPDims, nextUIAction, movePlayer, alert, alertHandled,
|
||||
setCardError, setMovingSkip }
|
||||
)(BoardApp)
|
||||
|
||||
class Card extends React.Component {
|
||||
|
||||
@@ -38,3 +38,4 @@ export const ALERT_HANDLED = 'alert-handled'
|
||||
export const AUTO_SKIP = 'auto-skip'
|
||||
export const MESSAGE = 'message'
|
||||
export const SET_HARVEST_TABLE = 'set-harvest-table'
|
||||
export const SET_MOVING_SKIP = 'set-moving-skip'
|
||||
|
||||
@@ -20,13 +20,14 @@ import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
|
||||
SPACE_PUSH_PLAYER, SPACE_CLEAR_PLAYERS, SET_OLD_MESSAGES, MESSAGE_PANEL_SPACE,
|
||||
MP_MOUSE, SET_MP_DIMS, MARK_ACTION_CHANGE_HANDLED, SET_NEXT_ACTION,
|
||||
MOVE_PLAYER, NEXT_UI_ACTION, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED,
|
||||
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR } from './actionTypes.js'
|
||||
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR,
|
||||
SET_MOVING_SKIP } from './actionTypes.js'
|
||||
|
||||
export { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
|
||||
spacePushPlayer, spaceClearPlayers, setOldMessages, setMessagePanelSpace,
|
||||
mpMouse, setMPDims, movePlayer, setNextAction, nextUIAction,
|
||||
markActionChangeHandled, nextUIActionSilent, alert, alertHandled,
|
||||
autoSkip, message, setHarvestTable, setCardError }
|
||||
autoSkip, message, setHarvestTable, setCardError, setMovingSkip }
|
||||
|
||||
function updateGame(update) {
|
||||
return { type: UPDATE_GAME,
|
||||
@@ -130,3 +131,7 @@ function message(message) {
|
||||
function setHarvestTable(table) {
|
||||
return { type: SET_HARVEST_TABLE, table };
|
||||
}
|
||||
|
||||
function setMovingSkip(skip) {
|
||||
return { type: SET_MOVING_SKIP, skip };
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ import * as websocket from '../../websocket.js'
|
||||
import { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
|
||||
movePlayer, setOldMessages, markActionChangeHandled,
|
||||
mpMouse, rolled, setNextAction, nextUIAction, nextUIActionSilent, alert,
|
||||
autoSkip, message, alertHandled, setHarvestTable, setCardError } from './actions.js'
|
||||
autoSkip, message, alertHandled, setHarvestTable,
|
||||
setCardError, setMovingSkip } from './actions.js'
|
||||
import { itemCard, fateCard } from 'game.js'
|
||||
|
||||
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||
@@ -189,7 +190,9 @@ function initialize(st, sc) {
|
||||
let lastAction = false,
|
||||
lastAutoSkip = false,
|
||||
rollMessage = '',
|
||||
rollTimer = false;
|
||||
rollTimer = false,
|
||||
movingAction = { from: 99, to: 99 },
|
||||
movingTimer = 0;
|
||||
const unsubscribe = store.subscribe(
|
||||
() => {
|
||||
const state = store.getState();
|
||||
@@ -265,6 +268,50 @@ function initialize(st, sc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((state.farm.ui.action === 'move' || state.farm.ui.action === 'goto') &&
|
||||
movingAction.from !== state.farm.ui.actionValue.from &&
|
||||
movingAction.to !== state.farm.ui.actionValue.to) {
|
||||
movingAction = state.farm.ui.actionValue;
|
||||
const movingProc = (player, from, to) => {
|
||||
let currentPos = from < 0 ? from + 49 : from;
|
||||
const color = player.color;
|
||||
const hurtBack = to === 2 && from === 11 ? true : false;
|
||||
const delta = currentPos === 48 ? -48 : hurtBack ? -1 : 1;
|
||||
store.dispatch(movePlayer(currentPos + delta, currentPos, color));
|
||||
currentPos += delta;
|
||||
|
||||
const tick = () => {
|
||||
if (store.getState().farm.ui.movingSkip ||
|
||||
store.getState().farm.ui.autoSkip === 'moving') {
|
||||
store.dispatch(setMovingSkip(false));
|
||||
store.dispatch(movePlayer(to, currentPos, color));
|
||||
currentPos = to;
|
||||
} else {
|
||||
const delta = currentPos === 48 ? -48 : hurtBack ? -1 : 1;
|
||||
store.dispatch(movePlayer(currentPos + delta, currentPos, color));
|
||||
currentPos += delta;
|
||||
}
|
||||
if (currentPos === to) {
|
||||
clearInterval(movingTimer);
|
||||
movingTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPos !== to) {
|
||||
movingTimer = setInterval(tick, 500);
|
||||
}
|
||||
}
|
||||
movingProc(state.farm.player.name === state.farm.game.currentPlayer ?
|
||||
state.farm.player : state.farm.game.otherPlayers
|
||||
.find(p => p.player.name === state.farm.game.currentPlayer).player,
|
||||
movingAction.from, movingAction.to);
|
||||
} else if (state.farm.ui.action !== 'move' && state.farm.ui.action !== 'goto') {
|
||||
if (movingTimer) {
|
||||
clearInterval(movingTimer);
|
||||
movingTimer = 0;
|
||||
movingAction = { from: 99, to: 99 };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// mpDims.mouseX = e.clientX
|
||||
|
||||
@@ -21,7 +21,8 @@ import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
|
||||
SET_OLD_MESSAGES, MESSAGE_PANEL_SPACE, MP_MOUSE,
|
||||
SET_MP_DIMS, MOVE_PLAYER, SET_NEXT_ACTION, NEXT_UI_ACTION,
|
||||
MARK_ACTION_CHANGE_HANDLED, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED,
|
||||
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR } from './actionTypes.js'
|
||||
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR,
|
||||
SET_MOVING_SKIP } from './actionTypes.js'
|
||||
import { GAME_STATES } from '../../constants.js'
|
||||
import { spaceContent, corners } from 'game.js'
|
||||
|
||||
@@ -121,6 +122,7 @@ const initialState = {
|
||||
unhandledAlert: false,
|
||||
autoSkip: false,
|
||||
playerSpaces: {},
|
||||
movingSkip: false,
|
||||
harvestTable: false },
|
||||
spaces: spaces,
|
||||
space: null,
|
||||
@@ -219,6 +221,8 @@ export default function(state = initialState, action) {
|
||||
return { ...state, ui: { ...state.ui, message: action.message }};
|
||||
case SET_HARVEST_TABLE:
|
||||
return { ...state, ui: { ...state.ui, harvestTable: action.table }};
|
||||
case SET_MOVING_SKIP:
|
||||
return { ...state, ui: { ...state.ui, movingSkip: action.skip }};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -584,6 +584,16 @@
|
||||
(when (alist-ref ridge params)
|
||||
(if (> (player-ridge player ridge) 0)
|
||||
(begin
|
||||
(safe-set!
|
||||
(player-assets originator)
|
||||
(alist-update 'cows (+ (alist-ref 'cows (player-assets originator))
|
||||
(alist-ref ridge (player-ridges player)))
|
||||
(player-assets originator)))
|
||||
(safe-set!
|
||||
(player-assets player)
|
||||
(alist-update 'cows (- (alist-ref 'cows (player-assets player))
|
||||
(alist-ref ridge (player-ridges player)))
|
||||
(player-assets player)))
|
||||
(safe-set! (player-ridges originator)
|
||||
(alist-update ridge
|
||||
(alist-ref ridge (player-ridges player))
|
||||
@@ -591,6 +601,16 @@
|
||||
(safe-set! (player-ridges player)
|
||||
(alist-update ridge 0 (player-ridges player))))
|
||||
(begin
|
||||
(safe-set!
|
||||
(player-assets originator)
|
||||
(alist-update 'cows (- (alist-ref 'cows (player-assets originator))
|
||||
(alist-ref ridge (player-ridges originator)))
|
||||
(player-assets originator)))
|
||||
(safe-set!
|
||||
(player-assets player)
|
||||
(alist-update 'cows (+ (alist-ref 'cows (player-assets player))
|
||||
(alist-ref ridge (player-ridges originator)))
|
||||
(player-assets player)))
|
||||
(safe-set! (player-ridges player)
|
||||
(alist-update ridge
|
||||
(alist-ref ridge (player-ridges originator))
|
||||
@@ -1903,17 +1923,11 @@
|
||||
;; TODO
|
||||
;; make sure two players can't have the same name
|
||||
;; info actions should look better
|
||||
;; you can get $50 from harvest
|
||||
;; moving bug 5 from oct 2 saw by player 2
|
||||
;; from harvest moon rolled 5
|
||||
;; finished
|
||||
;; infinite loop ((?action . end-game) (?value . #<procedure (a10302)>))
|
||||
;; you can get $50 from operating expense
|
||||
|
||||
;; auto-skip loop
|
||||
;; harvester / tractor don't say total price
|
||||
|
||||
;; mark spaces
|
||||
|
||||
;; trade notification keeps popping up
|
||||
|
||||
;; show harvest multiplier
|
||||
;; can't trade other player's ridge
|
||||
|
||||
@@ -268,8 +268,77 @@ $tab-margin: 0.3rem;
|
||||
|
||||
.player-trade-resources .resource-unit {
|
||||
display: inline-block;
|
||||
margin-bottom: 0.3rem;
|
||||
width: 4rem; }
|
||||
|
||||
.resource-unit.double-width {
|
||||
width: 84px;
|
||||
}
|
||||
|
||||
.resource-unit.double-width .button:last-child {
|
||||
margin-left: 0.2rem;
|
||||
}
|
||||
|
||||
.player-trade-resources img {
|
||||
margin-top: 0.2rem;
|
||||
margin-bottom: 0.2rem; }
|
||||
|
||||
.trade-player-container {
|
||||
border: 0.2rem solid $dark-color;
|
||||
border-radius: 0.2rem;
|
||||
background: #ccc;
|
||||
padding: 0.3rem;
|
||||
.button {
|
||||
margin: 0; }
|
||||
}
|
||||
|
||||
$trade-margin: 3rem;
|
||||
.resources-to-trade {
|
||||
margin-left: 0.5rem;
|
||||
visibility: hidden;
|
||||
.resource-unit {
|
||||
position: relative;
|
||||
margin-top: $trade-margin / 2;
|
||||
margin-bottom: $trade-margin / 2;
|
||||
}
|
||||
|
||||
.trade-asset-cancel {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: red;
|
||||
padding: 0.2rem;
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.trade-to {
|
||||
margin-top: ($trade-margin / 2) - 1.2;
|
||||
margin-bottom: ($trade-margin / 2) + 1.2;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.trade-to:hover .trade-asset-cancel {
|
||||
display: block;
|
||||
}
|
||||
.trade-from:hover .trade-asset-cancel {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.trade-from {
|
||||
margin-bottom: ($trade-margin / 2) - 1.2;
|
||||
margin-top: ($trade-margin / 2) + 1.2;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.card-id {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
@@ -305,6 +374,7 @@ $tab-margin: 0.3rem;
|
||||
}
|
||||
|
||||
.resource-unit {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
margin-right: 0.5rem;
|
||||
width: 40px;
|
||||
@@ -313,6 +383,19 @@ $tab-margin: 0.3rem;
|
||||
height: 34px; }
|
||||
}
|
||||
|
||||
.resource-doubled {
|
||||
position: absolute;
|
||||
top: -0.7rem;
|
||||
right: -0.2rem;
|
||||
color: blue;
|
||||
font-size: 1.4rem;
|
||||
padding: 0.1rem;
|
||||
transform: rotate(17deg);
|
||||
svg {
|
||||
filter: drop-shadow( 1px 1px 1px rgba(0, 0, 0, .7));
|
||||
}
|
||||
}
|
||||
|
||||
.resource-unit-container {
|
||||
display: flex;
|
||||
flex-direction: row; }
|
||||
@@ -556,12 +639,17 @@ $tab-margin: 0.3rem;
|
||||
max-height: 80vh;
|
||||
@include breakpoint(medium down) {
|
||||
flex-grow: 2;
|
||||
max-width: 82vw;
|
||||
}
|
||||
@include breakpoint(large) {
|
||||
width: 26rem;
|
||||
}
|
||||
}
|
||||
|
||||
.trade-tab {
|
||||
min-width: 26rem;
|
||||
}
|
||||
|
||||
.static-tab-container {
|
||||
overflow-y: auto;
|
||||
max-height: 80vh;
|
||||
|
||||
@@ -46,7 +46,8 @@ module.exports = {
|
||||
chunkFilename: '[id].css',
|
||||
}),
|
||||
new CopyPlugin([
|
||||
{ from: './src/server/', to: './' },
|
||||
{ from: './src/server/farm.scm', to: './[name].[ext]' },
|
||||
{ from: './src/server/farm', to: './[name]' },
|
||||
{ from: './assets/game/', to: './assets/game/' }
|
||||
]),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
|
||||
Reference in New Issue
Block a user