Merge branch 'cypress' into master
This commit is contained in:
11
Makefile
11
Makefile
@@ -17,7 +17,7 @@
|
|||||||
# along with the Alpha Centauri Farming project. If not, see
|
# along with the Alpha Centauri Farming project. If not, see
|
||||||
# <https://www.gnu.org/licenses/>.
|
# <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
.PHONY: clean install interactive
|
.PHONY: clean install interactive cypress
|
||||||
|
|
||||||
assets := assets/game/acf/
|
assets := assets/game/acf/
|
||||||
|
|
||||||
@@ -25,6 +25,10 @@ dev:
|
|||||||
npx webpack --config webpack.dev.js --env.assets ./$(assets)
|
npx webpack --config webpack.dev.js --env.assets ./$(assets)
|
||||||
|
|
||||||
rundev:
|
rundev:
|
||||||
|
webpack-dev-server --open --config webpack.dev.js --env.assets ./$(assets)
|
||||||
|
# make interactive
|
||||||
|
|
||||||
|
rundevserver:
|
||||||
make interactive
|
make interactive
|
||||||
|
|
||||||
prod: src/server/farm
|
prod: src/server/farm
|
||||||
@@ -35,7 +39,7 @@ install:
|
|||||||
npm install
|
npm install
|
||||||
|
|
||||||
interactive:
|
interactive:
|
||||||
cd dist/ && csi -include-path $(assets) -include-path ../src/server -s farm.scm
|
csi -include-path $(assets) -include-path src/server -s src/server/farm.scm
|
||||||
|
|
||||||
src/server/farm: src/server/farm.scm src/server/db.scm
|
src/server/farm: src/server/farm.scm src/server/db.scm
|
||||||
cd src/server/ && csc -include-path ../../$(assets) -O3 farm.scm
|
cd src/server/ && csc -include-path ../../$(assets) -O3 farm.scm
|
||||||
@@ -49,6 +53,9 @@ runprod:
|
|||||||
upload:
|
upload:
|
||||||
rsync -rtvz dist/ $(SERVER):~/farm
|
rsync -rtvz dist/ $(SERVER):~/farm
|
||||||
|
|
||||||
|
cypress:
|
||||||
|
npm run cypress:open
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *~ res/js/app.js
|
rm -f *~ res/js/app.js
|
||||||
|
|
||||||
|
|||||||
3
cypress.json
Normal file
3
cypress.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"baseUrl": "http://localhost:8080"
|
||||||
|
}
|
||||||
5
cypress/fixtures/example.json
Normal file
5
cypress/fixtures/example.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Using fixtures to represent data",
|
||||||
|
"email": "hello@cypress.io",
|
||||||
|
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||||
|
}
|
||||||
25
cypress/integration/sample_spec.js
Normal file
25
cypress/integration/sample_spec.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
describe('My First Test', () => {
|
||||||
|
it('Visits the Kitchen Sink', () => {
|
||||||
|
cy.visit('/')
|
||||||
|
|
||||||
|
cy.contains('Begin').click()
|
||||||
|
|
||||||
|
cy.contains('New Game').click()
|
||||||
|
|
||||||
|
cy.contains('Login').click()
|
||||||
|
|
||||||
|
cy.get('form [name="username"]').type('test')
|
||||||
|
cy.get('form [name="password"]').type('food')
|
||||||
|
cy.get('button[type="submit"]').click()
|
||||||
|
|
||||||
|
cy.get('form [name="gameName"]').type('test')
|
||||||
|
cy.get('button[type="submit"]').click()
|
||||||
|
|
||||||
|
cy.get('span[class="add-ai"]').click()
|
||||||
|
|
||||||
|
cy.contains('Ready to start').click()
|
||||||
|
cy.contains('Start Game').click()
|
||||||
|
|
||||||
|
cy.get('.show .action-item').first().click()
|
||||||
|
})
|
||||||
|
})
|
||||||
21
cypress/plugins/index.js
Normal file
21
cypress/plugins/index.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
// ***********************************************************
|
||||||
|
// This example plugins/index.js can be used to load plugins
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off loading
|
||||||
|
// the plugins file with the 'pluginsFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/plugins-guide
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// This function is called when a project is opened or re-opened (e.g. due to
|
||||||
|
// the project's config changing)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Cypress.PluginConfig}
|
||||||
|
*/
|
||||||
|
module.exports = (on, config) => {
|
||||||
|
// `on` is used to hook into various events Cypress emits
|
||||||
|
// `config` is the resolved Cypress config
|
||||||
|
}
|
||||||
25
cypress/support/commands.js
Normal file
25
cypress/support/commands.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// ***********************************************
|
||||||
|
// This example commands.js shows you how to
|
||||||
|
// create various custom commands and overwrite
|
||||||
|
// existing commands.
|
||||||
|
//
|
||||||
|
// For more comprehensive examples of custom
|
||||||
|
// commands please read more here:
|
||||||
|
// https://on.cypress.io/custom-commands
|
||||||
|
// ***********************************************
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a parent command --
|
||||||
|
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a child command --
|
||||||
|
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a dual command --
|
||||||
|
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This will overwrite an existing command --
|
||||||
|
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||||
20
cypress/support/index.js
Normal file
20
cypress/support/index.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// ***********************************************************
|
||||||
|
// This example support/index.js is processed and
|
||||||
|
// loaded automatically before your test files.
|
||||||
|
//
|
||||||
|
// This is a great place to put global configuration and
|
||||||
|
// behavior that modifies Cypress.
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off
|
||||||
|
// automatically serving support files with the
|
||||||
|
// 'supportFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/configuration
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// Import commands.js using ES2015 syntax:
|
||||||
|
import './commands'
|
||||||
|
|
||||||
|
// Alternatively you can use CommonJS syntax:
|
||||||
|
// require('./commands')
|
||||||
2273
package-lock.json
generated
2273
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build": "webpack --config webpack.dev.js",
|
"build": "webpack --config webpack.dev.js",
|
||||||
"prod": "webpack --config webpack.prod.js"
|
"prod": "webpack --config webpack.prod.js",
|
||||||
|
"cypress:open": "cypress open"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
"@babel/plugin-proposal-decorators": "^7.8.3",
|
"@babel/plugin-proposal-decorators": "^7.8.3",
|
||||||
"@babel/preset-env": "^7.8.3",
|
"@babel/preset-env": "^7.8.3",
|
||||||
"@babel/preset-react": "^7.8.3",
|
"@babel/preset-react": "^7.8.3",
|
||||||
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.1",
|
||||||
"autoprefixer": "^9.7.4",
|
"autoprefixer": "^9.7.4",
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-plugin-transform-decorators-legacy": "^1.3.5",
|
"babel-plugin-transform-decorators-legacy": "^1.3.5",
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
"copy-webpack-plugin": "^5.1.1",
|
"copy-webpack-plugin": "^5.1.1",
|
||||||
"css-loader": "^3.4.2",
|
"css-loader": "^3.4.2",
|
||||||
"css-url-relative-plugin": "^1.0.0",
|
"css-url-relative-plugin": "^1.0.0",
|
||||||
|
"cypress": "^4.4.1",
|
||||||
"favicons-webpack-plugin": "^2.1.0",
|
"favicons-webpack-plugin": "^2.1.0",
|
||||||
"file-loader": "^4.3.0",
|
"file-loader": "^4.3.0",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
@@ -38,11 +41,13 @@
|
|||||||
"node-sass": "^4.13.1",
|
"node-sass": "^4.13.1",
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
|
"react-refresh": "^0.8.3",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
"style-loader": "^1.1.3",
|
"style-loader": "^1.1.3",
|
||||||
"terser-webpack-plugin": "^2.3.5",
|
"terser-webpack-plugin": "^2.3.5",
|
||||||
"webpack": "^4.41.5",
|
"webpack": "^4.41.5",
|
||||||
"webpack-cli": "^3.3.10",
|
"webpack-cli": "^3.3.10",
|
||||||
|
"webpack-dev-server": "^3.11.0",
|
||||||
"webpack-merge": "^4.2.2"
|
"webpack-merge": "^4.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|||||||
import { faUser, faUsers, faTractor, faWindowRestore,
|
import { faUser, faUsers, faTractor, faWindowRestore,
|
||||||
faDollarSign, faTimes, faExchangeAlt,
|
faDollarSign, faTimes, faExchangeAlt,
|
||||||
faInfoCircle, faArrowUp, faArrowDown, faAward,
|
faInfoCircle, faArrowUp, faArrowDown, faAward,
|
||||||
faBan, faArrowCircleLeft, faPlusCircle } from '@fortawesome/free-solid-svg-icons'
|
faBan, faArrowCircleLeft, faPlusCircle, faBirthdayCake } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||||
import SpaceNode from './SpaceNode.jsx'
|
import SpaceNode from './SpaceNode.jsx'
|
||||||
@@ -49,7 +49,7 @@ import { buy, roll, endTurn, loan, trade, submitTradeAccept,
|
|||||||
submitTradeDeny, submitTradeCancel, audit,
|
submitTradeDeny, submitTradeCancel, audit,
|
||||||
buyUncleBert, skip, endAiTurn, startGame, readyToStart,
|
buyUncleBert, skip, endAiTurn, startGame, readyToStart,
|
||||||
leaveGame, kickPlayer, toggleRevealForTrade,
|
leaveGame, kickPlayer, toggleRevealForTrade,
|
||||||
addAIPlayer } from './interface.js'
|
addAIPlayer, birthdayBonusPlayer } from './interface.js'
|
||||||
|
|
||||||
let showScreenDelay = 2000;
|
let showScreenDelay = 2000;
|
||||||
|
|
||||||
@@ -177,18 +177,18 @@ class PlayerResources extends React.Component {
|
|||||||
<ResourceUnit img={TractorImg} h='240' s='100' label='Tractors'
|
<ResourceUnit img={TractorImg} h='240' s='100' label='Tractors'
|
||||||
amount={player.assets.tractor}>
|
amount={player.assets.tractor}>
|
||||||
{player.assets.tractor}
|
{player.assets.tractor}
|
||||||
|
</ResourceUnit>{' '}
|
||||||
|
{player.assets.birthday ? (
|
||||||
|
<ResourceUnit img={CakeImg} h='240' s='100' label='Birthday'
|
||||||
|
amount={player.assets.birthday ? player.assets.birthday : 0}>
|
||||||
|
{player.assets.birthday ? player.assets.birthday : 0}
|
||||||
</ResourceUnit>
|
</ResourceUnit>
|
||||||
|
) : (<></>)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* {' '}
|
|
||||||
* <ResourceUnit img={CakeImg} h='240' s='100' label='Birthday'
|
|
||||||
* amount={player.assets.birthday ? player.assets.birthday : 0}>
|
|
||||||
* {player.assets.birthday ? player.assets.birthday : 0}
|
|
||||||
* </ResourceUnit> */
|
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/149055
|
// http://stackoverflow.com/questions/149055
|
||||||
function formatMoney(n) {
|
function formatMoney(n) {
|
||||||
return n.toFixed(1).replace(/(\d)(?=(\d{3})+\.)/g, '$1,').slice(0, -2); }
|
return n.toFixed(1).replace(/(\d)(?=(\d{3})+\.)/g, '$1,').slice(0, -2); }
|
||||||
@@ -1949,6 +1949,7 @@ class AlertOverlay extends React.Component {
|
|||||||
<FontAwesomeIcon icon={faTimes} />
|
<FontAwesomeIcon icon={faTimes} />
|
||||||
</div>
|
</div>
|
||||||
) : (<></>)}
|
) : (<></>)}
|
||||||
|
<div className='alert-container'>
|
||||||
<div className='alert-overlay-contents'>
|
<div className='alert-overlay-contents'>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
<br />
|
<br />
|
||||||
@@ -1966,6 +1967,7 @@ class AlertOverlay extends React.Component {
|
|||||||
{!this.props.preventHiding ? (<a onClick={this.hide}>close</a>) : (<></>)}
|
{!this.props.preventHiding ? (<a onClick={this.hide}>close</a>) : (<></>)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2055,12 +2057,15 @@ class Info extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StartGame extends React.Component {
|
const StartGame = ({ game, player, toggleReady }) => {
|
||||||
render() {
|
const { auditThreshold, downPayment, loanInterest, maxDebt, startingOtbs, startingCash, startingDebt } = game.settings;
|
||||||
const { auditThreshold, downPayment, loanInterest, maxDebt, startingOtbs, startingCash, startingDebt } = this.props.game.settings;
|
const playerName = player.name;
|
||||||
const playerName = this.props.player.name;
|
const { color } = player;
|
||||||
const { color } = this.props.player;
|
const { name, host } = game;
|
||||||
const { name, host } = this.props.game;
|
|
||||||
|
const birthdayClass = (player) =>
|
||||||
|
player.assets.birthday ? 'birthday-selected' : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>Lobby</h1>
|
<h1>Lobby</h1>
|
||||||
@@ -2069,14 +2074,26 @@ class StartGame extends React.Component {
|
|||||||
</p>
|
</p>
|
||||||
<h3>Players</h3>
|
<h3>Players</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><PlayerColorIcon color={color} /> {playerName}</li>
|
<li>
|
||||||
{this.props.game.otherPlayers.map((p, i) => (
|
<PlayerColorIcon color={color} /> {playerName}
|
||||||
|
{playerName === host ? (
|
||||||
|
<span title="Birthday Bonus" className={'lobby-icon ' + birthdayClass(player)} onClick={() => birthdayBonusPlayer(playerName)}>
|
||||||
|
<FontAwesomeIcon icon={faBirthdayCake} />
|
||||||
|
</span>
|
||||||
|
) : (<></>)}
|
||||||
|
</li>
|
||||||
|
{game.otherPlayers.map((p, i) => (
|
||||||
<li key={i}>
|
<li key={i}>
|
||||||
<PlayerColorIcon color={p.player.color} /> {p.player.name}
|
<PlayerColorIcon color={p.player.color} /> {p.player.name}
|
||||||
{playerName === host ? (
|
{playerName === host ? (
|
||||||
<span title="Kick Player" className="kick-player" onClick={() => kickPlayer(p.player.name)}>
|
<>
|
||||||
|
<span title="Kick Player" className="lobby-icon kick-player" onClick={() => kickPlayer(p.player.name)}>
|
||||||
<FontAwesomeIcon icon={faBan} />
|
<FontAwesomeIcon icon={faBan} />
|
||||||
</span>
|
</span>
|
||||||
|
<span title="Birthday Bonus" className={"lobby-icon " + birthdayClass(p.player)} onClick={() => birthdayBonusPlayer(p.player.name)}>
|
||||||
|
<FontAwesomeIcon icon={faBirthdayCake} />
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
): (<></>)}
|
): (<></>)}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
@@ -2097,12 +2114,11 @@ class StartGame extends React.Component {
|
|||||||
<li><b>Starting Debt</b>: ${formatMoney(startingDebt)}</li>
|
<li><b>Starting Debt</b>: ${formatMoney(startingDebt)}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" onChange={this.props.toggleReady} />
|
<input type="checkbox" onChange={toggleReady} />
|
||||||
Ready to start
|
Ready to start
|
||||||
</label>
|
</label>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SCREENS = { summary: 'summary', misc: 'misc', farms: 'farms',
|
const SCREENS = { summary: 'summary', misc: 'misc', farms: 'farms',
|
||||||
@@ -2246,7 +2262,7 @@ class BoardApp extends React.Component {
|
|||||||
buttonText='Close'
|
buttonText='Close'
|
||||||
hideHandler={() => 'nothing'}
|
hideHandler={() => 'nothing'}
|
||||||
handler={() => { return false; }}>
|
handler={() => { return false; }}>
|
||||||
<Fragment>
|
<div className="game-over">
|
||||||
<h1>Game Over!</h1>
|
<h1>Game Over!</h1>
|
||||||
{alert.contents.results.map((e, i) => (
|
{alert.contents.results.map((e, i) => (
|
||||||
<p key={i}>{e}</p>
|
<p key={i}>{e}</p>
|
||||||
@@ -2257,7 +2273,14 @@ class BoardApp extends React.Component {
|
|||||||
<p>{alert.contents.stats.emergency}</p>
|
<p>{alert.contents.stats.emergency}</p>
|
||||||
<p>{alert.contents.stats.highRoller}</p>
|
<p>{alert.contents.stats.highRoller}</p>
|
||||||
<p>{alert.contents.stats.lowRoller}</p>
|
<p>{alert.contents.stats.lowRoller}</p>
|
||||||
</Fragment>
|
{alert.contents.stats.players.map(p => (
|
||||||
|
<div key={p.name}>
|
||||||
|
<p><b>{p.name} Harvests:</b></p>
|
||||||
|
<p>Total: ${formatMoney(p.harvestTotal)} Expenses: ${formatMoney(Math.abs(p.operatingExpenses))}</p>
|
||||||
|
<p>Avg ${formatMoney(p.harvestAverage)} rolling {p.harvestRoll} for {p.numHarvests} harvests</p>
|
||||||
|
<p>Hay: ${formatMoney(p.hay)} Grain: ${formatMoney(p.grain)} Fruit: ${formatMoney(p.fruit)} Cows: ${formatMoney(p.cows)}</p>
|
||||||
|
</div>))}
|
||||||
|
</div>
|
||||||
</AlertOverlay>
|
</AlertOverlay>
|
||||||
);
|
);
|
||||||
} else if (alert && alert.type === ALERTS.auditCalled) {
|
} else if (alert && alert.type === ALERTS.auditCalled) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
|
|||||||
submitTradeDeny, submitTradeCancel, audit, handleMessage,
|
submitTradeDeny, submitTradeCancel, audit, handleMessage,
|
||||||
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
|
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
|
||||||
startGame, readyToStart, leaveGame, kickPlayer, toggleRevealForTrade,
|
startGame, readyToStart, leaveGame, kickPlayer, toggleRevealForTrade,
|
||||||
addAIPlayer }
|
addAIPlayer, birthdayBonusPlayer }
|
||||||
|
|
||||||
let store;
|
let store;
|
||||||
let movingTimer = 0;
|
let movingTimer = 0;
|
||||||
@@ -218,6 +218,10 @@ function kickPlayer(name) {
|
|||||||
sendCommand({ type: 'kick-player', name });
|
sendCommand({ type: 'kick-player', name });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function birthdayBonusPlayer(name) {
|
||||||
|
sendCommand({ type: 'birthday-bonus-player', name });
|
||||||
|
}
|
||||||
|
|
||||||
function addAIPlayer() {
|
function addAIPlayer() {
|
||||||
sendCommand({ type: 'add-ai-player' });
|
sendCommand({ type: 'add-ai-player' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,12 @@
|
|||||||
(tax-person . 0)
|
(tax-person . 0)
|
||||||
(emergency . 0)
|
(emergency . 0)
|
||||||
(num-harvests . 0)
|
(num-harvests . 0)
|
||||||
(harvest-rolls . 0)))
|
(harvest-rolls . 0)
|
||||||
|
(operating-expenses . 0)
|
||||||
|
(hay . 0)
|
||||||
|
(grain . 0)
|
||||||
|
(fruit . 0)
|
||||||
|
(cows . 0)))
|
||||||
(alist-ref 'ai? args eqv? #f)
|
(alist-ref 'ai? args eqv? #f)
|
||||||
(alist-ref 'processing-turn args eqv? #f))))
|
(alist-ref 'processing-turn args eqv? #f))))
|
||||||
|
|
||||||
@@ -563,7 +568,7 @@
|
|||||||
;; (session-set! (sid) 'game *game*)
|
;; (session-set! (sid) 'game *game*)
|
||||||
;; (set-startup-otbs (session-ref (sid) 'player) 2)
|
;; (set-startup-otbs (session-ref (sid) 'player) 2)
|
||||||
)
|
)
|
||||||
(send-static-file "main.html")
|
(send-static-file "index.html")
|
||||||
;; (with-headers `((connection close)
|
;; (with-headers `((connection close)
|
||||||
;; (content-type text/html))
|
;; (content-type text/html))
|
||||||
;; (lambda ()
|
;; (lambda ()
|
||||||
@@ -1023,7 +1028,31 @@
|
|||||||
(* (/ (alist-ref 'harvest-rolls (player-stats p))
|
(* (/ (alist-ref 'harvest-rolls (player-stats p))
|
||||||
(max (alist-ref 'num-harvests (player-stats p)) 1))
|
(max (alist-ref 'num-harvests (player-stats p)) 1))
|
||||||
10))
|
10))
|
||||||
10)) ")"))))))
|
10)) ")")))
|
||||||
|
(players . ,(list->vector
|
||||||
|
(map (lambda (p)
|
||||||
|
(let ((stats (player-stats p)))
|
||||||
|
`((name . ,(player-name p))
|
||||||
|
(numHarvests . ,(alist-ref 'num-harvests stats))
|
||||||
|
(hay . ,(alist-ref 'hay stats))
|
||||||
|
(grain . ,(alist-ref 'grain stats))
|
||||||
|
(fruit . ,(alist-ref 'fruit stats))
|
||||||
|
(cows . ,(alist-ref 'cows stats))
|
||||||
|
(harvestAverage . ,(exact->inexact
|
||||||
|
(round
|
||||||
|
(/ (fold + 0 (map (lambda (c) (alist-ref c stats))
|
||||||
|
'(hay grain fruit cows)))
|
||||||
|
(alist-ref 'num-harvests stats)))))
|
||||||
|
(harvestTotal . ,(fold + 0 (map (lambda (c) (alist-ref c stats))
|
||||||
|
'(hay grain fruit cows))))
|
||||||
|
(operatingExpenses . ,(alist-ref 'operating-expenses stats))
|
||||||
|
(harvestRoll . ,(exact->inexact
|
||||||
|
(/ (round
|
||||||
|
(* (/ (alist-ref 'harvest-rolls stats)
|
||||||
|
(max (alist-ref 'num-harvests stats) 1))
|
||||||
|
10))
|
||||||
|
10))))))
|
||||||
|
(game-players game)))))))
|
||||||
type: "end-of-game")))
|
type: "end-of-game")))
|
||||||
|
|
||||||
(define (create-ws-response player event misc)
|
(define (create-ws-response player event misc)
|
||||||
@@ -1588,6 +1617,17 @@
|
|||||||
(safe-set! (player-ready-to-start (*player*)) (not (player-ready-to-start (*player*))))
|
(safe-set! (player-ready-to-start (*player*)) (not (player-ready-to-start (*player*))))
|
||||||
(message-players! (*game*) (*player*) '() type: "update")
|
(message-players! (*game*) (*player*) '() type: "update")
|
||||||
(create-ws-response (*player*) "update" '()))
|
(create-ws-response (*player*) "update" '()))
|
||||||
|
((string=? type "birthday-bonus-player")
|
||||||
|
(let ((player (find (lambda (p)
|
||||||
|
(equal? (player-name p) (alist-ref 'name msg)))
|
||||||
|
(game-players (*game*)))))
|
||||||
|
(if (> (alist-ref 'birthday (player-assets player)) 0)
|
||||||
|
(set! (player-assets player)
|
||||||
|
(alist-update 'birthday 0 (player-assets player)))
|
||||||
|
(set! (player-assets player)
|
||||||
|
(alist-update 'birthday 1 (player-assets player))))
|
||||||
|
(message-players! (*game*) (*player*) '() type: "update")
|
||||||
|
(create-ws-response (*player*) "update" '())))
|
||||||
((string=? type "kick-player")
|
((string=? type "kick-player")
|
||||||
(let ((kicked-player (find (lambda (p)
|
(let ((kicked-player (find (lambda (p)
|
||||||
(equal? (player-name p) (alist-ref 'name msg)))
|
(equal? (player-name p) (alist-ref 'name msg)))
|
||||||
@@ -1623,6 +1663,10 @@
|
|||||||
type: "player-left-game")
|
type: "player-left-game")
|
||||||
(create-ws-response (*player*) "left-game" '()))
|
(create-ws-response (*player*) "left-game" '()))
|
||||||
((string=? type "start-game")
|
((string=? type "start-game")
|
||||||
|
(for-each (lambda (p)
|
||||||
|
(when (> (alist-ref 'birthday (player-assets p)) 0)
|
||||||
|
(set-startup-otbs (*game*) p 3)))
|
||||||
|
(game-players (*game*)))
|
||||||
(safe-set! (game-state (*game*)) 'pre-turn)
|
(safe-set! (game-state (*game*)) 'pre-turn)
|
||||||
(db-update-game (game-id (*game*)) (symbol->string (game-state (*game*)))
|
(db-update-game (game-id (*game*)) (symbol->string (game-state (*game*)))
|
||||||
(game->sexp (*game*)))
|
(game->sexp (*game*)))
|
||||||
@@ -2348,7 +2392,7 @@
|
|||||||
(define (make-player-stat stat amount)
|
(define (make-player-stat stat amount)
|
||||||
(lambda (p)
|
(lambda (p)
|
||||||
(safe-set! (player-stats p)
|
(safe-set! (player-stats p)
|
||||||
(alist-update stat (+ (alist-ref stat (player-stats p)) amount)
|
(alist-update stat (+ (alist-ref stat (player-stats p) eqv? 0) amount)
|
||||||
(player-stats p)))))
|
(player-stats p)))))
|
||||||
|
|
||||||
(define (get-actions player space)
|
(define (get-actions player space)
|
||||||
@@ -2572,6 +2616,7 @@
|
|||||||
(begin
|
(begin
|
||||||
((make-player-stat 'num-harvests 1) player)
|
((make-player-stat 'num-harvests 1) player)
|
||||||
((make-player-stat 'harvest-rolls rolled) player)
|
((make-player-stat 'harvest-rolls rolled) player)
|
||||||
|
((make-player-stat crop income) player)
|
||||||
(safe-set! (player-cash player)
|
(safe-set! (player-cash player)
|
||||||
(+ (player-cash player) income))
|
(+ (player-cash player) income))
|
||||||
(safe-set! (player-harvest-mult player) 1)
|
(safe-set! (player-harvest-mult player) 1)
|
||||||
@@ -2585,6 +2630,9 @@
|
|||||||
(player-name player))))
|
(player-name player))))
|
||||||
(game-players game)))))
|
(game-players game)))))
|
||||||
((alist-ref 'action operating-expense) player)
|
((alist-ref 'action operating-expense) player)
|
||||||
|
((make-player-stat 'operating-expenses
|
||||||
|
(- (player-cash player) previous-cash))
|
||||||
|
player)
|
||||||
`((rolled . ,rolled)
|
`((rolled . ,rolled)
|
||||||
(rolls . ,(list->vector (make-rolls 22)))
|
(rolls . ,(list->vector (make-rolls 22)))
|
||||||
(income . ,income)
|
(income . ,income)
|
||||||
|
|||||||
@@ -919,8 +919,6 @@ $trade-margin: 3rem;
|
|||||||
color: white; }
|
color: white; }
|
||||||
|
|
||||||
.alert-overlay-contents {
|
.alert-overlay-contents {
|
||||||
max-height: 90vh;
|
|
||||||
overflow: auto;
|
|
||||||
background: $light-color;
|
background: $light-color;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -928,6 +926,10 @@ $trade-margin: 3rem;
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center; }
|
align-items: center; }
|
||||||
|
|
||||||
|
.alert-container {
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow: auto; }
|
||||||
|
|
||||||
.moving {
|
.moving {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -1049,11 +1051,16 @@ $intro-time: 6s;
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 1rem; }
|
bottom: 1rem; }
|
||||||
|
|
||||||
.kick-player {
|
.lobby-icon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: red;
|
|
||||||
margin-left: 0.2rem; }
|
margin-left: 0.2rem; }
|
||||||
|
|
||||||
|
.kick-player {
|
||||||
|
color: red; }
|
||||||
|
|
||||||
|
.birthday-selected {
|
||||||
|
color: blue; }
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
list-style-type: none; }
|
list-style-type: none; }
|
||||||
@@ -1062,3 +1069,9 @@ ul {
|
|||||||
font-family: 'IndieFlower-Regular';
|
font-family: 'IndieFlower-Regular';
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0; }
|
height: 0; }
|
||||||
|
|
||||||
|
.game-over p {
|
||||||
|
margin-bottom: 0.2rem;
|
||||||
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ const CssUrlRelativePlugin = require('css-url-relative-plugin')
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
app: './src/main.jsx',
|
app: './src/index.jsx',
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: './assets/[name].[contenthash].js',
|
filename: './assets/[name].[hash].js',
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
@@ -50,13 +50,13 @@ module.exports = {
|
|||||||
new CleanWebpackPlugin(),
|
new CleanWebpackPlugin(),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
title: 'Alpha Centauri Farming',
|
title: 'Alpha Centauri Farming',
|
||||||
filename: 'main.html',
|
filename: 'index.html',
|
||||||
meta: {viewport: 'width=device-width, initial-scale=1'},
|
meta: {viewport: 'width=device-width, initial-scale=1'},
|
||||||
}),
|
}),
|
||||||
new FaviconsWebpackPlugin('./assets/img/tractor.svg'),
|
new FaviconsWebpackPlugin('./assets/img/tractor.svg'),
|
||||||
new MiniCssExtractPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: './assets/[name].[contenthash].css',
|
filename: './assets/[name].[hash].css',
|
||||||
chunkFilename: './assets/[id].[contenthash].css',
|
chunkFilename: './assets/[id].[hash].css',
|
||||||
}),
|
}),
|
||||||
new CopyPlugin([
|
new CopyPlugin([
|
||||||
{ from: './src/server/farm.scm', to: './[name].[ext]' },
|
{ from: './src/server/farm.scm', to: './[name].[ext]' },
|
||||||
@@ -96,14 +96,14 @@ module.exports = {
|
|||||||
test: /\.(svg|png|gif)$/,
|
test: /\.(svg|png|gif)$/,
|
||||||
loader: 'file-loader',
|
loader: 'file-loader',
|
||||||
options: {
|
options: {
|
||||||
name: './assets/img/[name].[contenthash].[ext]',
|
name: './assets/img/[name].[hash].[ext]',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||||
loader: 'file-loader',
|
loader: 'file-loader',
|
||||||
options: {
|
options: {
|
||||||
name: './assets/font/[name].[contenthash].[ext]',
|
name: './assets/font/[name].[hash].[ext]',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,14 +20,46 @@ const merge = require('webpack-merge');
|
|||||||
const common = require('./webpack.common.js');
|
const common = require('./webpack.common.js');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||||
|
|
||||||
module.exports = function(env) {
|
module.exports = function(env) {
|
||||||
return merge(common, {
|
return merge(common, {
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
devtool: 'inline-source-map',
|
devtool: 'inline-source-map',
|
||||||
|
devServer: {
|
||||||
|
port: 9000,
|
||||||
|
contentBase: './dist',
|
||||||
|
hot: true,
|
||||||
|
proxy: {
|
||||||
|
'/websocket': {
|
||||||
|
target: 'ws://localhost:8080',
|
||||||
|
ws: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: [path.resolve(__dirname, 'src'),
|
modules: [path.resolve(__dirname, 'src'),
|
||||||
path.resolve(__dirname, env.assets),
|
path.resolve(__dirname, env.assets),
|
||||||
'node_modules']
|
'node_modules']
|
||||||
},
|
},
|
||||||
|
plugins: [
|
||||||
|
new ReactRefreshWebpackPlugin()
|
||||||
|
],
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
options: {
|
||||||
|
plugins: [require.resolve('react-refresh/babel')],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user