Syncing multi-player actions.
This commit is contained in:
@@ -43,7 +43,7 @@ import { setSelectedCard, setMessagePanelSpace, setMPDims, movePlayer,
|
|||||||
nextUIAction, alert } from './actions.js'
|
nextUIAction, alert } from './actions.js'
|
||||||
import { buy, roll, endTurn, loan, trade, submitTradeAccept,
|
import { buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||||
submitTradeDeny, submitTradeCancel, audit,
|
submitTradeDeny, submitTradeCancel, audit,
|
||||||
buyUncleBert } from './interface.js'
|
buyUncleBert, skip } 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) +
|
||||||
@@ -594,7 +594,9 @@ class Die extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { num: props.roll ? this.roll() : props.num,
|
this.state = { num: props.roll ? this.roll() : props.num,
|
||||||
finalFace: false }
|
finalFace: false,
|
||||||
|
autoSkip: typeof props.autoSkip === 'undefined' ? false :
|
||||||
|
props.autoSkip };
|
||||||
this.trigger = 1000 * this.speed[props.speed ? props.speed : 'fast']
|
this.trigger = 1000 * this.speed[props.speed ? props.speed : 'fast']
|
||||||
if (props.ms) {
|
if (props.ms) {
|
||||||
this.maxTicks = Math.floor(props.ms / this.trigger);
|
this.maxTicks = Math.floor(props.ms / this.trigger);
|
||||||
@@ -657,7 +659,10 @@ class Die extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skip() {
|
skip(preventAutoSkip) {
|
||||||
|
if (!preventAutoSkip) {
|
||||||
|
skip('die');
|
||||||
|
}
|
||||||
clearInterval(this.timerId);
|
clearInterval(this.timerId);
|
||||||
this.timerId = false;
|
this.timerId = false;
|
||||||
this.setState({ num: this.props.num, finalFace: true });
|
this.setState({ num: this.props.num, finalFace: true });
|
||||||
@@ -670,6 +675,16 @@ class Die extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 face;
|
let face;
|
||||||
switch (this.state.num) {
|
switch (this.state.num) {
|
||||||
@@ -751,6 +766,7 @@ class Rolling extends React.Component {
|
|||||||
<Die decay={true} num={this.props.num} ms={2000} roll={true}
|
<Die decay={true} num={this.props.num} ms={2000} roll={true}
|
||||||
showScreen={this.props.showScreen}
|
showScreen={this.props.showScreen}
|
||||||
skip={this.props.skip}
|
skip={this.props.skip}
|
||||||
|
autoSkip={this.props.autoSkip}
|
||||||
showScreenDelay={this.props.showScreenDelay} />
|
showScreenDelay={this.props.showScreenDelay} />
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
);
|
);
|
||||||
@@ -765,21 +781,43 @@ class Harvest extends React.Component {
|
|||||||
fruit: FruitImg,
|
fruit: FruitImg,
|
||||||
corn: CornImg }
|
corn: CornImg }
|
||||||
|
|
||||||
|
viewOrder = ['roll', 'income', 'operating-expense', 'expense-value', false]
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { view: 'ready' }
|
this.state = { view: 'ready',
|
||||||
|
autoSkip: typeof props.autoSkip === 'undefined' ? false :
|
||||||
|
props.autoSkip,
|
||||||
|
autoSkipView: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
nextView = view => {
|
nextView = (view, preventAutoSkip) => {
|
||||||
this.setState({ view });
|
const newView = view ? view :
|
||||||
|
this.viewOrder[this.viewOrder.indexOf(this.state.view) + 1];
|
||||||
|
this.setState({ view: newView });
|
||||||
|
if (!preventAutoSkip) {
|
||||||
|
skip('harvest|' + newView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cropToImg = crop => {
|
cropToImg = crop => {
|
||||||
return this.cropsToImg[crop];
|
return this.cropsToImg[crop];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
if (this.props.autoSkip &&
|
||||||
|
typeof this.props.autoSkip === 'string' &&
|
||||||
|
this.props.autoSkip.indexOf('harvest|') === 0 &&
|
||||||
|
this.state.autoSkipView !== this.props.autoSkip.split('|')[1]) {
|
||||||
|
this.nextView(this.props.autoSkip.split('|')[1], true);
|
||||||
|
this.setState({ autoSkipView: this.props.autoSkip.split('|')[1] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this.props.player.name === this.props.game.currentPlayer TODO
|
||||||
render() {
|
render() {
|
||||||
let view;
|
let view;
|
||||||
|
const isCurrentPlayer = this.props.player.name === this.props.game.currentPlayer;
|
||||||
switch (this.state.view) {
|
switch (this.state.view) {
|
||||||
case 'ready':
|
case 'ready':
|
||||||
view = (
|
view = (
|
||||||
@@ -791,7 +829,7 @@ class Harvest extends React.Component {
|
|||||||
Get ready to harvest <b>{this.props.acres}
|
Get ready to harvest <b>{this.props.acres}
|
||||||
{this.props.crop === 'cows' ? ' head of cow' : ' acres'}</b>!
|
{this.props.crop === 'cows' ? ' head of cow' : ' acres'}</b>!
|
||||||
</div>
|
</div>
|
||||||
{this.props.player.name === this.props.game.currentPlayer ? (
|
{isCurrentPlayer ? (
|
||||||
<Button onClick={() => this.nextView('roll')}>
|
<Button onClick={() => this.nextView('roll')}>
|
||||||
Roll for harvest!
|
Roll for harvest!
|
||||||
</Button>
|
</Button>
|
||||||
@@ -804,6 +842,7 @@ class Harvest extends React.Component {
|
|||||||
view = (<Die decay={true} num={this.props.rolled} ms={2000} roll={true}
|
view = (<Die decay={true} num={this.props.rolled} ms={2000} roll={true}
|
||||||
showScreen={() => this.nextView('income')}
|
showScreen={() => this.nextView('income')}
|
||||||
skip={true}
|
skip={true}
|
||||||
|
autoSkip={this.props.autoSkip === 'die'}
|
||||||
showScreenDelay={2000} />);
|
showScreenDelay={2000} />);
|
||||||
break;
|
break;
|
||||||
case 'income':
|
case 'income':
|
||||||
@@ -813,14 +852,16 @@ class Harvest extends React.Component {
|
|||||||
<div className={'flex green'}>
|
<div className={'flex green'}>
|
||||||
<FontAwesomeIcon icon={faDollarSign} size='6x' />
|
<FontAwesomeIcon icon={faDollarSign} size='6x' />
|
||||||
<div>
|
<div>
|
||||||
{this.props.player.name === this.props.game.currentPlayer ? 'You' :
|
{isCurrentPlayer ? 'You' :
|
||||||
this.props.game.currentPlayer} rolled a <b>{this.props.rolled}</b> and earned <b>${formatMoney(this.props.income)}</b>!
|
this.props.game.currentPlayer} rolled a <b>{this.props.rolled}</b> and earned <b>${formatMoney(this.props.income)}</b>!
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{isCurrentPlayer ? (
|
||||||
<div className='center spacer'>
|
<div className='center spacer'>
|
||||||
<Button onClick={() => this.nextView('operating-expense')}>Draw Operating Expense</Button>
|
<Button onClick={() => this.nextView('operating-expense')}>Draw Operating Expense</Button>
|
||||||
</div>
|
</div>
|
||||||
|
) : (<Fragment />)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@@ -833,9 +874,11 @@ class Harvest extends React.Component {
|
|||||||
dangerouslySetInnerHTML={{__html: this.props.contents}} />
|
dangerouslySetInnerHTML={{__html: this.props.contents}} />
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
</div>
|
</div>
|
||||||
|
{isCurrentPlayer ? (
|
||||||
<div className='center spacer'>
|
<div className='center spacer'>
|
||||||
<Button onClick={() => this.nextView('expense-value')}>Continue</Button>
|
<Button onClick={() => this.nextView('expense-value')}>Continue</Button>
|
||||||
</div>
|
</div>
|
||||||
|
) : (<Fragment />)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@@ -846,15 +889,17 @@ class Harvest extends React.Component {
|
|||||||
<div className={'flex ' + (this.props.expenseValue < 0 ? 'red' : 'green')}>
|
<div className={'flex ' + (this.props.expenseValue < 0 ? 'red' : 'green')}>
|
||||||
<FontAwesomeIcon icon={faDollarSign} size='6x' />
|
<FontAwesomeIcon icon={faDollarSign} size='6x' />
|
||||||
<div>
|
<div>
|
||||||
{this.props.player.name === this.props.game.currentPlayer ? 'You' :
|
{isCurrentPlayer ? 'You' :
|
||||||
this.props.game.currentPlayer} {this.props.expenseValue < 0 ? 'lost ' : 'gained '}
|
this.props.game.currentPlayer} {this.props.expenseValue < 0 ? 'lost ' : 'gained '}
|
||||||
${Math.abs(this.props.expenseValue)}!
|
${Math.abs(this.props.expenseValue)}!
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{isCurrentPlayer ? (
|
||||||
<div className='center spacer'>
|
<div className='center spacer'>
|
||||||
<Button onClick={this.props.nextAction}>Continue</Button>
|
<Button onClick={this.props.nextAction}>Continue</Button>
|
||||||
</div>
|
</div>
|
||||||
|
) : (<Fragment />)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@@ -879,7 +924,9 @@ class Moving extends React.Component {
|
|||||||
this.props.player : this.props.game.otherPlayers
|
this.props.player : this.props.game.otherPlayers
|
||||||
.find(p => p.player.name === this.props.game.currentPlayer).player;
|
.find(p => p.player.name === this.props.game.currentPlayer).player;
|
||||||
const currentPos = from;
|
const currentPos = from;
|
||||||
this.state = { currentPos: currentPos < 0 ? currentPos + 49 : currentPos };
|
this.state = { currentPos: currentPos < 0 ? currentPos + 49 : currentPos,
|
||||||
|
autoSkip: typeof props.autoSkip === 'undefined' ? false :
|
||||||
|
props.autoSkip };
|
||||||
this.endPos = to;
|
this.endPos = to;
|
||||||
this.color = currentPlayer.color;
|
this.color = currentPlayer.color;
|
||||||
// only for hurt back do we go backwards
|
// only for hurt back do we go backwards
|
||||||
@@ -923,13 +970,26 @@ class Moving extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skip() {
|
skip(preventAutoSkip) {
|
||||||
|
if (!preventAutoSkip) {
|
||||||
|
skip('moving');
|
||||||
|
}
|
||||||
clearInterval(this.timerId);
|
clearInterval(this.timerId);
|
||||||
this.timerId = false;
|
this.timerId = false;
|
||||||
this.props.movePlayer(this.endPos, this.state.currentPos, this.color);
|
this.props.movePlayer(this.endPos, this.state.currentPos, this.color);
|
||||||
this.setState({ currentPos: this.endPos });
|
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) {
|
||||||
@@ -1036,6 +1096,7 @@ class Action extends React.Component {
|
|||||||
break;
|
break;
|
||||||
case 'harvest':
|
case 'harvest':
|
||||||
view = (<Harvest rolled={this.props.ui.actionValue.rolled}
|
view = (<Harvest rolled={this.props.ui.actionValue.rolled}
|
||||||
|
autoSkip={this.props.ui.autoSkip}
|
||||||
player={this.props.player}
|
player={this.props.player}
|
||||||
game={this.props.game}
|
game={this.props.game}
|
||||||
income={this.props.ui.actionValue.income}
|
income={this.props.ui.actionValue.income}
|
||||||
@@ -1043,6 +1104,7 @@ class Action extends React.Component {
|
|||||||
expenseValue={this.props.ui.actionValue.operatingExpenseValue}
|
expenseValue={this.props.ui.actionValue.operatingExpenseValue}
|
||||||
crop={this.props.ui.actionValue.crop}
|
crop={this.props.ui.actionValue.crop}
|
||||||
acres={this.props.ui.actionValue.acres}
|
acres={this.props.ui.actionValue.acres}
|
||||||
|
autoSkip={this.props.ui.autoSkip}
|
||||||
nextAction={() => this.props.showNextAction()} />);
|
nextAction={() => this.props.showNextAction()} />);
|
||||||
buttons = (<Fragment />);
|
buttons = (<Fragment />);
|
||||||
break;
|
break;
|
||||||
@@ -1053,6 +1115,7 @@ class Action extends React.Component {
|
|||||||
game={this.props.game}
|
game={this.props.game}
|
||||||
spaces={this.props.spaces}
|
spaces={this.props.spaces}
|
||||||
movePlayer={this.props.movePlayer}
|
movePlayer={this.props.movePlayer}
|
||||||
|
autoSkip={this.props.ui.autoSkip}
|
||||||
ui={this.props.ui}/>);
|
ui={this.props.ui}/>);
|
||||||
buttons = (<Fragment />);
|
buttons = (<Fragment />);
|
||||||
break;
|
break;
|
||||||
@@ -1063,6 +1126,7 @@ class Action extends React.Component {
|
|||||||
game={this.props.game}
|
game={this.props.game}
|
||||||
spaces={this.props.spaces}
|
spaces={this.props.spaces}
|
||||||
movePlayer={this.props.movePlayer}
|
movePlayer={this.props.movePlayer}
|
||||||
|
autoSkip={this.props.ui.autoSkip}
|
||||||
ui={this.props.ui} />);
|
ui={this.props.ui} />);
|
||||||
buttons = (<Fragment />);
|
buttons = (<Fragment />);
|
||||||
break;
|
break;
|
||||||
@@ -1079,6 +1143,7 @@ class Action extends React.Component {
|
|||||||
showScreen={this.props.player.name === this.props.game.currentPlayer
|
showScreen={this.props.player.name === this.props.game.currentPlayer
|
||||||
? () => this.props.showNextAction()
|
? () => this.props.showNextAction()
|
||||||
: false}
|
: false}
|
||||||
|
autoSkip={this.props.ui.autoSkip}
|
||||||
skip={this.props.player.name === this.props.game.currentPlayer}
|
skip={this.props.player.name === this.props.game.currentPlayer}
|
||||||
showScreenDelay={2000} />);
|
showScreenDelay={2000} />);
|
||||||
buttons = (<Fragment />);
|
buttons = (<Fragment />);
|
||||||
|
|||||||
@@ -34,3 +34,4 @@ export const NEXT_UI_ACTION_SILENT = 'next-ui-action-silent'
|
|||||||
export const MARK_ACTION_CHANGE_HANDLED = 'mark-action-change-handled'
|
export const MARK_ACTION_CHANGE_HANDLED = 'mark-action-change-handled'
|
||||||
export const ALERT = 'alert'
|
export const ALERT = 'alert'
|
||||||
export const ALERT_HANDLED = 'alert-handled'
|
export const ALERT_HANDLED = 'alert-handled'
|
||||||
|
export const AUTO_SKIP = 'auto-skip'
|
||||||
|
|||||||
@@ -19,13 +19,14 @@
|
|||||||
import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
|
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,
|
||||||
} from './actionTypes.js'
|
AUTO_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 }
|
||||||
|
|
||||||
function updateGame(update) {
|
function updateGame(update) {
|
||||||
return { type: UPDATE_GAME,
|
return { type: UPDATE_GAME,
|
||||||
@@ -113,3 +114,7 @@ function alert(value) {
|
|||||||
function alertHandled() {
|
function alertHandled() {
|
||||||
return { type: ALERT_HANDLED };
|
return { type: ALERT_HANDLED };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function autoSkip(component) {
|
||||||
|
return { type: AUTO_SKIP, component };
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ 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,
|
||||||
} from './actions.js'
|
autoSkip } from './actions.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 }
|
nextAction, buyUncleBert, actionsFinished, skip }
|
||||||
|
|
||||||
let store;
|
let store;
|
||||||
|
|
||||||
@@ -94,6 +94,9 @@ function handleMessage(evt) {
|
|||||||
!store.getState().farm.ui.nextAction) {
|
!store.getState().farm.ui.nextAction) {
|
||||||
store.dispatch(alert(ALERTS.raiseMoney));
|
store.dispatch(alert(ALERTS.raiseMoney));
|
||||||
}
|
}
|
||||||
|
if (data.event === 'auto-skip') {
|
||||||
|
store.dispatch(autoSkip(data.component));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -151,6 +154,10 @@ function actionsFinished() {
|
|||||||
sendCommand({ type: 'actions-finished' });
|
sendCommand({ type: 'actions-finished' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function skip(component) {
|
||||||
|
sendCommand({ type: 'skip', component });
|
||||||
|
}
|
||||||
|
|
||||||
function initialize(st, sc) {
|
function initialize(st, sc) {
|
||||||
store = st;
|
store = st;
|
||||||
sendCommand = sc;
|
sendCommand = sc;
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
|
|||||||
SPACE_PUSH_PLAYER, SPACE_CLEAR_PLAYERS,
|
SPACE_PUSH_PLAYER, SPACE_CLEAR_PLAYERS,
|
||||||
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,
|
||||||
} from './actionTypes.js'
|
AUTO_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'
|
||||||
|
|
||||||
@@ -108,6 +108,7 @@ const initialState = {
|
|||||||
nextActionValue: null,
|
nextActionValue: null,
|
||||||
actionChangeHandled: true,
|
actionChangeHandled: true,
|
||||||
alert: false,
|
alert: false,
|
||||||
|
autoSkip: false,
|
||||||
alertHandled: false },
|
alertHandled: false },
|
||||||
spaces: spaces,
|
spaces: spaces,
|
||||||
space: null,
|
space: null,
|
||||||
@@ -164,6 +165,7 @@ export default function(state = initialState, action) {
|
|||||||
case NEXT_UI_ACTION:
|
case NEXT_UI_ACTION:
|
||||||
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
|
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
|
||||||
actionValue: state.ui.nextActionValue,
|
actionValue: state.ui.nextActionValue,
|
||||||
|
autoSkip: false,
|
||||||
actionChangeHandled: !state.ui.nextAction }};
|
actionChangeHandled: !state.ui.nextAction }};
|
||||||
case NEXT_UI_ACTION_SILENT: // don't set actionChangeHandled
|
case NEXT_UI_ACTION_SILENT: // don't set actionChangeHandled
|
||||||
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
|
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
|
||||||
@@ -176,6 +178,8 @@ export default function(state = initialState, action) {
|
|||||||
alertHandled: action.value === false ? true : false }};
|
alertHandled: action.value === false ? true : false }};
|
||||||
case ALERT_HANDLED:
|
case ALERT_HANDLED:
|
||||||
return { ...state, ui: { ...state.ui, alertHandled: true }};
|
return { ...state, ui: { ...state.ui, alertHandled: true }};
|
||||||
|
case AUTO_SKIP:
|
||||||
|
return { ...state, ui: { ...state.ui, autoSkip: action.component }};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ function handleMessage(evt) {
|
|||||||
} else if (data.event === 'new-game-started') {
|
} else if (data.event === 'new-game-started') {
|
||||||
initialize(store, Ws.sendCommand);
|
initialize(store, Ws.sendCommand);
|
||||||
Ws.setMainOnMessage(handleMessageFarm);
|
Ws.setMainOnMessage(handleMessageFarm);
|
||||||
|
Ws.openSecondary('push-web-socket');
|
||||||
Ws.setSecondaryOnMessage(handleMessageFarm);
|
Ws.setSecondaryOnMessage(handleMessageFarm);
|
||||||
Ws.sendCommand({ type: 'init' })
|
Ws.sendCommand({ type: 'init' })
|
||||||
store.dispatch(play());
|
store.dispatch(play());
|
||||||
@@ -95,7 +96,5 @@ function handleMessage(evt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ws.openMain('web-socket');
|
Ws.openMain('web-socket');
|
||||||
Ws.openSecondary('push-web-socket');
|
|
||||||
Ws.setMainOnMessage(handleMessage);
|
Ws.setMainOnMessage(handleMessage);
|
||||||
Ws.setSecondaryOnMessage(handleMessage);
|
|
||||||
Ws.setMainOnOpen(() => Ws.sendCommand({ type: 'main-init' }));
|
Ws.setMainOnOpen(() => Ws.sendCommand({ type: 'main-init' }));
|
||||||
|
|||||||
@@ -20,7 +20,8 @@
|
|||||||
(import chicken scheme srfi-1 data-structures)
|
(import chicken scheme srfi-1 data-structures)
|
||||||
(use http-session srfi-69 coops uri-common
|
(use http-session srfi-69 coops uri-common
|
||||||
srfi-18 medea numbers spiffy spiffy-cookies
|
srfi-18 medea numbers spiffy spiffy-cookies
|
||||||
intarweb pll sxml-transforms websockets miscmacros)
|
intarweb pll sxml-transforms websockets miscmacros
|
||||||
|
mailbox)
|
||||||
|
|
||||||
(cond-expand
|
(cond-expand
|
||||||
(geiser
|
(geiser
|
||||||
@@ -76,7 +77,7 @@
|
|||||||
(trade initform: '() accessor: player-trade)
|
(trade initform: '() accessor: player-trade)
|
||||||
(last-updated initform: 0 accessor: player-last-updated)
|
(last-updated initform: 0 accessor: player-last-updated)
|
||||||
(last-cash initform: 5000 accessor: player-last-cash)
|
(last-cash initform: 5000 accessor: player-last-cash)
|
||||||
(last-ui-action initform: #f accessor: player-last-ui-action)))
|
(mailbox initform: (make-mailbox) accessor: player-mailbox)))
|
||||||
|
|
||||||
(define-class <game> ()
|
(define-class <game> ()
|
||||||
((id initform: 0 accessor: game-id)
|
((id initform: 0 accessor: game-id)
|
||||||
@@ -94,8 +95,7 @@
|
|||||||
(state initform: 'playing accessor: game-state)
|
(state initform: 'playing accessor: game-state)
|
||||||
(name initform: "game" accessor: game-name)
|
(name initform: "game" accessor: game-name)
|
||||||
(turn initform: 1 accessor: game-turn)
|
(turn initform: 1 accessor: game-turn)
|
||||||
(actions initform: '() accessor: game-actions)
|
(actions initform: '() accessor: game-actions)))
|
||||||
(last-ui-action initform: #f accessor: game-last-ui-action)))
|
|
||||||
|
|
||||||
(define-class <app> ()
|
(define-class <app> ()
|
||||||
((games initform: '() accessor: app-games)
|
((games initform: '() accessor: app-games)
|
||||||
@@ -152,9 +152,6 @@
|
|||||||
(set-cookie! (session-cookie-name) sid))))
|
(set-cookie! (session-cookie-name) sid))))
|
||||||
(session-lifetime (* 60 60 24 7 4))
|
(session-lifetime (* 60 60 24 7 4))
|
||||||
|
|
||||||
(define update-condition-variable (make-condition-variable))
|
|
||||||
(define update-mutex (make-mutex))
|
|
||||||
|
|
||||||
(access-log (current-output-port))
|
(access-log (current-output-port))
|
||||||
|
|
||||||
(handle-not-found
|
(handle-not-found
|
||||||
@@ -641,15 +638,11 @@
|
|||||||
(players . ,(list->vector
|
(players . ,(list->vector
|
||||||
(map player-name (game-players game))))))
|
(map player-name (game-players game))))))
|
||||||
(app-games *app*))))))))
|
(app-games *app*))))))))
|
||||||
|
(define (message-players! game player message #!key (type "action"))
|
||||||
(define (set-ui-action! action game)
|
(for-each (lambda (p)
|
||||||
(set! (game-last-ui-action game) action))
|
(when (not (eq? p player))
|
||||||
|
(mailbox-send! (player-mailbox p) `((type . ,type) (value . ,message)))))
|
||||||
(define (ui-action game)
|
(game-players game)))
|
||||||
(game-last-ui-action game))
|
|
||||||
|
|
||||||
(define (new-ui-action? player action)
|
|
||||||
(not (eq? (player-last-ui-action player) action)))
|
|
||||||
|
|
||||||
(define *next-roll* #f)
|
(define *next-roll* #f)
|
||||||
|
|
||||||
@@ -681,16 +674,16 @@
|
|||||||
(append (game-actions game)
|
(append (game-actions game)
|
||||||
`(((?action . move) (?value . ,resp)))
|
`(((?action . move) (?value . ,resp)))
|
||||||
(sort-actions (get-actions player (player-space player)))))
|
(sort-actions (get-actions player (player-space player)))))
|
||||||
(set-ui-action! `((action . "roll")
|
(message-players! game player
|
||||||
(value . ,resp))
|
`((action . "roll")
|
||||||
game)
|
(value . ,resp)))
|
||||||
(create-ws-response player "action" `((action . "roll") (value . ,resp))))))
|
(create-ws-response player "action" `((action . "roll") (value . ,resp))))))
|
||||||
((and (string=? type "next-action")
|
((and (string=? type "next-action")
|
||||||
(not (eq? (player-state player) 'turn-ended)))
|
(not (eq? (player-state player) 'turn-ended)))
|
||||||
(let loop ()
|
(let loop ()
|
||||||
(if (null? (game-actions game))
|
(if (null? (game-actions game))
|
||||||
(begin
|
(begin
|
||||||
(set-ui-action! `((action . #f) (value . #f)) game)
|
(message-players! game player `((action . #f) (value . #f)))
|
||||||
(create-ws-response player "action" '((action . #f))))
|
(create-ws-response player "action" '((action . #f))))
|
||||||
(let* ((action (car (game-actions game)))
|
(let* ((action (car (game-actions game)))
|
||||||
(name (alist-ref '?action action))
|
(name (alist-ref '?action action))
|
||||||
@@ -701,22 +694,23 @@
|
|||||||
(set! (game-actions game) (cdr (game-actions game)))
|
(set! (game-actions game) (cdr (game-actions game)))
|
||||||
(if otb
|
(if otb
|
||||||
(begin
|
(begin
|
||||||
(set-ui-action! `((action . "otb")
|
(message-players! game player
|
||||||
(value . ,(alist-ref 'contents otb)))
|
`((action . "otb")
|
||||||
game)
|
(value . ,(alist-ref 'contents otb))))
|
||||||
(create-ws-response player "action"
|
(create-ws-response player "action"
|
||||||
`((action . "otb")
|
`((action . "otb")
|
||||||
(value . ,(alist-ref 'contents otb)))))
|
(value . ,(alist-ref 'contents otb)))))
|
||||||
(begin
|
(begin
|
||||||
(set-ui-action! `((action . "info")
|
(message-players! game player
|
||||||
(value . ,(conc "Out of " *item-card-short* "'s.")))
|
`((action . "info")
|
||||||
game)
|
(value . ,(conc "Out of " *item-card-short* "'s."))))
|
||||||
(create-ws-response player "action"
|
(create-ws-response player "action"
|
||||||
`((action . "info")
|
`((action . "info")
|
||||||
(value . ,(conc "Out of " *item-card-short* "'s."))))))))
|
(value . ,(conc "Out of " *item-card-short* "'s."))))))))
|
||||||
((eq? name 'move)
|
((eq? name 'move)
|
||||||
(set! (game-actions game) (cdr (game-actions game)))
|
(set! (game-actions game) (cdr (game-actions game)))
|
||||||
(set-ui-action! `((action . "move") (value . ,value)) game)
|
(message-players! game player
|
||||||
|
`((action . "move") (value . ,value)))
|
||||||
(create-ws-response player "action"
|
(create-ws-response player "action"
|
||||||
`((action . "move") (value . ,value))))
|
`((action . "move") (value . ,value))))
|
||||||
((eq? name 'harvest)
|
((eq? name 'harvest)
|
||||||
@@ -725,8 +719,9 @@
|
|||||||
(if (eq? res 'nothing)
|
(if (eq? res 'nothing)
|
||||||
(loop)
|
(loop)
|
||||||
(begin
|
(begin
|
||||||
(set-ui-action!
|
(message-players!
|
||||||
`((action . "harvest") (value . ,res)) game)
|
game player
|
||||||
|
`((action . "harvest") (value . ,res)))
|
||||||
(create-ws-response player
|
(create-ws-response player
|
||||||
"action"
|
"action"
|
||||||
`((action . "harvest")
|
`((action . "harvest")
|
||||||
@@ -740,10 +735,10 @@
|
|||||||
(if (= (- (player-cash player) previous-cash) 0)
|
(if (= (- (player-cash player) previous-cash) 0)
|
||||||
(loop)
|
(loop)
|
||||||
(begin
|
(begin
|
||||||
(set-ui-action! `((action . "money")
|
(message-players! game player
|
||||||
|
`((action . "money")
|
||||||
(value . ,(- (player-cash player)
|
(value . ,(- (player-cash player)
|
||||||
previous-cash)))
|
previous-cash))))
|
||||||
game)
|
|
||||||
(create-ws-response player "action"
|
(create-ws-response player "action"
|
||||||
`((action . "money")
|
`((action . "money")
|
||||||
(value . ,(- (player-cash player)
|
(value . ,(- (player-cash player)
|
||||||
@@ -758,9 +753,9 @@
|
|||||||
(set! (game-actions game)
|
(set! (game-actions game)
|
||||||
(append (alist-ref 'actions ff)
|
(append (alist-ref 'actions ff)
|
||||||
(cdr (game-actions game))))
|
(cdr (game-actions game))))
|
||||||
(set-ui-action! `((action . "farmers-fate")
|
(message-players! game player
|
||||||
(value . ,(alist-ref 'contents ff)))
|
`((action . "farmers-fate")
|
||||||
game)
|
(value . ,(alist-ref 'contents ff))))
|
||||||
(create-ws-response player "action"
|
(create-ws-response player "action"
|
||||||
`((action . "farmers-fate")
|
`((action . "farmers-fate")
|
||||||
(value . ,(alist-ref 'contents ff))))))
|
(value . ,(alist-ref 'contents ff))))))
|
||||||
@@ -769,21 +764,22 @@
|
|||||||
(if (= value 0)
|
(if (= value 0)
|
||||||
(loop)
|
(loop)
|
||||||
(begin
|
(begin
|
||||||
(set-ui-action! `((action . "money") (value . ,value))
|
(message-players! game player
|
||||||
game)
|
`((action . "money") (value . ,value)))
|
||||||
(create-ws-response player "action"
|
(create-ws-response player "action"
|
||||||
`((action . "money")
|
`((action . "money")
|
||||||
(value . ,value))))))
|
(value . ,value))))))
|
||||||
((eq? name 'ff-uncle-bert)
|
((eq? name 'ff-uncle-bert)
|
||||||
(set! (game-actions game) (cdr (game-actions game)))
|
(set! (game-actions game) (cdr (game-actions game)))
|
||||||
(set-ui-action! `((action . "ff-uncle-bert") (value . #f))
|
(message-players! game player
|
||||||
game)
|
`((action . "ff-uncle-bert") (value . #f)))
|
||||||
(create-ws-response player "action"
|
(create-ws-response player "action"
|
||||||
`((action . "ff-uncle-bert")
|
`((action . "ff-uncle-bert")
|
||||||
(value . #f))))
|
(value . #f))))
|
||||||
((eq? name 'info)
|
((eq? name 'info)
|
||||||
(set! (game-actions game) (cdr (game-actions game)))
|
(set! (game-actions game) (cdr (game-actions game)))
|
||||||
(set-ui-action! `((action . "info") (value . ,value)) game)
|
(message-players! game player
|
||||||
|
`((action . "info") (value . ,value)))
|
||||||
(create-ws-response player "action"
|
(create-ws-response player "action"
|
||||||
`((action . "info")
|
`((action . "info")
|
||||||
(value . ,value))))
|
(value . ,value))))
|
||||||
@@ -795,9 +791,8 @@
|
|||||||
(cdr (game-actions game))))
|
(cdr (game-actions game))))
|
||||||
(let ((resp `((from . ,(player-previous-space player))
|
(let ((resp `((from . ,(player-previous-space player))
|
||||||
(to . ,(player-space player)))))
|
(to . ,(player-space player)))))
|
||||||
(set-ui-action! `((action . "goto")
|
(message-players! game player `((action . "goto")
|
||||||
(value . ,resp))
|
(value . ,resp)))
|
||||||
game)
|
|
||||||
(create-ws-response player "action"
|
(create-ws-response player "action"
|
||||||
`((action . "goto")
|
`((action . "goto")
|
||||||
(value . ,resp)))))
|
(value . ,resp)))))
|
||||||
@@ -807,6 +802,10 @@
|
|||||||
(loop))
|
(loop))
|
||||||
(else ;; TODO make error
|
(else ;; TODO make error
|
||||||
(create-ws-response player "action" `((action . ,name)))))))))
|
(create-ws-response player "action" `((action . ,name)))))))))
|
||||||
|
((string=? type "skip")
|
||||||
|
(message-players! game player `((component . ,(alist-ref 'component msg)))
|
||||||
|
type: "auto-skip")
|
||||||
|
(create-ws-response player "update" '()))
|
||||||
((string=? type "buy")
|
((string=? type "buy")
|
||||||
(let* ((id (alist-ref 'id msg))
|
(let* ((id (alist-ref 'id msg))
|
||||||
(otb (find (lambda (x) (= id (alist-ref 'id x)))
|
(otb (find (lambda (x) (= id (alist-ref 'id x)))
|
||||||
@@ -828,12 +827,14 @@
|
|||||||
(set! (player-otbs player)
|
(set! (player-otbs player)
|
||||||
(filter (lambda (x) (not (= id (alist-ref 'id x))))
|
(filter (lambda (x) (not (= id (alist-ref 'id x))))
|
||||||
(player-otbs player)))))
|
(player-otbs player)))))
|
||||||
|
(message-players! game player '() type: "update")
|
||||||
(create-ws-response player "buy" '()))
|
(create-ws-response player "buy" '()))
|
||||||
((string=? type "buy-uncle-bert")
|
((string=? type "buy-uncle-bert")
|
||||||
(set! (player-cash player) (- (player-cash player) 10000))
|
(set! (player-cash player) (- (player-cash player) 10000))
|
||||||
(set! (player-assets player)
|
(set! (player-assets player)
|
||||||
(alist-update 'hay (+ (alist-ref 'hay (player-assets player)) 10)
|
(alist-update 'hay (+ (alist-ref 'hay (player-assets player)) 10)
|
||||||
(player-assets player)))
|
(player-assets player)))
|
||||||
|
(message-players! game player '() type: "update")
|
||||||
(create-ws-response player "buy" '()))
|
(create-ws-response player "buy" '()))
|
||||||
((string=? type "actions-finished")
|
((string=? type "actions-finished")
|
||||||
(create-ws-response player "update" '()))
|
(create-ws-response player "update" '()))
|
||||||
@@ -859,9 +860,11 @@
|
|||||||
(create-ws-response player "loan" '()))
|
(create-ws-response player "loan" '()))
|
||||||
((string=? type "trade")
|
((string=? type "trade")
|
||||||
(propose-trade game player (alist-ref 'parameters msg))
|
(propose-trade game player (alist-ref 'parameters msg))
|
||||||
|
(message-players! game player '() type: "update")
|
||||||
(create-ws-response player "trade" '()))
|
(create-ws-response player "trade" '()))
|
||||||
((string=? type "trade-accept")
|
((string=? type "trade-accept")
|
||||||
(accept-trade game player)
|
(accept-trade game player)
|
||||||
|
(message-players! game player '() type: "update")
|
||||||
(create-ws-response player "trade-accepted" '()))
|
(create-ws-response player "trade-accepted" '()))
|
||||||
((string=? type "trade-deny")
|
((string=? type "trade-deny")
|
||||||
(push-message player (conc (player-name player) " denied trade with "
|
(push-message player (conc (player-name player) " denied trade with "
|
||||||
@@ -870,6 +873,7 @@
|
|||||||
game (alist-ref 'originator (player-trade player))))
|
game (alist-ref 'originator (player-trade player))))
|
||||||
'())
|
'())
|
||||||
(set! (player-trade player) '())
|
(set! (player-trade player) '())
|
||||||
|
(message-players! game player '() type: "update")
|
||||||
(create-ws-response player "trade-denied" '()))
|
(create-ws-response player "trade-denied" '()))
|
||||||
((string=? type "trade-cancel")
|
((string=? type "trade-cancel")
|
||||||
(push-message player (conc (player-name player) " cancelled trade with "
|
(push-message player (conc (player-name player) " cancelled trade with "
|
||||||
@@ -878,16 +882,19 @@
|
|||||||
game (alist-ref 'player (player-trade player))))
|
game (alist-ref 'player (player-trade player))))
|
||||||
'())
|
'())
|
||||||
(set! (player-trade player) '())
|
(set! (player-trade player) '())
|
||||||
|
(message-players! game player '() type: "update")
|
||||||
(create-ws-response player "trade-cancelled" '()))
|
(create-ws-response player "trade-cancelled" '()))
|
||||||
((string=? type "audit")
|
((string=? type "audit")
|
||||||
(call-audit game player)
|
(call-audit game player)
|
||||||
|
(message-players! game player '() type: "update")
|
||||||
(create-ws-response player "called-audit" '()))
|
(create-ws-response player "called-audit" '()))
|
||||||
((string=? type "init")
|
((string=? type "init")
|
||||||
(create-ws-response player "init" '()))
|
(create-ws-response player "init" '()))
|
||||||
((string=? type "turn-ended")
|
((string=? type "turn-ended")
|
||||||
(if (>= (player-cash player) 0)
|
(if (>= (player-cash player) 0)
|
||||||
(begin (advance-turn game player)
|
(begin (advance-turn game player)
|
||||||
(create-ws-response player "turn-ended" '()))
|
(message-players! game player '() type: "update")
|
||||||
|
(create-ws-response player "update" '()))
|
||||||
(begin (push-message player "Cannot end a turn with negative cash!")
|
(begin (push-message player "Cannot end a turn with negative cash!")
|
||||||
(create-ws-response player "update" '()))))
|
(create-ws-response player "update" '()))))
|
||||||
;;;;;;;;;;;;;;;;;;;;; start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;; start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -969,8 +976,7 @@
|
|||||||
msg)))
|
msg)))
|
||||||
(when game
|
(when game
|
||||||
(set! (game-last-updated game) (+ (game-last-updated game) 1))
|
(set! (game-last-updated game) (+ (game-last-updated game) 1))
|
||||||
(set! (player-last-updated player) (game-last-updated game))
|
(set! (player-last-updated player) (game-last-updated game)))
|
||||||
(condition-variable-broadcast! update-condition-variable))
|
|
||||||
res)))))
|
res)))))
|
||||||
(loop (read-json (receive-message)))))))
|
(loop (read-json (receive-message)))))))
|
||||||
|
|
||||||
@@ -981,7 +987,8 @@
|
|||||||
(lambda ()
|
(lambda ()
|
||||||
(let ((game (session-ref (sid) 'game))
|
(let ((game (session-ref (sid) 'game))
|
||||||
(player (session-ref (sid) 'player)))
|
(player (session-ref (sid) 'player)))
|
||||||
(let loop ((updated (mutex-unlock! update-mutex update-condition-variable)))
|
(let loop ((msg (mailbox-receive! (player-mailbox player))))
|
||||||
|
(print msg)
|
||||||
(when (not game)
|
(when (not game)
|
||||||
(set! game (session-ref (sid) 'game)))
|
(set! game (session-ref (sid) 'game)))
|
||||||
(when (not player)
|
(when (not player)
|
||||||
@@ -1005,16 +1012,11 @@
|
|||||||
(print-call-chain)
|
(print-call-chain)
|
||||||
(print-error-message exn))))
|
(print-error-message exn))))
|
||||||
(event . "error"))
|
(event . "error"))
|
||||||
(if (and (new-ui-action? player (ui-action game))
|
|
||||||
(or (eq? (player-state player) 'turn-ended)
|
|
||||||
(eq? (player-state player) 'finished-game)))
|
|
||||||
(begin
|
|
||||||
(set! (player-last-ui-action player) (ui-action game))
|
|
||||||
(create-ws-response player
|
(create-ws-response player
|
||||||
"action"
|
(alist-ref 'type msg)
|
||||||
(ui-action game)))
|
(alist-ref 'value msg))
|
||||||
(create-ws-response player "update" '())))))))
|
)))))
|
||||||
(loop (mutex-unlock! update-mutex update-condition-variable)))))))
|
(loop (mailbox-receive! (player-mailbox player))))))))
|
||||||
|
|
||||||
(define (otb-spec->otb-cards spec id)
|
(define (otb-spec->otb-cards spec id)
|
||||||
`((contents . ,(sxml->html* (list-ref spec 5)))
|
`((contents . ,(sxml->html* (list-ref spec 5)))
|
||||||
@@ -1709,7 +1711,6 @@
|
|||||||
;; TODO
|
;; TODO
|
||||||
;; make game finished display results.
|
;; make game finished display results.
|
||||||
;; make sure two players can't have the same name
|
;; make sure two players can't have the same name
|
||||||
;; bug: harvest action multiplayer doesn't flow right for other players
|
|
||||||
;; info actions should look better
|
;; info actions should look better
|
||||||
;; you can get $50 from harvest
|
;; you can get $50 from harvest
|
||||||
;; bug: new websocket messages should not reset IFS card selection
|
;; bug: new websocket messages should not reset IFS card selection
|
||||||
|
|||||||
Reference in New Issue
Block a user