Initial public release.

This commit is contained in:
2020-02-05 18:04:50 -08:00
commit de7cf70319
173 changed files with 35469 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React, { Fragment } from 'react'
import { connect } from 'react-redux'
import Board from '../farm/Board.jsx'
import MessagePanel from '../farm/MessagePanel.jsx'
import CreateOrJoin from '../create-or-join/CreateOrJoin.jsx'
import NewGame from '../new-game/NewGame.jsx'
import JoinGame from '../join-game/JoinGame.jsx'
import Welcome from '../welcome/Welcome.jsx'
import Tractor from '../tractor/Tractor.jsx'
import { SCREENS, messagePanelId } from '../../constants.js'
import { play } from './actions.js'
class Chrome extends React.Component {
render() {
return (
<div className='flex-fullcenter'>
<div className='background-heading'><h1>Alpha Centauri Farming</h1></div>
{this.props.children}
<Tractor spikes={this.props.spikes} className={this.props.tractorClass} />
</div>
);
}
}
class App extends React.Component {
render() {
let view;
switch (this.props.screen) {
case SCREENS.intro:
view = (<Chrome spikes={true} tractorClass='intro'><Welcome /></Chrome>);
break;
case SCREENS.start:
view = (<Chrome><CreateOrJoin /></Chrome>);
break;
case SCREENS.newGame:
view = (<Chrome>
<div className='view-container'>
<NewGame colors={['green', 'red', 'blue', 'yellow', 'black']}
button={'Start'}
title={'New Game'}
type={'new-game'}
showGameName={true} />
</div>
</Chrome>);
break;
case SCREENS.joinGame:
view = (<Chrome><div className='view-container'><JoinGame /></div></Chrome>);
break;
case SCREENS.play:
view = (<Board />);
break;
}
return (
<Fragment>
{view}
<div id={messagePanelId}><MessagePanel /></div>
</Fragment>
);
}
}
export default connect(
state => state.app,
null
)(App);

View File

@@ -0,0 +1,22 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
export const START = 'start';
export const PLAY = 'play';
export const SHOW_NEW_GAME = 'show-new-game';
export const SHOW_JOIN_GAME = 'show-join-game';

View File

@@ -0,0 +1,37 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import { START, PLAY, SHOW_NEW_GAME, SHOW_JOIN_GAME } from './actionTypes.js'
export { start, play, showNewGame, showJoinGame }
function start() {
return { type: START };
}
function play() {
return { type: PLAY };
}
function showNewGame() {
return { type: SHOW_NEW_GAME };
}
function showJoinGame() {
return { type: SHOW_JOIN_GAME };
}

View File

@@ -0,0 +1,40 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import { PLAY, SHOW_NEW_GAME, SHOW_JOIN_GAME, START } from './actionTypes.js'
import { SCREENS } from '../../constants.js'
const initialState = {
screen: SCREENS.intro
};
export default function(state = initialState, action) {
switch (action.type) {
case START:
return { ...state, screen: SCREENS.start };
case PLAY:
return { ...state, screen: SCREENS.play };
case SHOW_NEW_GAME:
return { ...state, screen: SCREENS.newGame };
case SHOW_JOIN_GAME:
return { ...state, screen: SCREENS.joinGame };
default:
return state;
}
}

View File

@@ -0,0 +1,45 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React, { Fragment } from 'react'
import { connect } from 'react-redux'
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
import { showNewGame, showJoinGame } from '../app/actions.js'
class CreateOrJoin extends React.Component {
render() {
return (
<Fragment>
<Button size='large' className='shadow' onClick={this.props.showNewGame}>
New Game
</Button>
<Button size='large' className='shadow' onClick={this.props.showJoinGame}>
Join Game
</Button>
</Fragment>
);
}
}
export default connect(
state => state,
{ showNewGame,
showJoinGame
}
)(CreateOrJoin)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React from 'react'
import { connect } from 'react-redux'
import SpaceNode from './SpaceNode.jsx'
import { setMessagePanelSpace, mpMouse } from './actions.js'
class MessagePanel extends React.Component {
render () {
if (this.props.space !== null) {
const panel = document.getElementById('message-panel'),
mpDims = this.props.mpDims;
panel.style.top =
(Math.min(Math.max(mpDims.mouseY, mpDims.minHeight + mpDims.padding),
mpDims.maxHeight)) + 'px';
panel.style.left =
(Math.min(Math.max(mpDims.mouseX, mpDims.minWidth + mpDims.padding),
mpDims.maxWidth)) + 'px';
return (
<SpaceNode space={this.props.space} height='210px'
showtitle={true} orientation={''} />
);
} else {
return null;
}
}
}
export default connect(
state => state.farm,
null
)(MessagePanel);

