Syncing multi-player actions.

logins
Thomas Hintz 5 years ago
parent b9cb7e842a
commit 2d8aee8c65

@ -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

Loading…
Cancel
Save