New trading interface and moving bug fixes.

logins
Thomas Hintz 5 years ago
parent 1dc5d53f0d
commit 16897679e3

@ -31,7 +31,8 @@ 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, 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 { GroupBox, Row, Col, Button } from '../widgets.jsx'
import SpaceNode from './SpaceNode.jsx' import SpaceNode from './SpaceNode.jsx'
@ -40,7 +41,8 @@ import Tractor from '../tractor/Tractor.jsx'
import { GAME_STATES, ALERTS } from '../../constants.js' import { GAME_STATES, ALERTS } from '../../constants.js'
import { itemCard, itemCardShort, fateCard, ridgeNames } from 'game.js' import { itemCard, itemCardShort, fateCard, ridgeNames } from 'game.js'
import { setSelectedCard, setMessagePanelSpace, setMPDims, movePlayer, 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, import { buy, roll, endTurn, loan, trade, submitTradeAccept,
submitTradeDeny, submitTradeCancel, audit, submitTradeDeny, submitTradeCancel, audit,
buyUncleBert, skip } from './interface.js' buyUncleBert, skip } from './interface.js'
@ -174,7 +176,7 @@ 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;
return ( return (
<div className='resource-unit' <div className={'resource-unit ' + (this.props.className ? this.props.className : '')}
title={this.props.amount + ' ' + this.props.label} title={this.props.amount + ' ' + this.props.label}
style={{backgroundColor: hslString + '%, 85%)', style={{backgroundColor: hslString + '%, 85%)',
borderTop: '3px solid ' + hslString + '%, 55%)'}}> 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 { class CCBY extends React.Component {
render() { render() {
return ( return (
@ -1012,105 +1371,32 @@ class Harvest extends React.Component {
} }
} }
// props: currentPos, moveTo, color
// actions: movePlayer
class Moving extends React.Component { 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) { skip(preventAutoSkip) {
if (!preventAutoSkip) { if (!preventAutoSkip) {
skip('moving'); skip('moving');
} }
clearInterval(this.props.timerId); this.props.setMovingSkip(true);
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 });
}
} }
render() { render() {
let buttons; let buttons;
if (this.props.player.name !== this.props.game.currentPlayer) { if (this.props.player.name !== this.props.game.currentPlayer) {
buttons = (<Fragment />); 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>); buttons = (<Button onClick={() => this.props.showNextAction()}>Continue</Button>);
} else { } else {
buttons = (<Button onClick={() => this.skip()}>Skip</Button>); 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 ( return (
<Row> <Row>
<Col width={'12'}> <Col width={'12'}>
<div className='moving'> <div className='moving'>
<div className={'action clear-background'}> <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} /> height={'170px'} showtitle={true} />
</div> </div>
</div> </div>
@ -1242,6 +1528,7 @@ class Action extends React.Component {
autoSkip={this.props.ui.autoSkip} autoSkip={this.props.ui.autoSkip}
timerId={this.props.timerId} timerId={this.props.timerId}
setTimerId={this.props.setTimerId} setTimerId={this.props.setTimerId}
setMovingSkip={this.props.setMovingSkip}
ui={this.props.ui} />); ui={this.props.ui} />);
buttons = (<Fragment />); buttons = (<Fragment />);
break; break;
@ -1251,6 +1538,7 @@ class Action extends React.Component {
setTimerId={this.props.setTimerId} setTimerId={this.props.setTimerId}
player={this.props.player} player={this.props.player}
game={this.props.game} game={this.props.game}
setMovingSkip={this.props.setMovingSkip}
spaces={this.props.spaces} spaces={this.props.spaces}
movePlayer={this.props.movePlayer} movePlayer={this.props.movePlayer}
autoSkip={this.props.ui.autoSkip} autoSkip={this.props.ui.autoSkip}
@ -1311,7 +1599,7 @@ class Board extends React.Component {
(<SpaceNode showIcons={true} space={s} key={s.key} orientation={o} />); (<SpaceNode showIcons={true} space={s} key={s.key} orientation={o} />);
return ( return (
<Fragment> <Fragment>
<Row collapse='true' className='row-spaces'> <Row collapse='true' className='row-spaces'>
<Col width='1'>{renderSpace(this.props.spaces[0], rh, 'corner-tl')}</Col> <Col width='1'>{renderSpace(this.props.spaces[0], rh, 'corner-tl')}</Col>
<Col width='10'> <Col width='10'>
@ -1705,6 +1993,7 @@ class BoardApp extends React.Component {
otherPlayersTurn={this.props.player.name !== this.props.game.currentPlayer} otherPlayersTurn={this.props.player.name !== this.props.game.currentPlayer}
screen={this.state.screen} screen={this.state.screen}
showScreen={screen => this.showScreen(screen)} showScreen={screen => this.showScreen(screen)}
setMovingSkip={this.props.setMovingSkip}
ui={this.props.ui} />); ui={this.props.ui} />);
// faExchangeAlt -> trade icon, hidden for now // faExchangeAlt -> trade icon, hidden for now
return ( return (
@ -1768,8 +2057,8 @@ class BoardApp extends React.Component {
<FarmsContainer player={this.props.player} <FarmsContainer player={this.props.player}
otherPlayers={this.props.game.otherPlayers} /> otherPlayers={this.props.game.otherPlayers} />
</div> </div>
<div className={this.tabClass(SCREENS.trade)}> <div className={this.tabClass(SCREENS.trade) + ' trade-tab'}>
<TradeContainer player={this.props.player} game={this.props.game} /> <TradeContainer2 player={this.props.player} game={this.props.game} />
</div> </div>
<div className={this.tabClass(SCREENS.misc)}> <div className={this.tabClass(SCREENS.misc)}>
<Misc /> <Misc />
@ -1792,7 +2081,8 @@ class BoardApp extends React.Component {
export default connect( export default connect(
state => state.farm, state => state.farm,
{ setMessagePanelSpace, setMPDims, nextUIAction, movePlayer, alert, alertHandled, setCardError } { setMessagePanelSpace, setMPDims, nextUIAction, movePlayer, alert, alertHandled,
setCardError, setMovingSkip }
)(BoardApp) )(BoardApp)
class Card extends React.Component { class Card extends React.Component {

@ -38,3 +38,4 @@ export const ALERT_HANDLED = 'alert-handled'
export const AUTO_SKIP = 'auto-skip' export const AUTO_SKIP = 'auto-skip'
export const MESSAGE = 'message' export const MESSAGE = 'message'
export const SET_HARVEST_TABLE = 'set-harvest-table' 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, SPACE_PUSH_PLAYER, SPACE_CLEAR_PLAYERS, SET_OLD_MESSAGES, MESSAGE_PANEL_SPACE,
MP_MOUSE, SET_MP_DIMS, MARK_ACTION_CHANGE_HANDLED, SET_NEXT_ACTION, MP_MOUSE, SET_MP_DIMS, MARK_ACTION_CHANGE_HANDLED, SET_NEXT_ACTION,
MOVE_PLAYER, NEXT_UI_ACTION, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED, 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, export { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
spacePushPlayer, spaceClearPlayers, setOldMessages, setMessagePanelSpace, spacePushPlayer, spaceClearPlayers, setOldMessages, setMessagePanelSpace,
mpMouse, setMPDims, movePlayer, setNextAction, nextUIAction, mpMouse, setMPDims, movePlayer, setNextAction, nextUIAction,
markActionChangeHandled, nextUIActionSilent, alert, alertHandled, markActionChangeHandled, nextUIActionSilent, alert, alertHandled,
autoSkip, message, setHarvestTable, setCardError } autoSkip, message, setHarvestTable, setCardError, setMovingSkip }
function updateGame(update) { function updateGame(update) {
return { type: UPDATE_GAME, return { type: UPDATE_GAME,
@ -130,3 +131,7 @@ function message(message) {
function setHarvestTable(table) { function setHarvestTable(table) {
return { type: SET_HARVEST_TABLE, 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, import { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
movePlayer, setOldMessages, markActionChangeHandled, movePlayer, setOldMessages, markActionChangeHandled,
mpMouse, rolled, setNextAction, nextUIAction, nextUIActionSilent, alert, 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' import { itemCard, fateCard } from 'game.js'
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept, export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
@ -189,7 +190,9 @@ function initialize(st, sc) {
let lastAction = false, let lastAction = false,
lastAutoSkip = false, lastAutoSkip = false,
rollMessage = '', rollMessage = '',
rollTimer = false; rollTimer = false,
movingAction = { from: 99, to: 99 },
movingTimer = 0;
const unsubscribe = store.subscribe( const unsubscribe = store.subscribe(
() => { () => {
const state = store.getState(); const state = store.getState();
@ -265,6 +268,50 @@ function initialize(st, sc) {
break; 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 // 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_OLD_MESSAGES, MESSAGE_PANEL_SPACE, MP_MOUSE,
SET_MP_DIMS, MOVE_PLAYER, SET_NEXT_ACTION, NEXT_UI_ACTION, SET_MP_DIMS, MOVE_PLAYER, SET_NEXT_ACTION, NEXT_UI_ACTION,
MARK_ACTION_CHANGE_HANDLED, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED, 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 { GAME_STATES } from '../../constants.js'
import { spaceContent, corners } from 'game.js' import { spaceContent, corners } from 'game.js'
@ -121,6 +122,7 @@ const initialState = {
unhandledAlert: false, unhandledAlert: false,
autoSkip: false, autoSkip: false,
playerSpaces: {}, playerSpaces: {},
movingSkip: false,
harvestTable: false }, harvestTable: false },
spaces: spaces, spaces: spaces,
space: null, space: null,
@ -219,6 +221,8 @@ export default function(state = initialState, action) {
return { ...state, ui: { ...state.ui, message: action.message }}; return { ...state, ui: { ...state.ui, message: action.message }};
case SET_HARVEST_TABLE: case SET_HARVEST_TABLE:
return { ...state, ui: { ...state.ui, harvestTable: action.table }}; return { ...state, ui: { ...state.ui, harvestTable: action.table }};
case SET_MOVING_SKIP:
return { ...state, ui: { ...state.ui, movingSkip: action.skip }};
default: default:
return state; return state;
} }

@ -584,6 +584,16 @@
(when (alist-ref ridge params) (when (alist-ref ridge params)
(if (> (player-ridge player ridge) 0) (if (> (player-ridge player ridge) 0)
(begin (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) (safe-set! (player-ridges originator)
(alist-update ridge (alist-update ridge
(alist-ref ridge (player-ridges player)) (alist-ref ridge (player-ridges player))
@ -591,6 +601,16 @@
(safe-set! (player-ridges player) (safe-set! (player-ridges player)
(alist-update ridge 0 (player-ridges player)))) (alist-update ridge 0 (player-ridges player))))
(begin (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) (safe-set! (player-ridges player)
(alist-update ridge (alist-update ridge
(alist-ref ridge (player-ridges originator)) (alist-ref ridge (player-ridges originator))
@ -1903,17 +1923,11 @@
;; TODO ;; TODO
;; make sure two players can't have the same name ;; make sure two players can't have the same name
;; info actions should look better ;; info actions should look better
;; you can get $50 from harvest ;; you can get $50 from operating expense
;; moving bug 5 from oct 2 saw by player 2
;; from harvest moon rolled 5
;; finished
;; infinite loop ((?action . end-game) (?value . #<procedure (a10302)>))
;; auto-skip loop ;; auto-skip loop
;; harvester / tractor don't say total price ;; harvester / tractor don't say total price
;; mark spaces ;; mark spaces
;; trade notification keeps popping up ;; can't trade other player's ridge
;; show harvest multiplier

@ -268,8 +268,77 @@ $tab-margin: 0.3rem;
.player-trade-resources .resource-unit { .player-trade-resources .resource-unit {
display: inline-block; display: inline-block;
margin-bottom: 0.3rem;
width: 4rem; } 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 { .card-id {
position: absolute; position: absolute;
top: 10px; top: 10px;
@ -305,6 +374,7 @@ $tab-margin: 0.3rem;
} }
.resource-unit { .resource-unit {
position: relative;
text-align: center; text-align: center;
margin-right: 0.5rem; margin-right: 0.5rem;
width: 40px; width: 40px;
@ -313,6 +383,19 @@ $tab-margin: 0.3rem;
height: 34px; } 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 { .resource-unit-container {
display: flex; display: flex;
flex-direction: row; } flex-direction: row; }
@ -556,12 +639,17 @@ $tab-margin: 0.3rem;
max-height: 80vh; max-height: 80vh;
@include breakpoint(medium down) { @include breakpoint(medium down) {
flex-grow: 2; flex-grow: 2;
max-width: 82vw;
} }
@include breakpoint(large) { @include breakpoint(large) {
width: 26rem; width: 26rem;
} }
} }
.trade-tab {
min-width: 26rem;
}
.static-tab-container { .static-tab-container {
overflow-y: auto; overflow-y: auto;
max-height: 80vh; max-height: 80vh;

@ -46,7 +46,8 @@ module.exports = {
chunkFilename: '[id].css', chunkFilename: '[id].css',
}), }),
new CopyPlugin([ 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/' } { from: './assets/game/', to: './assets/game/' }
]), ]),
new webpack.LoaderOptionsPlugin({ new webpack.LoaderOptionsPlugin({

Loading…
Cancel
Save