View File

@@ -0,0 +1,30 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React from 'react'
export default class PlayerIcon extends React.Component {
render() {
return (
<center>
{this.props.colors
.map(c => (<div key={c} className={'player player-' + c}></div>))}
</center>
);
}
}

View File

@@ -0,0 +1,69 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React from 'react'
import { connect } from 'react-redux'
import PlayerIcon from './PlayerIcon.jsx'
import { setMessagePanelSpace, mpMouse } from './actions.js'
class SpaceNode extends React.Component {
render() {
const space = this.props.space;
let title = '';
if (this.props.showtitle) {
switch (this.props.space.type) {
case 'hay': title = 'Hay Cutting'; break;
case 'cherry': title = 'Cherry Harvest'; break;
case 'wheat': title = 'Wheat Harvest'; break;
case 'cows': title = 'Livestock Sales'; break;
case 'apple': title = 'Apple Harvest'; break;
case 'corn': title = 'Corn Harvest'; break;
case 'buy': title = 'Purchasing'; break;
}
}
return (
<div className={'space space-type-' + this.props.space.type +
' space-orientation-' + this.props.orientation}
onMouseOver={evt => {
const clientRects = evt.target.getClientRects()[0];
this.props.setMessagePanelSpace(space);
this.props.mpMouse(clientRects.left, clientRects.top);
return false; } }>
<div style={this.props.height ? {height: this.props.height} : {}}>
<center>{this.props.space.month}</center>
{ this.props.showtitle ? (
<div className='space-title'>
{title}
</div>)
: (null)}
{ this.props.space.players.length ? <PlayerIcon colors={this.props.space.players} /> : ''}
<div className='space-description'>
{this.props.space.description}
</div>
</div>
</div>
);
}
}
export default connect(
null,
{ setMessagePanelSpace, mpMouse }
)(SpaceNode)

View File

@@ -0,0 +1,36 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
export const UPDATE_GAME = 'update-game';
export const UPDATE_PLAYER = 'update-player';
export const GAME_STATE = 'game-state';
export const SET_SELECTED_CARD = 'set-selected-card';
export const SET_CARDS = 'set-cards';
export const SPACE_PUSH_PLAYER = 'space-push-player';
export const SPACE_CLEAR_PLAYERS = 'space-clear-players';
export const SET_OLD_MESSAGES = 'set-old-messages';
export const MESSAGE_PANEL_SPACE = 'message-panel-space';
export const MP_MOUSE = 'mp-mouse';
export const SET_MP_DIMS = 'set-mp-dims';
export const MOVE_PLAYER = 'move-player'
export const SET_NEXT_ACTION = 'set-next-action'
export const NEXT_UI_ACTION = 'next-ui-action'
export const NEXT_UI_ACTION_SILENT = 'next-ui-action-silent'
export const MARK_ACTION_CHANGE_HANDLED = 'mark-action-change-handled'
export const ALERT = 'alert'
export const ALERT_HANDLED = 'alert-handled'

View File

@@ -0,0 +1,115 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
SPACE_PUSH_PLAYER, SPACE_CLEAR_PLAYERS, SET_OLD_MESSAGES, MESSAGE_PANEL_SPACE,
MP_MOUSE, SET_MP_DIMS, MARK_ACTION_CHANGE_HANDLED, SET_NEXT_ACTION,
MOVE_PLAYER, NEXT_UI_ACTION, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED
} from './actionTypes.js'
export { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
spacePushPlayer, spaceClearPlayers, setOldMessages, setMessagePanelSpace,
mpMouse, setMPDims, movePlayer, setNextAction, nextUIAction,
markActionChangeHandled, nextUIActionSilent, alert, alertHandled }
function updateGame(update) {
return { type: UPDATE_GAME,
update };
}
function updatePlayer(update) {
return { type: UPDATE_PLAYER,
update };
}
function gameState(state) {
return { type: GAME_STATE,
state };
}
function setSelectedCard(card) {
return { type: SET_SELECTED_CARD,
// TODO share with initialState ui.card
card: card ? card : { type: 'no-card', contents: '', total: 0 } }
}
function setCards(cards) {
return { type: SET_CARDS,
cards };
}
function spacePushPlayer(id, player) {
return { type: SPACE_PUSH_PLAYER,
id,
player };
}
function spaceClearPlayers(id) {
return { type: SPACE_CLEAR_PLAYERS,
id };
}
function setOldMessages(messages) {
return { type: SET_OLD_MESSAGES,
messages };
}
function setMessagePanelSpace(space) {
return { type: MESSAGE_PANEL_SPACE,
space };
}
function mpMouse(mouseX, mouseY) {
return { type: MP_MOUSE,
mouseX, mouseY };
}
function setMPDims(minWidth, minHeight, maxWidth, maxHeight) {
return { type: SET_MP_DIMS,
minWidth, minHeight, maxWidth, maxHeight };
}
function movePlayer(newSpace, oldSpace, player) {
return { type: MOVE_PLAYER,
newSpace, oldSpace, player };
}
function nextUIAction() {
return { type: NEXT_UI_ACTION };
}
function nextUIActionSilent() {
return { type: NEXT_UI_ACTION_SILENT };
}
function setNextAction(action, value) {
return { type: SET_NEXT_ACTION,
action, value };
}
function markActionChangeHandled() {
return { type: MARK_ACTION_CHANGE_HANDLED };
}
function alert(value) {
return { type: ALERT, value };
}
function alertHandled() {
return { type: ALERT_HANDLED };
}

View File

@@ -0,0 +1,177 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import { GAME_STATES, ALERTS } from '../../constants.js'
import { batch } from 'react-redux'
import * as websocket from '../../websocket.js'
import { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
movePlayer, setOldMessages, markActionChangeHandled,
mpMouse, rolled, setNextAction, nextUIAction, nextUIActionSilent, alert
} from './actions.js'
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
submitTradeDeny, submitTradeCancel, audit, handleMessage,
nextAction, buyUncleBert, actionsFinished }
let store;
let spacesWithPlayers = [];
let loop = 0;
function handleMessage(evt) {
const data = JSON.parse(evt.data),
type = data.event;
if (data.event === 'error') {
console.log('error:' + data.exn);
return;
}
batch(() => {
if (data.player.state === GAME_STATES.preTurn &&
data.game.otherPlayers.length > 0 &&
store.getState().farm.player.state !== GAME_STATES.preTurn) {
store.dispatch(alert(ALERTS.beginTurn));
} else if (data.game.otherPlayers.length > 0 &&
data.game.currentPlayer !== store.getState().farm.game.currentPlayer) {
store.dispatch(alert(ALERTS.otherPlayersTurn));
}
store.dispatch(updatePlayer(data.player));
if (data.event === 'init') {
store.dispatch(movePlayer(data.player.space, 0, data.player.color));
}
// new player(s) added to game, put them on the board
if (data.game.otherPlayers.length !== store.getState().farm.game.otherPlayers.length) {
const otherPlayers = store.getState().farm.game.otherPlayers;
const newPlayers = data.game.otherPlayers.filter(
x => !otherPlayers.find(y => y.player.name === x.player.name));
for (const p of newPlayers) {
store.dispatch(movePlayer(p.player.space, 0, p.player.color));
}
}
const oldMessages = store.getState().farm.game.messages.slice(0, 20);
store.dispatch(updateGame(data.game));
store.dispatch(setOldMessages(oldMessages));
if (data.player.cards.length > 0) {
store.dispatch(setSelectedCard(data.player.cards[0]));
} else {
store.dispatch(setSelectedCard());
}
store.dispatch(setCards(data.player.cards));
if (data.event === 'action') {
if (data.player.name !== data.game.currentPlayer &&
data.action !== 'roll') {
store.dispatch(nextUIAction());
}
store.dispatch(setNextAction(data.action, data.value));
if (data.action === 'roll') {
store.dispatch(nextUIAction());
}
}
if (data.player.state === GAME_STATES.midTurn &&
data.player.cash < 0 &&
!store.getState().farm.ui.nextAction) {
store.dispatch(alert(ALERTS.raiseMoney));
}
});
};
let sendCommand;
function buy(id, cash) {
sendCommand({ type: 'buy', id: id, cash: cash });
}
function roll() {
store.dispatch(setNextAction('pre-rolling', false));
store.dispatch(nextUIActionSilent());
sendCommand({ type: 'roll' });
}
function endTurn() {
store.dispatch(gameState(GAME_STATES.turnEnded));
sendCommand({ type: 'turn-ended' });
}
function loan(amount) {
sendCommand({ type: 'loan', amount: amount });
}
function trade(parameters) {
sendCommand({ type: 'trade',
parameters: parameters });
}
function submitTradeAccept() {
sendCommand({ type: 'trade-accept' });
}
function submitTradeDeny() {
sendCommand({ type: 'trade-deny' });
}
function submitTradeCancel() {
sendCommand({ type: 'trade-cancel' });
}
function audit() {
sendCommand({ type: 'audit' });
}
function nextAction() {
sendCommand({ type: 'next-action' });
}
function buyUncleBert() {
sendCommand({ type: 'buy-uncle-bert' });
}
function actionsFinished() {
sendCommand({ type: 'actions-finished' });
}
function initialize(st, sc) {
store = st;
sendCommand = sc;
const unsubscribe = store.subscribe(
() => {
const state = store.getState();
if (state.farm.player.name === state.farm.game.currentPlayer
&& !state.farm.ui.actionChangeHandled) {
store.dispatch(markActionChangeHandled());
nextAction();
}
});
// mpDims.mouseX = e.clientX
// window.onmousemove = e => store.
// dispatch(mpMouse(e.clientX, store.getState().farm.mpDims.mouseY));
// document.addEventListener('keydown', keydown);
}
function keydown(e) {
switch (e.key) {
case 'r':
roll();
break;
case 'e':
endTurn();
break;
}
}

View File

@@ -0,0 +1,182 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
SPACE_PUSH_PLAYER, SPACE_CLEAR_PLAYERS,
SET_OLD_MESSAGES, MESSAGE_PANEL_SPACE, MP_MOUSE,
SET_MP_DIMS, MOVE_PLAYER, SET_NEXT_ACTION, NEXT_UI_ACTION,
MARK_ACTION_CHANGE_HANDLED, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED
} from './actionTypes.js'
import { GAME_STATES } from '../../constants.js'
import { spaceContent, corners } from 'game.js'
const spaces =
[[corners[0], 'buy'],
['January', 'buy'],
['January', 'buy'],
['January', 'buy'],
['January', 'buy'],
['February','buy'],
['February', 'buy'],
['February', 'buy'],
['February', 'buy'],
['March', 'buy'],
['March', 'buy'],
['March', 'buy'],
['March', 'buy'],
['April', 'buy'],
[corners[1], 'buy'],
['April', 'none'],
['April', 'none'],
['May', 'none'],
['May', 'none'],
['May', 'hay'],
['May', 'hay'],
['June', 'hay'],
['June', 'hay'],
['June', 'cherry'],
['June', 'cherry'],
[corners[2], 'cherry'],
['July', 'hay'],
['July', 'hay'],
['July', 'hay'],
['July', 'wheat'],
['August', 'wheat'],
['August', 'wheat'],
['August', 'wheat'],
['August', 'wheat'],
['September', 'hay'],
['September', 'hay'],
['September', 'cows'],
[corners[3], 'cows'],
['September', 'cows'],
['October', 'cows'],
['October', 'hay'],
['October', 'hay'],
['October', 'apple'],
['November', 'apple'],
['November', 'apple'],
['November', 'apple'],
['November', 'corn'],
['December', 'corn'],
['December', 'corn']]
.map((s, i) => {
return { month: s[0], description: spaceContent[i],
type: s[1], key: i, players: [] }});
const initialState = {
player: { cash: 5000,
lastCash: 5000,
debt: 5000,
spaces,
state: GAME_STATES.turnEnded,
assets: { hay: 10, grain: 10, fruit: 0, cows: 0, harvester: 0, tractor: 0 },
color: '',
name: '',
ridges: { ridge1: 0, ridge2: 0, ridge3: 0, ridge4: 0 },
space: 0,
trade: {}
},
game: { auditThreshold: 250000,
calledAudit: false,
currentPlayer: '',
messages: [],
otherPlayers: [],
state: GAME_STATES.preTurn,
turn: 0,
oldMessages: [] },
ui: { card: { type: 'no-card', contents: '', total: 0 },
cards: [],
action: false,
actionValue: null,
nextAction: false,
nextActionValue: null,
actionChangeHandled: true,
alert: false,
alertHandled: false },
spaces: spaces,
space: null,
// message panel dimenions
mpDims: { mouseX: 0, mouseY: 0,
minWidth: 0, minHeight: 0, maxWidth: 0, maxHeight: 0,
padding: 8 },
profile: false,
profileTurns: 500
}
export default function(state = initialState, action) {
switch (action.type) {
case UPDATE_GAME:
return { ...state, game: { ...state.game, ...action.update }};
case UPDATE_PLAYER:
return { ...state, player: action.update };
case GAME_STATE:
return { ...state, game: { ...state.game, state: action.state } };
case SET_SELECTED_CARD:
return { ...state, ui: { ...state.ui, card: action.card }};
case SET_CARDS:
return { ...state, ui: { ...state.ui, cards: action.cards }};
case MOVE_PLAYER:
return { ...state, spaces: state.spaces
.map((item, index) => {
if (index === action.newSpace &&
item.players.indexOf(action.player) === -1) {
return { ...item, players: [...item.players, action.player]};
} else if (index === action.oldSpace) {
return { ...item,
players: item.players
.filter(x => x !== action.player) };
}
return item;
})
};
case SET_OLD_MESSAGES:
return { ...state, oldMessages: action.messages };
case MESSAGE_PANEL_SPACE:
return { ...state, space: action.space };
case MP_MOUSE:
return { ...state, mpDims: { ...state.mpDims,
mouseX: action.mouseX, mouseY: action.mouseY }};
case SET_MP_DIMS:
return { ...state, mpDims: { ...state.mpDims,
minWidth: action.minWidth,
minHeight: action.minHeight,
maxWidth: action.maxWidth,
maxHeight: action.maxHeight }};
case SET_NEXT_ACTION:
return { ...state, ui: { ...state.ui, nextAction: action.action,
nextActionValue: action.value }};
case NEXT_UI_ACTION:
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
actionValue: state.ui.nextActionValue,
actionChangeHandled: !state.ui.nextAction }};
case NEXT_UI_ACTION_SILENT: // don't set actionChangeHandled
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
actionValue: state.ui.nextActionValue }};
case MARK_ACTION_CHANGE_HANDLED:
return { ...state, ui: { ...state.ui, actionChangeHandled: true }};
case ALERT:
return { ...state, ui: { ...state.ui,
alert: action.value,
alertHandled: action.value === false ? true : false }};
case ALERT_HANDLED:
return { ...state, ui: { ...state.ui, alertHandled: true }};
default:
return state;
}
}

View File

@@ -0,0 +1,97 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React, { Fragment } from 'react'
import { connect } from 'react-redux'
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
import { startOrJoinGame } from '../start/actions.js'
import NewGame from '../new-game/NewGame.jsx'
const JoinGameScreens = { list: 'list', details: 'details' };
class JoinGame extends React.Component {
constructor(props) {
super(props);
this.state = {
screen: JoinGameScreens.list,
game: null
};
}
handleClickGame = game => {
this.setState({ screen: JoinGameScreens.details,
game: game
});
}
handleBack = e => {
this.setState({ screen: JoinGameScreens.list });
}
handleJoinAsExisting = e => {
this.props.startOrJoinGame({ type: 'join-as-existing',
playerName: e.target.text,
gameName: this.state.game.name });
}
render() {
return (
<GroupBox title='Join Game'>
<Row>
<Col width='12'>
{this.state.screen === JoinGameScreens.list ?
(<ul>
{this.props.games
.map((g, i) =>
(<li key={i}>
<a href='#' onClick={() => this.handleClickGame(g)}>{g.name}</a>
</li>))}
</ul>)
: (<Fragment>
<p><a href="#" onClick={this.handleBack}>back to games</a></p>
<h3><b>Game:</b> {this.state.game.name}</h3>
<h4>Join as existing player:</h4>
<ul>
{this.state.game.players.map((p, i) =>
(<li key={i}>
<a href='#' onClick={this.handleJoinAsExisting}>
{p}
</a>
</li>))}
</ul>
<NewGame colors={this.state.game.colors}
button={'Join'}
showGameName={false}
gameName={this.state.game.name}
type={'join-game'}
title={'Join as New Player'} />
</Fragment>)}
</Col>
</Row>
</GroupBox>
);
}
}
export default connect(
state => state.start.start,
{ startOrJoinGame }
)(JoinGame)

View File

@@ -0,0 +1,104 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React, { Fragment } from 'react'
import { connect } from 'react-redux'
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
import { startOrJoinGame } from '../start/actions.js'
class NewGame extends React.Component {
constructor(props) {
super(props);
this.state = {
playerName: '',
checkedColor: props.colors[0],
gameName: props.gameName || ''
};
}
handleInputChange = e => {
const target = e.target,
value = target.type === 'checkbox' ? target.name : target.value,
name = target.type === 'checkbox' ? 'checkedColor' : target.name;
this.setState({
[name]: value
});
}
handleSubmit = e => {
e.preventDefault();
this.props.startOrJoinGame(Object.assign({ type: this.props.type }, this.state));
}
render() {
let playerNameInput;
return (
<GroupBox title={this.props.title}>
<form onSubmit={this.handleSubmit}>
<Row>
<Col width='12'>
<label>Your Name
<input type='text' name='playerName'
value={this.state.playerName}
onChange={this.handleInputChange} />
</label>
</Col>
</Row>
<Row>
<Col width='12'>
<label>Your Color</label>
{this.props.colors
.map(c =>
(<label key={c} className={'player player-selectable player-' + c + (this.state.checkedColor === c ? ' player-selected' : '')}>
<input type='checkbox'
checked={this.state.checkedColor === c}
onChange={this.handleInputChange}
name={c} />
</label>))
}
<br /><br />
</Col>
</Row>
{this.props.showGameName && (
<Row>
<Col width='12'>
<label>Game Name
<input type='text' name='gameName' value={this.state.gameName}
onChange={this.handleInputChange} />
</label>
</Col>
</Row>
)}
<Row>
<Col width='12'>
<Button type='submit'>{this.props.button} Game</Button>
</Col>
</Row>
</form>
</GroupBox>
);
}
}
export default connect(
null,
{ startOrJoinGame }
)(NewGame)

View File

@@ -0,0 +1,94 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React, { Fragment } from 'react'
import { connect } from 'react-redux'
import { GroupBox, Row, Col } from '../widgets.jsx'
import { startOrJoinGame } from './actions.js'
const JoinGameScreens = { list: 'list', details: 'details' };
class JoinGameComp extends React.Component {
constructor(props) {
super(props);
this.state = {
screen: JoinGameScreens.list,
game: null
};
}
handleClickGame = game => {
this.setState({ screen: JoinGameScreens.details,
game: game
});
}
handleBack = e => {
this.setState({ screen: JoinGameScreens.list });
}
handleJoinAsExisting = e => {
this.props.startOrJoinGame({ type: 'join-as-existing',
playerName: e.target.text,
gameName: this.state.game.name });
}
render() {
return (
<GroupBox title='Join Game'>
<Row>
<Col width='12'>
{this.state.screen === JoinGameScreens.list ?
(<ul>
{this.props.games
.map((g, i) =>
(<li key={i}>
<a href='#' onClick={() => this.handleClickGame(g)}>{g.name}</a>
</li>))}
</ul>)
: (<Fragment>
<p><a href="#" onClick={this.handleBack}>back to games</a></p>
<h3><b>Game:</b> {this.state.game.name}</h3>
<h4>Join as existing player:</h4>
<ul>
{this.state.game.players.map((p, i) =>
(<li key={i}>
<a href='#' onClick={this.handleJoinAsExisting}>
{p}
</a>
</li>))}
</ul>
<NewGame colors={this.state.game.colors}
button={'Join'}
showGameName={false}
gameName={this.state.game.name}
type={'join-game'}
title={'Join as New Player'} />
</Fragment>)}
</Col>
</Row>
</GroupBox>
);
}
}
const JoinGame = connect(
null,
{ startOrJoinGame }
)(JoinGameComp)

View File

@@ -0,0 +1,20 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
export const SET_START_GAMES = 'set-start-games';
export const START_OR_JOIN_GAME = 'start-or-join-game';

View File

@@ -0,0 +1,31 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import { SET_START_GAMES, START_OR_JOIN_GAME } from './actionTypes.js'
export { setStartGames, startOrJoinGame }
function setStartGames(games) {
return { type: SET_START_GAMES,
games };
}
function startOrJoinGame(msg) {
return { type: START_OR_JOIN_GAME,
msg };
}

View File

@@ -0,0 +1,37 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import { SET_START_GAMES, START_OR_JOIN_GAME } from './actionTypes.js'
import { SCREENS } from '../../constants.js'
const initialState = {
start: { games: [] },
msg: null
};
export default function(state = initialState, action) {
switch (action.type) {
case SET_START_GAMES:
return { ...state, start: { ...state.start, games: action.games }};
case START_OR_JOIN_GAME:
return { ...state, msg: action.msg };
default:
return state;
}
}

View File

@@ -0,0 +1,40 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import TractorImg from './../../../assets/img/tractor-offset.svg'
import TractorAndSpikesImg from './../../../assets/img/tractor-offset-and-spikes.svg'
import TractorSpikesImg from './../../../assets/img/tractor-spikes-offset.svg'
import React, { Fragment } from 'react'
export default class Tractor extends React.Component {
render() {
return (
<Fragment>
<div className={'tractor ' + (this.props.className ? this.props.className : '')}>
<img src={this.props.spikes ? TractorImg : TractorAndSpikesImg} />
</div>
{this.props.spikes ? (
<div className='tractor spikes'>
<img src={TractorSpikesImg} />
</div>
) : (<Fragment />)}
</Fragment>
);
}
}

View File

@@ -0,0 +1,46 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React, { Fragment } from 'react'
import { connect } from 'react-redux'
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
import { start } from '../app/actions.js'
class Welcome extends React.Component {
render() {
return (
<Fragment>
<div className='intro-text'>
<div className='game-card'>
Your ancestors were farmers on one of the first transports to Alpha Centuari{`'`}s Proxima b. The growing season is short and harsh but the colonists depend on you for their food. Are you up to the challenge?
</div>
</div>
<Button size='large' className='shadow intro' onClick={this.props.start}>
Begin
</Button>
</Fragment>
);
}
}
export default connect(
state => state,
{ start }
)(Welcome)

View File

@@ -0,0 +1,69 @@
// Copyright 2020 Thomas Hintz
//
// This file is part of the Alpha Centauri Farming project.
//
// The Alpha Centauri Farming project is free software: you can
// redistribute it and/or modify it under the terms of the GNU General
// Public License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// The Alpha Centauri Farming project is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Alpha Centauri Farming project. If not, see
// <https://www.gnu.org/licenses/>.
import React, { Fragment } from 'react'
export { GroupBox, Row, Col, Button }
class GroupBox extends React.Component {
render() {
return (
<div className='panel card'>
{this.props.title ?
(<div className='card-divider'>
{this.props.title}
</div>) : (<Fragment />)}
<div className={'card-section ' + this.props.className ? this.props.className : ''}>
{this.props.children}
</div>
</div>
);
}
}
class Row extends React.Component {
render() {
return (<div className={'grid-x full-width ' +
(this.props.collapse ? 'collapse' : '') + ' ' +
(this.props.className ? this.props.className : '')} >
{this.props.children}</div>);
}
}
class Col extends React.Component {
render() {
return (
<div className={'cell small-' + this.props.width}>
{this.props.children}
</div>
);
}
}
class Button extends React.Component {
render() {
return (
<button className={'button ' + (this.props.size ? this.props.size : '') +
' ' + (this.props.className ? this.props.className : '')}
type={this.props.type || 'button'}
onClick={this.props.onClick} >
{this.props.children}
</button>
);
}
}