Compare commits
9 Commits
logins
...
leave-game
| Author | SHA1 | Date | |
|---|---|---|---|
| 29e4955de5 | |||
| 7ba6f19133 | |||
| 70d8b50ac3 | |||
| b06d1b4513 | |||
| ced8faf6f6 | |||
| afd548ae0b | |||
| 775ec7ed70 | |||
| 333bd70d1a | |||
| 197e4ffc5d |
4
Makefile
4
Makefile
@@ -37,14 +37,14 @@ install:
|
||||
interactive:
|
||||
cd dist/ && csi -include-path $(assets) -include-path ../src/server -s farm.scm
|
||||
|
||||
src/server/farm: src/server/farm.scm
|
||||
src/server/farm: src/server/farm.scm src/server/db.scm
|
||||
cd src/server/ && csc -include-path ../../$(assets) -O3 farm.scm
|
||||
|
||||
farm:
|
||||
make src/server/farm
|
||||
|
||||
runprod:
|
||||
cd dist/ && chmod +x farm && ./farm
|
||||
cd dist/ && chmod +x farm && ./farm -:a50
|
||||
|
||||
upload:
|
||||
rsync -rtvz dist/ $(SERVER):~/farm
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"20 Cows on Peridier Ridge"))))
|
||||
|
||||
(define *ff-text*
|
||||
'(((p (img (@ (src "53c3a93b0867eee67b9b9f6ebc4c1f4a.gif") (style "float: left;"))) "Natural Disaster--The Solar Winds break through the atmosphere. You are luckily shielded by Mt Proctor. Your hay survives and jumps in price. " (b "COLLECT $500 per Hay acre") ". To see if they escaped, other players must roll. Odd: escaped, Even: hit. " (b "Wind hit players must clean up all acres at $100 per acre.")))
|
||||
'(((p (img (@ (src "./assets/img/volcano2.53c3a93b0867eee67b9b9f6ebc4c1f4a.gif") (style "float: left;"))) "Natural Disaster--The Solar Winds break through the atmosphere. You are luckily shielded by Mt Proctor. Your hay survives and jumps in price. " (b "COLLECT $500 per Hay acre") ". To see if they escaped, other players must roll. Odd: escaped, Even: hit. " (b "Wind hit players must clean up all acres at $100 per acre.")))
|
||||
((p "Planetary Disaster Fund comes through." (p (b "COLLECT $100 per Grain acre."))))
|
||||
((p "Another high wind spring and your wheat didn't get sprayed. Weeds take over and cut your harvest in half. Hold this card through Wheat Harvest for this year."))
|
||||
((p "Kept back some of your cows and Proxima B steak goes viral.") (p (b "COLLECT $2,000 if you have cows.")))
|
||||
|
||||
45
assets/img/cake.svg
Normal file
45
assets/img/cake.svg
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 80.125 79.983627"
|
||||
xml:space="preserve"
|
||||
id="svg4786"
|
||||
sodipodi:docname="cake.svg"
|
||||
width="80.125"
|
||||
height="79.983627"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
|
||||
id="metadata4792"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs4790" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1375"
|
||||
id="namedview4788"
|
||||
showgrid="false"
|
||||
inkscape:zoom="9.424"
|
||||
inkscape:cx="40.23"
|
||||
inkscape:cy="27.714"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4786" /><path
|
||||
d="M 79.125,21.572625 H 62.26 v -7.523 c 2.469,-0.565 4.319,-2.775 4.319,-5.4129999 0,-2.758 -4.007,-7.411 -4.811,-8.31599999 -0.379,-0.428 -1.116,-0.427 -1.496,0 -0.803,0.90499999 -4.81,5.55899999 -4.81,8.31599999 0,2.8059999 2.092,5.1269999 4.798,5.4989999 v 7.437 H 48.247 v -7.523 c 2.469,-0.565 4.319,-2.775 4.319,-5.4129999 0,-2.758 -4.007,-7.411 -4.811,-8.31599999 -0.38,-0.428 -1.116,-0.427 -1.496,0 -0.803,0.90499999 -4.81,5.55899999 -4.81,8.31599999 0,2.8059999 2.092,5.1269999 4.798,5.4989999 v 7.437 H 34.233 v -7.523 c 2.469,-0.565 4.319,-2.775 4.319,-5.4129999 0,-2.758 -4.007,-7.411 -4.811,-8.31599999 -0.379,-0.428 -1.116,-0.427 -1.496,0 -0.803,0.90499999 -4.81,5.55899999 -4.81,8.31599999 0,2.8059999 2.092,5.1269999 4.798,5.4989999 v 7.437 H 20.219 v -7.523 c 2.469,-0.565 4.319,-2.775 4.319,-5.4129999 0,-2.758 -4.007,-7.411 -4.811,-8.31599999 -0.38,-0.428 -1.116,-0.427 -1.496,0 -0.803,0.90499999 -4.81,5.55899999 -4.81,8.31599999 0,2.8059999 2.092,5.1269999 4.798,5.4989999 v 7.437 H 1.129 c -0.552,0 -1,0.447 -1,1 v 8.891 c 0,0.062 0.006,0.123 0.017,0.182 0.062,3.042 1.68,5.705 4.084,7.237 v 26.175 H 3.543 c -1.954,0 -3.543,1.59 -3.543,3.543 v 2.023 c 0,1.683 1.181,3.089 2.757,3.449 0.007,0.027 0.002,0.054 0.012,0.081 l 1.717,4.771 c 0.254,0.702 1.133,1.059 2.613,1.059 h 65.803 c 1.48,0 2.359,-0.356 2.613,-1.06 l 1.717,-4.771 c 0.01,-0.027 0.005,-0.054 0.012,-0.081 1.575,-0.36 2.756,-1.766 2.756,-3.449 v -2.023 c 0,-1.953 -1.589,-3.543 -3.543,-3.543 H 75.77 v -26.013 c 2.601,-1.53 4.355,-4.351 4.355,-7.581 v -8.891 c 0,-0.552 -0.448,-0.999 -1,-0.999 z M 57.462,8.6356251 c 0,-1.337 1.953,-4.153 3.558,-6.11 1.668,2.035 3.559,4.833 3.559,6.11 0,1.9619999 -1.596,3.5579999 -3.559,3.5579999 -1.961,0 -3.558,-1.596 -3.558,-3.5579999 z m -14.013,0 c 0,-1.337 1.953,-4.153 3.558,-6.11 1.668,2.035 3.559,4.833 3.559,6.11 0,1.9619999 -1.596,3.5579999 -3.559,3.5579999 -1.962,0 -3.558,-1.596 -3.558,-3.5579999 z m -14.014,0 c 0,-1.337 1.953,-4.153 3.558,-6.11 1.668,2.035 3.559,4.833 3.559,6.11 0,1.9619999 -1.596,3.5579999 -3.559,3.5579999 -1.962,0 -3.558,-1.596 -3.558,-3.5579999 z m -14.014,0 c 0,-1.337 1.953,-4.153 3.558,-6.11 1.668,2.035 3.559,4.833 3.559,6.11 0,1.9619999 -1.596,3.5579999 -3.559,3.5579999 -1.961,0 -3.558,-1.596 -3.558,-3.5579999 z M 72.901,77.983625 H 7.099 c -0.38,0 -0.672,-0.038 -0.854,-0.077 l -1.346,-3.739 h 70.202 l -1.346,3.739 c -0.181,0.039 -0.474,0.077 -0.854,0.077 z m 5.099,-9.384 v 2.023 c 0,0.852 -0.692,1.544 -1.543,1.544 H 3.543 c -0.851,0 -1.543,-0.692 -1.543,-1.544 v -2.023 c 0,-0.851 0.692,-1.543 1.543,-1.543 h 72.914 c 0.851,0 1.543,0.692 1.543,1.543 z m -4.23,-3.543 H 6.23 v -25.229 c 0.855,0.278 1.765,0.433 2.712,0.433 3.383,0 6.327,-1.919 7.798,-4.727 1.472,2.808 4.415,4.727 7.798,4.727 3.383,0 6.327,-1.919 7.798,-4.727 1.472,2.808 4.415,4.727 7.798,4.727 3.383,0 6.327,-1.919 7.798,-4.727 1.472,2.808 4.415,4.727 7.798,4.727 3.383,0 6.326,-1.919 7.798,-4.727 1.472,2.808 4.415,4.727 7.798,4.727 0.848,0 1.666,-0.127 2.442,-0.352 v 25.148 z m 4.355,-33.594 c 0,3.748 -3.049,6.798 -6.798,6.798 -3.749,0 -6.798,-3.05 -6.798,-6.798 0,-0.553 -0.448,-1 -1,-1 -0.552,0 -1,0.447 -1,1 0,3.748 -3.049,6.798 -6.798,6.798 -3.749,0 -6.798,-3.05 -6.798,-6.798 0,-0.553 -0.448,-1 -1,-1 -0.552,0 -1,0.447 -1,1 0,3.748 -3.05,6.798 -6.798,6.798 -3.748,0 -6.798,-3.05 -6.798,-6.798 0,-0.553 -0.448,-1 -1,-1 -0.552,0 -1,0.447 -1,1 0,3.748 -3.05,6.798 -6.798,6.798 -3.748,0 -6.798,-3.05 -6.798,-6.798 0,-0.553 -0.448,-1 -1,-1 -0.552,0 -1,0.447 -1,1 0,3.748 -3.05,6.798 -6.798,6.798 -3.748,0 -6.798,-3.05 -6.798,-6.798 0,-0.059 -0.005,-0.116 -0.015,-0.172 v -7.719 h 75.996 v 7.891 z"
|
||||
id="path4780"
|
||||
inkscape:connector-curvature="0" /></svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
53
package-lock.json
generated
53
package-lock.json
generated
@@ -2212,8 +2212,7 @@
|
||||
"array-uniq": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
|
||||
"integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
|
||||
"dev": true
|
||||
"integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
|
||||
},
|
||||
"array-unique": {
|
||||
"version": "0.3.2",
|
||||
@@ -2667,8 +2666,7 @@
|
||||
"big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
|
||||
},
|
||||
"bignumber.js": {
|
||||
"version": "2.4.0",
|
||||
@@ -3787,6 +3785,16 @@
|
||||
"integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=",
|
||||
"dev": true
|
||||
},
|
||||
"css-url-relative-plugin": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-url-relative-plugin/-/css-url-relative-plugin-1.0.0.tgz",
|
||||
"integrity": "sha1-T4FVU2I2Tw8ZG9HFKLwnsKdqFGw=",
|
||||
"requires": {
|
||||
"loader-utils": "^1.1.0",
|
||||
"parse-import": "^2.0.0",
|
||||
"webpack-sources": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
|
||||
@@ -4189,8 +4197,7 @@
|
||||
"emojis-list": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
|
||||
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
|
||||
"dev": true
|
||||
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
@@ -5486,6 +5493,15 @@
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
},
|
||||
"get-imports": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-imports/-/get-imports-1.0.0.tgz",
|
||||
"integrity": "sha1-R8C07piTUWQsVJdxk79Pyqv1N48=",
|
||||
"requires": {
|
||||
"array-uniq": "^1.0.1",
|
||||
"import-regex": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"get-stdin": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
|
||||
@@ -6018,6 +6034,11 @@
|
||||
"resolve-cwd": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"import-regex": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/import-regex/-/import-regex-1.1.0.tgz",
|
||||
"integrity": "sha1-pVxS5McFx2XKIQ6SQqBrvMiqf2Y="
|
||||
},
|
||||
"imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
@@ -6500,7 +6521,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.0"
|
||||
}
|
||||
@@ -6619,7 +6639,6 @@
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
|
||||
"integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^2.0.0",
|
||||
@@ -6918,8 +6937,7 @@
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||
},
|
||||
"minipass": {
|
||||
"version": "3.1.1",
|
||||
@@ -7681,6 +7699,14 @@
|
||||
"integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==",
|
||||
"dev": true
|
||||
},
|
||||
"parse-import": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-import/-/parse-import-2.0.0.tgz",
|
||||
"integrity": "sha1-KyR0Aw4AirmNt2xLy/TbWucwb18=",
|
||||
"requires": {
|
||||
"get-imports": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
@@ -9694,8 +9720,7 @@
|
||||
"source-list-map": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||
"integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
@@ -10797,7 +10822,6 @@
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
|
||||
"integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-list-map": "^2.0.0",
|
||||
"source-map": "~0.6.1"
|
||||
@@ -10806,8 +10830,7 @@
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"@fortawesome/free-solid-svg-icons": "^5.12.0",
|
||||
"@fortawesome/react-fontawesome": "^0.1.8",
|
||||
"cookies-js": "^1.2.3",
|
||||
"css-url-relative-plugin": "^1.0.0",
|
||||
"mobx": "^5.15.3",
|
||||
"mobx-react": "^6.1.4",
|
||||
"react": "^16.12.0",
|
||||
|
||||
@@ -22,6 +22,7 @@ import CowImg from './../../../assets/img/cow.svg'
|
||||
import HayImg from './../../../assets/img/hay.svg'
|
||||
import WheatImg from './../../../assets/img/wheat.svg'
|
||||
import TractorImg from './../../../assets/img/tractor-icon.svg'
|
||||
import CakeImg from './../../../assets/img/cake.svg'
|
||||
import TractorFullImg from './../../../assets/img/tractor-with-spikes.svg'
|
||||
import HarvesterImg from './../../../assets/img/harvester.svg'
|
||||
import VolcanoImg from './../../../assets/img/volcano2.gif'
|
||||
@@ -46,21 +47,22 @@ import { setSelectedCard, setMessagePanelSpace, setMPDims, movePlayer,
|
||||
setMovingSkip } from './actions.js'
|
||||
import { buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||
submitTradeDeny, submitTradeCancel, audit,
|
||||
buyUncleBert, skip, endAiTurn, startGame } from './interface.js'
|
||||
buyUncleBert, skip, endAiTurn, startGame, readyToStart,
|
||||
leaveGame } from './interface.js'
|
||||
|
||||
function netWorth(player) {
|
||||
return ((player.assets.hay + player.assets.grain) * 2000) +
|
||||
(player.assets.fruit * 5000) +
|
||||
(player.assets.cows * 500) +
|
||||
((player.assets.harvester + player.assets.tractor) * 10000) +
|
||||
(player.assets.fruit * 5000) +
|
||||
(player.assets.cows * 500) +
|
||||
((player.assets.harvester + player.assets.tractor) * 10000) +
|
||||
player.displayCash - player.debt;
|
||||
}
|
||||
|
||||
function assetsValue(player) {
|
||||
return ((player.assets.hay + player.assets.grain) * 2000) +
|
||||
(player.assets.fruit * 5000) +
|
||||
(player.assets.cows * 500) +
|
||||
((player.assets.harvester + player.assets.tractor) * 10000);
|
||||
(player.assets.fruit * 5000) +
|
||||
(player.assets.cows * 500) +
|
||||
((player.assets.harvester + player.assets.tractor) * 10000);
|
||||
}
|
||||
|
||||
function getElementValue(id) {
|
||||
@@ -288,6 +290,12 @@ class PlayerResources extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
/* {' '}
|
||||
* <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
|
||||
function formatMoney(n) {
|
||||
return n.toFixed(1).replace(/(\d)(?=(\d{3})+\.)/g, '$1,').slice(0, -2); }
|
||||
@@ -343,6 +351,7 @@ class PlayerSummary extends React.Component {
|
||||
<PlayerTurnContainer player={player}
|
||||
game={this.props.game}
|
||||
ui={this.props.ui}
|
||||
hideForLarge={this.props.hideForLarge}
|
||||
screen={this.props.screen}
|
||||
showScreen={this.props.showScreen}/>
|
||||
</GroupBox>
|
||||
@@ -421,7 +430,9 @@ class PlayerTurnContainer extends React.Component {
|
||||
<br />
|
||||
</>
|
||||
) : (<></>)}
|
||||
{view}
|
||||
<div className={this.props.hideForLarge ? 'hide-for-large' : ''}>
|
||||
{view}
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
@@ -885,7 +896,7 @@ class Misc extends React.Component {
|
||||
<img src={VolcanoImg} /> Copyright <a href="https://thenounproject.com/Maludk/">Laymik</a> with modifications by Thomas Hintz - <CCBY />
|
||||
</li>
|
||||
<li>
|
||||
<img src={CornImg} /> <img src={FruitImg} /> Copyright <a href='https://madexmade.com/'>Made</a> - <CCBY />
|
||||
<img src={CornImg} /> <img src={FruitImg} /> <img src={CakeImg} /> Copyright <a href='https://madexmade.com/'>Made</a> - <CCBY />
|
||||
</li>
|
||||
<li>
|
||||
<img src={CowImg} /> Copyright <a href='https://thenounproject.com/rivercon/'>rivercon</a> - <CCBY />
|
||||
@@ -1488,6 +1499,24 @@ class Moving extends React.Component {
|
||||
}
|
||||
|
||||
class Action extends React.Component {
|
||||
state = {
|
||||
bertChoice: 'nothing'
|
||||
}
|
||||
|
||||
setBertChoice = (e) => {
|
||||
this.setState({ bertChoice: e.target.value });
|
||||
}
|
||||
|
||||
bertSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
if (this.state.bertChoice === 'accept') {
|
||||
buyUncleBert();
|
||||
this.props.showNextAction();
|
||||
} else if (this.state.bertChoice === 'deny') {
|
||||
this.props.showNextAction();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let view, buttons;
|
||||
const { currentPlayer } = this.props;
|
||||
@@ -1512,44 +1541,54 @@ class Action extends React.Component {
|
||||
buttons = (<Button onClick={() => this.props.showNextAction()}>Continue</Button>);
|
||||
break;
|
||||
case 'farmers-fate':
|
||||
view = (
|
||||
<div className='game-card'>
|
||||
<GroupBox title={fateCard}>
|
||||
<div className='card'
|
||||
dangerouslySetInnerHTML={{ __html: this.props.ui.actionValue }} />
|
||||
</GroupBox>
|
||||
</div>
|
||||
);
|
||||
buttons = (<Button onClick={() => this.props.showNextAction()}>Continue</Button>);
|
||||
break;
|
||||
case 'ff-uncle-bert':
|
||||
const ffButtons = (
|
||||
<Fragment>
|
||||
{this.props.player.cash >= 10000 ? (
|
||||
<Button onClick={() => { buyUncleBert(); this.props.showNextAction(); }}>
|
||||
Yes, take over for $10,000!
|
||||
</Button>
|
||||
) : (<Fragment />)}
|
||||
<Button onClick={() => this.props.showNextAction()}>
|
||||
No, continue on
|
||||
</Button>
|
||||
</Fragment>
|
||||
);
|
||||
view = (
|
||||
<div className='game-card'>
|
||||
<GroupBox title={fateCard}>
|
||||
<div className='card'
|
||||
dangerouslySetInnerHTML={{ __html: this.props.ui.actionValue }} />
|
||||
</GroupBox>
|
||||
</div>
|
||||
);
|
||||
buttons = (<Button onClick={() => this.props.showNextAction()}>Continue</Button>);
|
||||
break;
|
||||
case 'ff-uncle-bert':
|
||||
const { cash } = this.props.player;
|
||||
const ffButtons = (
|
||||
<>
|
||||
{cash < 10000 ? (
|
||||
<Button onClick={() => this.props.showScreen(SCREENS.loans)}>Raise ${formatMoney(10000 - cash)} Now</Button>
|
||||
) : (<></>)}
|
||||
<form onSubmit={this.bertSubmit}>
|
||||
<label>
|
||||
<input type="radio" name="bert" value="accept" onClick={this.setBertChoice} />
|
||||
Yes, take over for $10,000!
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="bert" value="deny" onClick={this.setBertChoice} />
|
||||
No, continue on
|
||||
</label>
|
||||
<Button type="submit" disabled={this.state.bertChoice === 'nothing' || this.state.bertChoice === 'accept' && cash < 10000}>Submit</Button>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
view = (
|
||||
<GroupBox title={`Uncle Bert's inheritance`}>
|
||||
<div className='center'>
|
||||
<p>
|
||||
{currentPlayer.cash >= 10000 ?
|
||||
`You have enough cash to take over Uncle Bert's farm!` :
|
||||
`You must raise another $` +
|
||||
formatMoney(10000 - currentPlayer.cash) +
|
||||
` to be able to take over Uncle Berts farm!`
|
||||
}
|
||||
(
|
||||
<>
|
||||
You must raise another $
|
||||
{formatMoney(10000 - currentPlayer.cash) + ' '}
|
||||
to be able to take over Uncle Berts farm!
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
<div>
|
||||
{(this.props.player.name === this.props.game.currentPlayer) ?
|
||||
ffButtons : (<Fragment />)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</GroupBox>
|
||||
);
|
||||
@@ -1772,6 +1811,11 @@ class AlertOverlay extends React.Component {
|
||||
this.hide(e);
|
||||
this.props.handler();
|
||||
}
|
||||
|
||||
cancelButtonClick = e => {
|
||||
e.preventDefault();
|
||||
this.props.cancelHandler();
|
||||
}
|
||||
// <label><input type='checkbox' onClick={this.hidePermanent} /> {`Don't show again`}</label>
|
||||
|
||||
render() {
|
||||
@@ -1785,7 +1829,17 @@ class AlertOverlay extends React.Component {
|
||||
<div className='alert-overlay-contents'>
|
||||
{this.props.children}
|
||||
<br />
|
||||
<Button onClick={this.buttonClick}>{this.props.buttonText}</Button>
|
||||
<div>
|
||||
<Button onClick={this.buttonClick} disabled={!!this.props.disabled}>{this.props.buttonText}</Button>
|
||||
{this.props.cancelButtonText ? (
|
||||
<>
|
||||
{' '}
|
||||
<Button onClick={this.cancelButtonClick} disabled={!!this.props.cancelDisabled}>
|
||||
{this.props.cancelButtonText}
|
||||
</Button>
|
||||
</>
|
||||
): (<></>)}
|
||||
</div>
|
||||
{!this.props.preventHiding ? (<a onClick={this.hide}>close</a>) : (<></>)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1878,9 +1932,47 @@ class Info extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
class StartGame extends React.Component {
|
||||
render() {
|
||||
const { auditThreshold, downPayment, loanInterest, maxDebt, startingOtbs, startingCash, startingDebt } = this.props.game.settings;
|
||||
const { name } = this.props.game;
|
||||
return (
|
||||
<>
|
||||
<h1>Lobby</h1>
|
||||
<p>
|
||||
<b>Game</b>: {name}
|
||||
</p>
|
||||
<h3>Players</h3>
|
||||
<ul>
|
||||
<li>{this.props.player.name}</li>
|
||||
{this.props.game.otherPlayers.map((p, i) => (
|
||||
<li key={i}>
|
||||
{p.player.name}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<h4>Game Settings</h4>
|
||||
<ul>
|
||||
<li><b>Audit Threshold</b>: ${formatMoney(auditThreshold)}</li>
|
||||
<li><b>Max Debt</b>: ${formatMoney(maxDebt)}</li>
|
||||
<li><b>Loan Interest</b>: {loanInterest * 100}%</li>
|
||||
<li><b>Required Down Payment</b>: ${formatMoney(downPayment)}</li>
|
||||
<li><b>Starting {itemCardShort}</b>: {startingOtbs}</li>
|
||||
<li><b>Starting Cash</b>: ${formatMoney(startingCash)}</li>
|
||||
<li><b>Starting Debt</b>: ${formatMoney(startingDebt)}</li>
|
||||
</ul>
|
||||
<label>
|
||||
<input type="checkbox" onChange={this.props.toggleReady} />
|
||||
Ready to start
|
||||
</label>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const SCREENS = { summary: 'summary', misc: 'misc', farms: 'farms',
|
||||
cards: 'cards', trade: 'trade', loans: 'loans',
|
||||
action: 'action', info: 'info' };
|
||||
action: 'action', info: 'info', error: 'error' };
|
||||
|
||||
class BoardApp extends React.Component {
|
||||
iconToScreen = { user: SCREENS.summary, 'window-restore': SCREENS.cards,
|
||||
@@ -1895,7 +1987,8 @@ class BoardApp extends React.Component {
|
||||
screen: SCREENS.summary,
|
||||
card: props.ui.card,
|
||||
timerId: false,
|
||||
currentPlayer: this.props.player
|
||||
currentPlayer: this.props.player,
|
||||
readyToStart: false
|
||||
};
|
||||
this.myRef = React.createRef();
|
||||
this.actionRef = React.createRef();
|
||||
@@ -1943,6 +2036,10 @@ class BoardApp extends React.Component {
|
||||
.find(p => p.player.name === this.props.game.currentPlayer).player;
|
||||
this.setState({ currentPlayer });
|
||||
}
|
||||
|
||||
if (!prevProps.ui.exn && this.props.ui.exn) {
|
||||
this.setState({ screen: SCREENS.error });
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -1996,6 +2093,11 @@ class BoardApp extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
startGameToggleReady = () => {
|
||||
this.setState(state => { return { readyToStart: !state.readyToStart }; });
|
||||
readyToStart();
|
||||
}
|
||||
|
||||
render() {
|
||||
let alertOverlay;
|
||||
const alert = this.props.ui.unhandledAlert;
|
||||
@@ -2037,21 +2139,16 @@ class BoardApp extends React.Component {
|
||||
alertHandled={this.props.alertHandled}
|
||||
buttonText='Start Game'
|
||||
hideHandler={() => 'nothing'}
|
||||
cancelButtonText='Leave Game'
|
||||
cancelHandler={leaveGame}
|
||||
cancelDisabled={this.state.readyToStart}
|
||||
preventHiding={true}
|
||||
disabled={!this.props.game.readyToStart}
|
||||
handler={startGame}>
|
||||
<Fragment>
|
||||
<h1>Pre Game</h1>
|
||||
<p>When all players have joined click 'Start Game'!</p>
|
||||
<h3>Players</h3>
|
||||
<ul>
|
||||
<li>{this.props.player.name}</li>
|
||||
{this.props.game.otherPlayers.map((p, i) => (
|
||||
<li key={i}>
|
||||
{p.player.name}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Fragment>
|
||||
<StartGame player={this.props.player}
|
||||
game={this.props.game}
|
||||
toggleReady={this.startGameToggleReady}
|
||||
/>
|
||||
</AlertOverlay>
|
||||
);
|
||||
} else if (alert && alert.type === ALERTS.proposedTrade) {
|
||||
@@ -2165,6 +2262,7 @@ class BoardApp extends React.Component {
|
||||
<PlayerSummary player={this.props.player}
|
||||
ui={this.props.ui}
|
||||
screen={this.state.screen}
|
||||
hideForLarge={true}
|
||||
game={this.props.game} showScreen={this.showScreen} />
|
||||
</div>
|
||||
<div className={this.tabClass(SCREENS.action)}>
|
||||
@@ -2207,6 +2305,11 @@ class BoardApp extends React.Component {
|
||||
<div className={this.tabClass(SCREENS.info)}>
|
||||
<Info harvestTable={this.props.ui.harvestTable} game={this.props.game} />
|
||||
</div>
|
||||
<div className={this.tabClass(SCREENS.error)}>
|
||||
<h3>Error</h3>
|
||||
<p>A server error occured.</p>
|
||||
<p><a href="/?reload-game=true">Reload game</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='static-tab-container show-for-large'>
|
||||
<div className='tab show'>
|
||||
|
||||
@@ -39,3 +39,5 @@ export const AUTO_SKIP = 'auto-skip'
|
||||
export const MESSAGE = 'message'
|
||||
export const SET_HARVEST_TABLE = 'set-harvest-table'
|
||||
export const SET_MOVING_SKIP = 'set-moving-skip'
|
||||
export const SERVER_ERROR = 'server-error'
|
||||
export const REMOVE_PLAYER = 'remove-player'
|
||||
|
||||
@@ -21,13 +21,14 @@ import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
|
||||
MP_MOUSE, SET_MP_DIMS, MARK_ACTION_CHANGE_HANDLED, SET_NEXT_ACTION,
|
||||
MOVE_PLAYER, NEXT_UI_ACTION, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED,
|
||||
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR,
|
||||
SET_MOVING_SKIP } from './actionTypes.js'
|
||||
SET_MOVING_SKIP, SERVER_ERROR, REMOVE_PLAYER } from './actionTypes.js'
|
||||
|
||||
export { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
|
||||
spacePushPlayer, spaceClearPlayers, setOldMessages, setMessagePanelSpace,
|
||||
mpMouse, setMPDims, movePlayer, setNextAction, nextUIAction,
|
||||
markActionChangeHandled, nextUIActionSilent, alert, alertHandled,
|
||||
autoSkip, message, setHarvestTable, setCardError, setMovingSkip }
|
||||
autoSkip, message, setHarvestTable, setCardError, setMovingSkip,
|
||||
serverError, removePlayer }
|
||||
|
||||
function updateGame(update) {
|
||||
return { type: UPDATE_GAME,
|
||||
@@ -95,6 +96,11 @@ function movePlayer(newSpace, oldSpace, player) {
|
||||
newSpace, oldSpace, player };
|
||||
}
|
||||
|
||||
function removePlayer(color) {
|
||||
return { type: REMOVE_PLAYER,
|
||||
color };
|
||||
}
|
||||
|
||||
function nextUIAction() {
|
||||
return { type: NEXT_UI_ACTION };
|
||||
}
|
||||
@@ -135,3 +141,7 @@ function setHarvestTable(table) {
|
||||
function setMovingSkip(skip) {
|
||||
return { type: SET_MOVING_SKIP, skip };
|
||||
}
|
||||
|
||||
function serverError(exn) {
|
||||
return { type: SERVER_ERROR, exn };
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@ import { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
|
||||
movePlayer, setOldMessages, markActionChangeHandled,
|
||||
mpMouse, rolled, setNextAction, nextUIAction, nextUIActionSilent, alert,
|
||||
autoSkip, message, alertHandled, setHarvestTable,
|
||||
setCardError, setMovingSkip } from './actions.js'
|
||||
setCardError, setMovingSkip, serverError, removePlayer } from './actions.js'
|
||||
import { itemCard, fateCard } from 'game.js'
|
||||
|
||||
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||
submitTradeDeny, submitTradeCancel, audit, handleMessage,
|
||||
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
|
||||
startGame }
|
||||
startGame, readyToStart, leaveGame }
|
||||
|
||||
let store;
|
||||
let movingTimer = 0;
|
||||
@@ -42,9 +42,16 @@ function handleMessage(evt) {
|
||||
|
||||
if (data.event === 'error') {
|
||||
console.log('error:' + data.exn);
|
||||
store.dispatch(serverError(data.exn));
|
||||
return;
|
||||
}
|
||||
batch(() => {
|
||||
if (data.event === 'left-game') {
|
||||
window.location.href = window.location.pathname;
|
||||
}
|
||||
if (data.event === 'player-left-game') {
|
||||
store.dispatch(removePlayer(data.color));
|
||||
}
|
||||
if (data.game.state === GAME_STATES.preGame) {
|
||||
store.dispatch(alert(ALERTS.preGame, '', 'pre-game'));
|
||||
}
|
||||
@@ -79,7 +86,7 @@ function handleMessage(evt) {
|
||||
store.dispatch(movePlayer(data.player.space, -1, data.player.color));
|
||||
store.dispatch(setHarvestTable(data.harvestTable));
|
||||
}
|
||||
// new player(s) added to game, put them on the board
|
||||
// player(s) added or removed from 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(
|
||||
@@ -198,6 +205,14 @@ function startGame() {
|
||||
sendCommand({ type: 'start-game' });
|
||||
}
|
||||
|
||||
function readyToStart() {
|
||||
sendCommand({ type: 'ready-to-start' });
|
||||
}
|
||||
|
||||
function leaveGame() {
|
||||
sendCommand({ type: 'leave-game' });
|
||||
}
|
||||
|
||||
// TODO share with Board.jsx
|
||||
// http://stackoverflow.com/questions/149055
|
||||
function formatMoney(n) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
|
||||
SET_MP_DIMS, MOVE_PLAYER, SET_NEXT_ACTION, NEXT_UI_ACTION,
|
||||
MARK_ACTION_CHANGE_HANDLED, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED,
|
||||
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR,
|
||||
SET_MOVING_SKIP } from './actionTypes.js'
|
||||
SET_MOVING_SKIP, SERVER_ERROR, REMOVE_PLAYER } from './actionTypes.js'
|
||||
import { GAME_STATES } from '../../constants.js'
|
||||
import { spaceContent, corners } from 'game.js'
|
||||
|
||||
@@ -88,7 +88,7 @@ const initialState = {
|
||||
debt: 5000,
|
||||
spaces,
|
||||
state: GAME_STATES.turnEnded,
|
||||
assets: { hay: 10, grain: 10, fruit: 0, cows: 0, harvester: 0, tractor: 0 },
|
||||
assets: { hay: 10, grain: 10, fruit: 0, cows: 0, harvester: 0, tractor: 0, birthday: 0 },
|
||||
color: '',
|
||||
name: '',
|
||||
ridges: { ridge1: 0, ridge2: 0, ridge3: 0, ridge4: 0 },
|
||||
@@ -105,10 +105,15 @@ const initialState = {
|
||||
state: GAME_STATES.preTurn,
|
||||
turn: 0,
|
||||
oldMessages: [],
|
||||
name: '',
|
||||
settings: { downPayment: 0.2,
|
||||
loanInterest: 0.2,
|
||||
maxDebt: 50000,
|
||||
auditThreshold: 250000 }
|
||||
auditThreshold: 250000,
|
||||
startingOtbs: 2,
|
||||
startingCash: 5000,
|
||||
startingDebt: 5000 },
|
||||
readyToStart: false
|
||||
},
|
||||
ui: { card: { type: 'no-card', contents: '', total: 0 },
|
||||
cards: [],
|
||||
@@ -124,7 +129,8 @@ const initialState = {
|
||||
autoSkip: false,
|
||||
playerSpaces: {},
|
||||
movingSkip: false,
|
||||
harvestTable: false },
|
||||
harvestTable: false,
|
||||
exn: false },
|
||||
spaces: spaces,
|
||||
space: null,
|
||||
// message panel dimenions
|
||||
@@ -170,6 +176,21 @@ export default function(state = initialState, action) {
|
||||
[action.player]: action.newSpace }}
|
||||
};
|
||||
}
|
||||
case REMOVE_PLAYER:
|
||||
const playerSpace = state.ui.playerSpaces[action.color];
|
||||
return { ...state,
|
||||
spaces: state.spaces.map((item, index) => {
|
||||
if (index === playerSpace) {
|
||||
return { ...item,
|
||||
players: item.players
|
||||
.filter(x => x !== action.color) };
|
||||
}
|
||||
return item;
|
||||
}),
|
||||
ui: { ...state.ui,
|
||||
playerSpaces: { ...state.ui.playerSpaces,
|
||||
[action.player]: -1 }}
|
||||
};
|
||||
case SET_OLD_MESSAGES:
|
||||
return { ...state, oldMessages: action.messages };
|
||||
case MESSAGE_PANEL_SPACE:
|
||||
@@ -228,6 +249,8 @@ export default function(state = initialState, action) {
|
||||
return { ...state, ui: { ...state.ui, harvestTable: action.table }};
|
||||
case SET_MOVING_SKIP:
|
||||
return { ...state, ui: { ...state.ui, movingSkip: action.skip }};
|
||||
case SERVER_ERROR:
|
||||
return { ...state, ui: { ...state.ui, exn: action.exn }};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccoun
|
||||
import { startOrJoinGame } from '../start/actions.js'
|
||||
import { start } from '../app/actions.js'
|
||||
|
||||
import { itemCardShort } from 'game.js'
|
||||
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faArrowCircleLeft, faCog } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
@@ -63,6 +65,7 @@ class NewGame extends React.Component {
|
||||
auditThreshold: 250000,
|
||||
startingCash: 5000,
|
||||
startingDebt: 5000,
|
||||
startingOtbs: 2,
|
||||
trade: true,
|
||||
showLogin: false
|
||||
};
|
||||
@@ -71,10 +74,10 @@ class NewGame extends React.Component {
|
||||
handleInputChange = e => {
|
||||
const target = e.target,
|
||||
value = target.type === 'checkbox' && target.name !== 'trade'
|
||||
? target.name : target.value,
|
||||
? target.name : target.value,
|
||||
|
||||
name = target.type === 'checkbox' && target.name !== 'trade'
|
||||
? 'checkedColor' : target.name;
|
||||
? 'checkedColor' : target.name;
|
||||
|
||||
this.setState({
|
||||
[name]: value
|
||||
@@ -98,122 +101,129 @@ class NewGame extends React.Component {
|
||||
|
||||
render() {
|
||||
let titleBar = !this.props.hideBack ? (
|
||||
<Fragment>
|
||||
<a onClick={this.handleBack}>
|
||||
<Fragment>
|
||||
<a onClick={this.handleBack}>
|
||||
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
||||
</a>
|
||||
{this.props.title}
|
||||
</Fragment>
|
||||
) : this.props.title,
|
||||
</a>
|
||||
{this.props.title}
|
||||
</Fragment>
|
||||
) : this.props.title,
|
||||
colors = 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} />
|
||||
<input type='checkbox'
|
||||
checked={this.state.checkedColor === c}
|
||||
onChange={this.handleInputChange}
|
||||
name={c} />
|
||||
</label>
|
||||
)
|
||||
),
|
||||
),
|
||||
gameName = this.props.showGameName && (
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>Game Name
|
||||
<input type='text' name='gameName' value={this.state.gameName}
|
||||
required
|
||||
onChange={this.handleInputChange} />
|
||||
</label>
|
||||
</Col>
|
||||
<Col width='12'>
|
||||
<label>Game Name
|
||||
<input type='text' name='gameName' value={this.state.gameName}
|
||||
required
|
||||
onChange={this.handleInputChange} />
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
),
|
||||
settingsClass = this.state.showSettings ? '' : 'hidden',
|
||||
mainScreenClass = !this.state.showSettings ? '' : 'hidden';
|
||||
return (
|
||||
<GroupBox title={titleBar}>
|
||||
{this.props.user ? (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className={mainScreenClass}>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>Your Color</label>
|
||||
{colors}
|
||||
<br /><br />
|
||||
</Col>
|
||||
</Row>
|
||||
{gameName}
|
||||
</div>
|
||||
<div className={settingsClass}>
|
||||
<InputRow label='Down Payment'
|
||||
name='downPayment'
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={this.state.downPayment}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Loan Interest'
|
||||
name='loanInterest'
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={this.state.loanInterest}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Maximum Debt'
|
||||
name='maxDebt'
|
||||
min={0}
|
||||
step={5000}
|
||||
value={this.state.maxDebt}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Audit Threshold'
|
||||
name='auditThreshold'
|
||||
min={0}
|
||||
step={25000}
|
||||
value={this.state.auditThreshold}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Starting Cash'
|
||||
name='startingCash'
|
||||
min={0}
|
||||
step={1000}
|
||||
value={this.state.startingCash}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Starting Debt'
|
||||
name='startingDebt'
|
||||
min={0}
|
||||
step={1000}
|
||||
value={this.state.startingDebt}
|
||||
onChange={this.handleInputChange} />
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>
|
||||
<input type='checkbox'
|
||||
checked={this.state.trade}
|
||||
onChange={this.handleInputChange}
|
||||
name='trade' />
|
||||
Enable Trading
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<div className='new-game-submit-container'>
|
||||
<Button type='submit'>{this.props.button} Game</Button>
|
||||
{this.props.showGameName ? (
|
||||
<a onClick={this.toggleSettings}>
|
||||
<FontAwesomeIcon icon={faCog} size='lg' />
|
||||
</a>
|
||||
) : (<Fragment />)}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
) : (
|
||||
<>
|
||||
<span>Sign in or create account to continue</span>
|
||||
<LoginOrCreateAccount login={this.props.login}
|
||||
createAccount={this.props.createAccount}
|
||||
errors={this.props.errors}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{this.props.user ? (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className={mainScreenClass}>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>Your Color</label>
|
||||
{colors}
|
||||
<br /><br />
|
||||
</Col>
|
||||
</Row>
|
||||
{gameName}
|
||||
</div>
|
||||
<div className={settingsClass}>
|
||||
<InputRow label='Down Payment'
|
||||
name='downPayment'
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={this.state.downPayment}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Loan Interest'
|
||||
name='loanInterest'
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={this.state.loanInterest}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Maximum Debt'
|
||||
name='maxDebt'
|
||||
min={0}
|
||||
step={5000}
|
||||
value={this.state.maxDebt}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Audit Threshold'
|
||||
name='auditThreshold'
|
||||
min={0}
|
||||
step={25000}
|
||||
value={this.state.auditThreshold}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Starting Cash'
|
||||
name='startingCash'
|
||||
min={0}
|
||||
step={1000}
|
||||
value={this.state.startingCash}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Starting Debt'
|
||||
name='startingDebt'
|
||||
min={0}
|
||||
step={1000}
|
||||
value={this.state.startingDebt}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label={'Number of Starting ' + itemCardShort}
|
||||
name='startingOtbs'
|
||||
min={0}
|
||||
max={8}
|
||||
step={1}
|
||||
value={this.state.startingOtbs}
|
||||
onChange={this.handleInputChange} />
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>
|
||||
<input type='checkbox'
|
||||
checked={this.state.trade}
|
||||
onChange={this.handleInputChange}
|
||||
name='trade' />
|
||||
Enable Trading
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<div className='new-game-submit-container'>
|
||||
<Button type='submit'>{this.props.button} Game</Button>
|
||||
{this.props.showGameName ? (
|
||||
<a onClick={this.toggleSettings}>
|
||||
<FontAwesomeIcon icon={faCog} size='lg' />
|
||||
</a>
|
||||
) : (<Fragment />)}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
) : (
|
||||
<>
|
||||
<span>Sign in or create account to continue</span>
|
||||
<LoginOrCreateAccount login={this.props.login}
|
||||
createAccount={this.props.createAccount}
|
||||
errors={this.props.errors}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</GroupBox>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ const unsubscribeNewOrJoinGame = store.subscribe(() => {
|
||||
});
|
||||
|
||||
let autostart = new URL(window.location.href).searchParams.get('autostart');
|
||||
let rejoin = new URL(window.location.href).searchParams.get('reload-game');
|
||||
|
||||
function handleMessage(evt) {
|
||||
const data = JSON.parse(evt.data),
|
||||
@@ -86,6 +87,8 @@ function handleMessage(evt) {
|
||||
if (data.event === 'error') {
|
||||
console.log('error:' + data.exn);
|
||||
} else if (data.event === 'new-game-started') {
|
||||
history.replaceState({}, document.title, '/');
|
||||
console.log('clearing auto-reload');
|
||||
initialize(store, Ws.sendCommand);
|
||||
Ws.setMainOnMessage(handleMessageFarm);
|
||||
Ws.openSecondary('push-web-socket');
|
||||
@@ -111,6 +114,10 @@ function handleMessage(evt) {
|
||||
gameName: data.games.games[0].name }));
|
||||
}
|
||||
}
|
||||
if (rejoin) {
|
||||
store.dispatch(startOrJoinGame({ type: 'join-as-existing',
|
||||
gameId: false }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
(with-db (db)
|
||||
(exec (sql db "create table users(id INTEGER PRIMARY KEY, username TEXT, email TEXT, password TEXT, salt TEXT);"))
|
||||
(exec (sql db "create table sessions(bindings TEXT, session_id TEXT PRIMARY KEY);"))
|
||||
(exec (sql db "create table games(id INTEGER PRIMARY KEY, status TEXT, object TEXT);"))
|
||||
(exec (sql db "create table games(id INTEGER PRIMARY KEY, status TEXT, object TEXT, updated INTEGER);"))
|
||||
(exec (sql db "create table players(id INTEGER PRIMARY KEY, object TEXT);"))
|
||||
(exec (sql db "create table user_games(user_id INTEGER, game_id INTEGER);"))))
|
||||
|
||||
@@ -70,14 +70,14 @@
|
||||
|
||||
(define (db-add-game status object)
|
||||
(with-db (db)
|
||||
(exec (sql db "insert into games(status, object) values (?, ?);")
|
||||
status (alist->string object))
|
||||
(exec (sql db "insert into games(status, object, updated) values (?, ?, ?);")
|
||||
status (alist->string object) (current-seconds))
|
||||
(last-insert-rowid db)))
|
||||
|
||||
(define (db-update-game id status object)
|
||||
(with-db (db)
|
||||
(exec (sql db "replace into games(id, status, object) values (?, ?, ?);")
|
||||
id status (alist->string object))))
|
||||
(exec (sql db "replace into games(id, status, object, updated) values (?, ?, ?, ?);")
|
||||
id status (alist->string object) (current-seconds))))
|
||||
|
||||
(define (db-fetch-game id)
|
||||
(string->alist
|
||||
@@ -91,7 +91,7 @@
|
||||
string->alist
|
||||
(with-db (db)
|
||||
(query fetch-column
|
||||
(sql db "select object from games where status=?;")
|
||||
(sql db "select object from games where status=? order by updated desc;")
|
||||
"pre-game"))))
|
||||
|
||||
(define (db-fetch-game-row id)
|
||||
@@ -127,8 +127,13 @@
|
||||
(exec (sql db "insert into user_games(user_id, game_id) values (?, ?);")
|
||||
user-id game-id)))
|
||||
|
||||
(define (db-remove-user-game user-id game-id)
|
||||
(with-db (db)
|
||||
(exec (sql db "delete from user_games where user_id=? and game_id=?;")
|
||||
user-id game-id)))
|
||||
|
||||
(define (db-fetch-user-games user-id)
|
||||
(with-db (db)
|
||||
(query fetch-column
|
||||
(sql db "select game_id from user_games where user_id=?;")
|
||||
user-id)))
|
||||
(sql db "select game_id from user_games join games on user_games.game_id=games.id where user_games.user_id=? and not games.status=? order by updated desc;")
|
||||
user-id "finished")))
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
;;; <https://www.gnu.org/licenses/>.
|
||||
|
||||
(import chicken scheme srfi-1 data-structures)
|
||||
(use http-session srfi-69 coops uri-common
|
||||
(use http-session srfi-69 coops coops-utils uri-common
|
||||
srfi-18 medea numbers spiffy spiffy-cookies
|
||||
intarweb pll sxml-transforms websockets miscmacros
|
||||
mailbox)
|
||||
@@ -106,7 +106,8 @@
|
||||
(finished initform: #f accessor: player-finished)
|
||||
(assets initform:
|
||||
'((hay . 10) (grain . 10) (fruit . 0) (cows . 0)
|
||||
(harvester . 0) (tractor . 0))
|
||||
(harvester . 0) (tractor . 0)
|
||||
(birthday . 0))
|
||||
accessor: player-assets)
|
||||
(ridges initform:
|
||||
'((ridge1 . 0) (ridge2 . 0) (ridge3 . 0) (ridge4 . 0))
|
||||
@@ -126,7 +127,8 @@
|
||||
(mutex initform: (make-mutex 'player) accessor: player-mutex)
|
||||
(harvesting initform: #f accessor: player-harvesting)
|
||||
(hay-doubled initform: #f accessor: player-hay-doubled)
|
||||
(corn-doubled initform: #f accessor: player-corn-doubled)))
|
||||
(corn-doubled initform: #f accessor: player-corn-doubled)
|
||||
(ready-to-start initform: #f accessor: player-ready-to-start)))
|
||||
|
||||
(define-class <ai> (<player>)
|
||||
((processing-turn initform: #f accessor: ai-processing-turn)))
|
||||
@@ -155,7 +157,8 @@
|
||||
(audit-threshold . 250000)
|
||||
(starting-cash . 5000)
|
||||
(starting-debt . 5000)
|
||||
(trade . #t))
|
||||
(trade . #t)
|
||||
(starting-otbs . 2))
|
||||
accessor: game-settings)
|
||||
(mutex initform: (make-mutex 'game) accessor: game-mutex)))
|
||||
|
||||
@@ -168,8 +171,8 @@
|
||||
(mutex initform: (make-mutex 'app) accessor: app-mutex)))
|
||||
|
||||
(define (player->sexp player)
|
||||
`((cash . ,(player-cash player))
|
||||
(debt . ,(player-debt player))
|
||||
`((cash . ,(inexact->exact (round (player-cash player))))
|
||||
(debt . ,(inexact->exact (round (player-debt player))))
|
||||
(space . ,(player-space player))
|
||||
(previous-space . ,(player-previous-space player))
|
||||
(state . ,(player-state player))
|
||||
@@ -246,12 +249,54 @@
|
||||
'games (map sexp->game (alist-ref 'games x))
|
||||
'last-game-id (alist-ref 'last-game-id x)))
|
||||
|
||||
(define (save-app)
|
||||
(with-output-to-file "/home/tjhintz/app.scm"
|
||||
(lambda ()
|
||||
(write (app->sexp *app*)))))
|
||||
(define (validate-game g)
|
||||
(assert (instance-of? g <game>))
|
||||
(assert (number? (game-id g)))
|
||||
(assert (list? (game-players g)))
|
||||
(for-each (lambda (p)
|
||||
(assert (instance-of? p <player>))
|
||||
(assert (number? (player-cash p)))
|
||||
(assert (number? (player-display-cash p)))
|
||||
(assert (= (player-cash p) (player-display-cash p)))
|
||||
(assert (number? (player-debt p)))
|
||||
(assert (number? (player-space p)))
|
||||
(assert (number? (player-previous-space p)))
|
||||
(assert (symbol? (player-state p)))
|
||||
(assert (member (player-state p) '(turn-ended pre-turn mid-turn)))
|
||||
(assert (boolean? (player-finished p)))
|
||||
(assert (list? (player-assets p))) ;; TODO test assets
|
||||
(assert (list? (player-ridges p)))
|
||||
(assert (number? (player-harvest-mult p)))
|
||||
(assert (list? (player-otbs p)))
|
||||
(assert (list? (player-farmers-fates p)))
|
||||
(assert (list? (player-year-rules p)))
|
||||
(assert (list? (player-next-year-rules p)))
|
||||
(assert (symbol? (player-color p)))
|
||||
(assert (string? (player-name p)))
|
||||
(assert (number? (player-user-id p)))
|
||||
(assert (list? (player-trade p)))
|
||||
(assert (number? (player-last-cash p)))
|
||||
(assert (boolean? (player-harvesting p)))
|
||||
(assert (boolean? (player-hay-doubled p)))
|
||||
(assert (boolean? (player-corn-doubled p))))
|
||||
(game-players g))
|
||||
(assert (list? (game-otbs g)))
|
||||
(assert (list? (game-used-otbs g)))
|
||||
(assert (list? (game-farmers-fates g)))
|
||||
(assert (list? (game-operating-expenses g)))
|
||||
(assert (number? (game-operating-expense-index g)))
|
||||
(assert (list? (game-colors g)))
|
||||
(assert (or (instance-of? (game-called-audit g) <player>)
|
||||
(boolean? (game-called-audit g))))
|
||||
(assert (symbol? (game-state g))) ;; TODO test all symbols
|
||||
(assert (string? (game-name g)))
|
||||
(assert (number? (game-turn g)))
|
||||
(assert (or (instance-of? (game-current-player g) <player>)
|
||||
(boolean? (game-current-player g))))
|
||||
(assert (list? (game-settings g))))
|
||||
|
||||
(define (save-game game)
|
||||
(validate-game game)
|
||||
(db-update-game (game-id game) (symbol->string (game-state game))
|
||||
(game->sexp game)))
|
||||
|
||||
@@ -292,7 +337,9 @@
|
||||
(set-cookie! (session-cookie-name) sid))))
|
||||
(session-lifetime (* 60 60 24 7 4))
|
||||
|
||||
(access-log (current-output-port))
|
||||
;; (access-log (current-output-port))
|
||||
(access-log "access.log")
|
||||
(error-log "error.log")
|
||||
|
||||
(handle-not-found
|
||||
(let ((old-handler (handle-not-found)))
|
||||
@@ -518,11 +565,19 @@
|
||||
#f))
|
||||
(state . ,(symbol->string (game-state g)))
|
||||
(turn . ,(game-turn g))
|
||||
(name . ,(game-name g))
|
||||
(settings . ((downPayment . ,(game-setting 'down-payment g))
|
||||
(loanInterest . ,(game-setting 'loan-interest g))
|
||||
(maxDebt . ,(game-setting 'max-debt g))
|
||||
(auditThreshold . ,(game-setting 'audit-threshold g))
|
||||
(trade . ,(game-setting 'trade g))))))))
|
||||
(startingOtbs . ,(game-setting 'starting-otbs g))
|
||||
(startingCash . ,(game-setting 'starting-cash g))
|
||||
(startingDebt . ,(game-setting 'starting-debt g))
|
||||
(trade . ,(game-setting 'trade g))))
|
||||
(readyToStart . ,(fold (lambda (p r)
|
||||
(and (player-ready-to-start p) r))
|
||||
#t
|
||||
(game-players g)))))))
|
||||
|
||||
(define (buy-crop crop unnormalized-crop amount cash-value player game)
|
||||
(let ((total-cost (* amount (alist-ref unnormalized-crop
|
||||
@@ -576,14 +631,21 @@
|
||||
(lambda (p1 p2)
|
||||
(> (player-net-worth p1)
|
||||
(player-net-worth p2))))))
|
||||
(bonus (max (farming-round
|
||||
(* (- (player-net-worth richest)
|
||||
(player-net-worth player))
|
||||
0.2))
|
||||
2500)))
|
||||
;; (bonus (max (farming-round
|
||||
;; (inexact->exact
|
||||
;; (round
|
||||
;; (* (- (player-net-worth richest)
|
||||
;; (+ (player-net-worth player)
|
||||
;; ;; don't give a bonus for emergency debt
|
||||
;; (max 0 (- (player-debt player) (game-setting 'max-debt game)))))
|
||||
;; 0.2))))
|
||||
;; 2500))
|
||||
(bonus 5000)
|
||||
)
|
||||
(safe-set! (player-cash player)
|
||||
;; (+ (player-cash player) 5000)
|
||||
(+ (player-cash player) bonus))
|
||||
(+ (player-cash player) 5000)
|
||||
;; (+ (player-cash player) bonus)
|
||||
)
|
||||
(safe-set! (player-display-cash player) (player-cash player))
|
||||
(safe-set! (game-actions game)
|
||||
(cons `((?action . info)
|
||||
@@ -826,8 +888,8 @@
|
||||
#f)))
|
||||
|
||||
(define (call-audit game player)
|
||||
(if (game-called-audit game)
|
||||
(begin (safe-set! (game-called-audit game) player))))
|
||||
(if (not (game-called-audit game))
|
||||
(safe-set! (game-called-audit game) player)))
|
||||
|
||||
(define (player-net-worth player)
|
||||
(+ (* (+ (player-asset 'hay player) (player-asset 'grain player)) 2000)
|
||||
@@ -941,6 +1003,17 @@
|
||||
rolls))
|
||||
(_make-rolls n 1 (list (next-roll -1))))
|
||||
|
||||
(define (log-error exn)
|
||||
(with-output-to-file (error-log)
|
||||
(lambda ()
|
||||
(print-call-chain)
|
||||
(print exn)
|
||||
(print-error-message exn))
|
||||
append:))
|
||||
|
||||
(define (log-msg msg)
|
||||
(log-to (error-log) "~A" msg))
|
||||
|
||||
(define (process-message player game type msg)
|
||||
(when player
|
||||
(safe-set! (player-last-cash player) (player-cash player)))
|
||||
@@ -1252,10 +1325,8 @@
|
||||
(begin (advance-turn game player)
|
||||
(handle-exceptions
|
||||
exn
|
||||
(begin (print-call-chain)
|
||||
(print exn)
|
||||
(print-error-message exn)
|
||||
(print "error saving app"))
|
||||
(begin (log-error exn)
|
||||
(log-msg "error saving app"))
|
||||
(save-game game))
|
||||
(if (eq? (game-state game) 'finished)
|
||||
(do-end-of-game game)
|
||||
@@ -1285,6 +1356,10 @@
|
||||
0))
|
||||
(starting-debt . ,(->i (alist-ref 'startingDebt msg)
|
||||
0))
|
||||
(starting-otbs . ,(min (max (->number (alist-ref 'startingOtbs msg)
|
||||
2)
|
||||
0)
|
||||
8))
|
||||
(trade . ,(or (alist-ref 'trade msg) #t)))))
|
||||
(player (add-player-to-game game
|
||||
color
|
||||
@@ -1300,7 +1375,7 @@
|
||||
(session-set! (sid) 'game-id (game-id game)))
|
||||
(*game* game)
|
||||
(*player* player)
|
||||
(set-startup-otbs game player 2)
|
||||
(set-startup-otbs game player (alist-ref 'starting-otbs (game-settings game)))
|
||||
;; (set-startup-otbs game ai-player 2)
|
||||
;; (thread-start! (make-ai-push-receiver game ai-player))
|
||||
(create-start-response "new-game-started")))
|
||||
@@ -1322,11 +1397,12 @@
|
||||
(db-add-user-game (alist-ref 'id user) (game-id game))
|
||||
(*game* game)
|
||||
(*player* player)
|
||||
(set-startup-otbs game player 2)
|
||||
(set-startup-otbs game player (alist-ref 'starting-otbs (game-settings game)))
|
||||
(message-players! game player '() type: "update")
|
||||
(create-start-response "new-game-started")))
|
||||
((string=? type "join-as-existing")
|
||||
(let* ((id (alist-ref 'gameId msg))
|
||||
(let* ((id (or (alist-ref 'gameId msg)
|
||||
(session-ref (sid) 'game-id)))
|
||||
(user-id (session-ref (sid) 'user-id))
|
||||
(game (find-game id))
|
||||
(player (find (lambda (p) (equal? (player-user-id p) user-id))
|
||||
@@ -1357,6 +1433,42 @@
|
||||
(session-set! (sid) 'game-id #f)
|
||||
(session-set! (sid) 'user-id #f)
|
||||
(create-start-response "start-init"))
|
||||
((string=? type "ready-to-start")
|
||||
(safe-set! (player-ready-to-start (*player*)) (not (player-ready-to-start (*player*))))
|
||||
(message-players! (*game*) (*player*) '() type: "update")
|
||||
(create-ws-response (*player*) "update" '()))
|
||||
((string=? type "kick-player")
|
||||
(let ((kicked-player (find (lambda (p)
|
||||
(equal? (player-name p) (alist-ref 'name msg)))
|
||||
(game-players (*game*)))))
|
||||
(safe-set! (game-colors (*game*))
|
||||
(cons (player-color kicked-player) (game-colors (*game*))))
|
||||
(safe-set! (game-otbs (*game*))
|
||||
(append (game-otbs (*game*))
|
||||
(player-otbs kicked-player)))
|
||||
(safe-set! (game-players (*game*))
|
||||
(filter (lambda (p)
|
||||
(eq? p kicked-player))
|
||||
(game-players (*game*))))
|
||||
(db-remove-user-game (player-user-id kicked-player) (game-id (*game*))))
|
||||
(message-players! (*game*) (*player*) '() type: "update")
|
||||
(create-ws-response (*player*) "update" '()))
|
||||
((string=? type "leave-game")
|
||||
(safe-set! (game-colors (*game*))
|
||||
(cons (player-color (*player*)) (game-colors (*game*))))
|
||||
(safe-set! (game-otbs (*game*))
|
||||
(append (game-otbs (*game*))
|
||||
(player-otbs (*player*))))
|
||||
(safe-set! (game-players (*game*))
|
||||
(filter (lambda (p)
|
||||
(not (eq? p (*player*))))
|
||||
(game-players (*game*))))
|
||||
(when (not (null? (game-players (*game*))))
|
||||
(safe-set! (game-current-player (*game*)) (car (game-players (*game*)))))
|
||||
(db-remove-user-game (player-user-id (*player*)) (game-id (*game*)))
|
||||
(message-players! (*game*) (*player*) `((color . ,(symbol->string (player-color (*player*)))))
|
||||
type: "player-left-game")
|
||||
(create-ws-response (*player*) "left-game" '()))
|
||||
((string=? type "start-game")
|
||||
(safe-set! (game-state (*game*)) 'pre-turn)
|
||||
(db-update-game (game-id (*game*)) (symbol->string (game-state (*game*)))
|
||||
@@ -1439,19 +1551,19 @@
|
||||
exn
|
||||
(send-message
|
||||
(json->string
|
||||
`((exn . ,(with-output-to-string
|
||||
(lambda ()
|
||||
(print-call-chain)
|
||||
(print-error-message exn))))
|
||||
`((exn . ,(begin (log-error exn)
|
||||
(conc "Server error: " (with-output-to-string
|
||||
(lambda ()
|
||||
(print-error-message exn))))))
|
||||
(event . "error"))))
|
||||
(send-message
|
||||
(json->string
|
||||
(handle-exceptions
|
||||
exn
|
||||
`((exn . ,(with-output-to-string
|
||||
(lambda ()
|
||||
(print-call-chain)
|
||||
(print-error-message exn))))
|
||||
`((exn . ,(begin (log-error exn)
|
||||
(conc "Server error: " (with-output-to-string
|
||||
(lambda ()
|
||||
(print-error-message exn))))))
|
||||
(event . "error"))
|
||||
(session-game)
|
||||
(let* ((game (*game*))
|
||||
@@ -1491,18 +1603,18 @@
|
||||
exn
|
||||
(send-message
|
||||
(json->string
|
||||
`((exn . ,(with-output-to-string
|
||||
(lambda ()
|
||||
(print-call-chain)
|
||||
(print-error-message exn)))))))
|
||||
`((exn . ,(begin (log-error exn)
|
||||
(conc "Server error: " (with-output-to-string
|
||||
(lambda ()
|
||||
(print-error-message exn)))))))))
|
||||
(send-message
|
||||
(json->string
|
||||
(handle-exceptions
|
||||
exn
|
||||
`((exn . ,(with-output-to-string
|
||||
(lambda ()
|
||||
(print-call-chain)
|
||||
(print-error-message exn))))
|
||||
`((exn . ,(begin (log-error exn)
|
||||
(conc "Server error: " (with-output-to-string
|
||||
(lambda ()
|
||||
(print-error-message exn))))))
|
||||
(event . "error"))
|
||||
(create-ws-response (*player*)
|
||||
(alist-ref 'type msg)
|
||||
@@ -1939,7 +2051,7 @@
|
||||
(define (gains amount) (lambda (n) (+ n amount)))
|
||||
|
||||
(define (player-crop-rule player crop)
|
||||
(if (> (alist-ref crop (player-assets player)) 0) `(((tom ,crop))) '()))
|
||||
(if (> (alist-ref crop (player-assets player) eqv? 0) 0) `(((tom ,crop))) '()))
|
||||
|
||||
(define (aug4-action player)
|
||||
(when (not (already-harvested? 'wheat player))
|
||||
@@ -1969,6 +2081,7 @@
|
||||
((apr2 add-rule ?p ,(make-player-year-rule
|
||||
10 '((?p corn harvest-mult 2) (?p grain)))))
|
||||
((apr2 player-action ?p ,(lambda (p) (safe-set! (player-corn-doubled p) #t))))
|
||||
((apr2 money ?p ,(gains 5000)) (?p birthday))
|
||||
((apr3 money ?p ,(pays 500)))
|
||||
((apr4 money ?p ,(pays 1000)))
|
||||
((may1 money ?p ,(gains 500)))
|
||||
@@ -2045,7 +2158,8 @@
|
||||
,@(player-crop-rule player 'hay)
|
||||
,@(player-crop-rule player 'grain)
|
||||
,@(player-crop-rule player 'tractor)
|
||||
,@(player-crop-rule player 'harvester))
|
||||
,@(player-crop-rule player 'harvester)
|
||||
,@(player-crop-rule player 'birthday))
|
||||
`((,(list-ref *months* space) ?action tom ?value)))))
|
||||
(if a
|
||||
(begin (set! res (cons a res)) (loop (amb+)))
|
||||
@@ -2140,7 +2254,10 @@
|
||||
(let ((value (alist-ref '?value action)))
|
||||
(if (procedure? value)
|
||||
(value player)
|
||||
(apply (alist-ref (car value) *action-map*) player (cdr value)))))
|
||||
(let ((action-proc (alist-ref (car value) *action-map*)))
|
||||
(if (procedure? action-proc)
|
||||
(apply action-proc player (cdr value))
|
||||
(print (conc "unknown action value: " value)))))))
|
||||
((eq? a 'harvest-mult)
|
||||
(safe-set! (player-harvest-mult player)
|
||||
(* (player-harvest-mult player) (alist-ref '?value action))))
|
||||
@@ -2238,6 +2355,15 @@
|
||||
(define (gp i)
|
||||
(list-ref (game-players (first-game)) i))
|
||||
|
||||
(define (gn name)
|
||||
(find (lambda (p) (equal? (player-name p) name))
|
||||
(game-players (first-game))))
|
||||
|
||||
(define (gnb name)
|
||||
(let ((player (gn name)))
|
||||
(safe-set! (player-assets player)
|
||||
(alist-update 'birthday 1 (player-assets player)))))
|
||||
|
||||
(cond-expand
|
||||
(geiser
|
||||
'())
|
||||
@@ -2256,49 +2382,3 @@
|
||||
;; you can get $50 from operating expense
|
||||
|
||||
;; mark spaces
|
||||
|
||||
;; error:
|
||||
;; Call history:
|
||||
|
||||
;; farm.scm:714: mailbox#mailbox-send!
|
||||
;; type-errors.scm:119: make-error-type-message
|
||||
;; type-errors.scm:104: make-bad-argument-message
|
||||
;; type-errors.scm:106: make-type-name-message
|
||||
;; type-errors.scm:290: ->string
|
||||
;; type-errors.scm:291: conc
|
||||
;; type-errors.scm:103: string-append
|
||||
;; type-errors.scm:119: signal-type-error
|
||||
;; farm.scm:1125: k7172
|
||||
;; farm.scm:1125: g7176
|
||||
;; farm.scm:1127: with-output-to-string
|
||||
;; farm.scm:1129: print-call-chain <--
|
||||
|
||||
;; Error: (mailbox-send!) bad argument type - not a mailbox: ()
|
||||
|
||||
|
||||
;; error:
|
||||
;; Call history:
|
||||
|
||||
;; farm.scm:129: alist-ref
|
||||
;; farm.scm:1125: k7172
|
||||
;; farm.scm:1125: g7176
|
||||
;; farm.scm:1127: with-output-to-string
|
||||
;; farm.scm:1129: print-call-chain <--
|
||||
|
||||
;; Error: (assv) bad argument type: ridge-cows
|
||||
|
||||
;; proposed trade to wrong player
|
||||
;; accidentally clicking no for uncle bert
|
||||
;; farmers fate 2nd week of january
|
||||
;; error:
|
||||
;; Call history:
|
||||
|
||||
;; farm.scm:129: alist-ref
|
||||
;; farm.scm:1213: k7426
|
||||
;; farm.scm:1213: g7430
|
||||
;; farm.scm:1215: with-output-to-string
|
||||
;; farm.scm:1217: print-call-chain <--
|
||||
|
||||
;; Error: (assv) bad argument type: #<coops instance of `<game>'>
|
||||
|
||||
;; when getting trade the name is wrong
|
||||
|
||||
@@ -798,6 +798,8 @@ $trade-margin: 3rem;
|
||||
color: white; }
|
||||
|
||||
.alert-overlay-contents {
|
||||
max-height: 90vh;
|
||||
overflow: auto;
|
||||
background: $light-color;
|
||||
padding: 2rem;
|
||||
display: flex;
|
||||
|
||||
@@ -24,15 +24,28 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const webpack = require("webpack");
|
||||
const autoprefixer = require("autoprefixer");
|
||||
const CssUrlRelativePlugin = require('css-url-relative-plugin')
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
app: './src/main.jsx',
|
||||
},
|
||||
output: {
|
||||
filename: '[name].bundle.js',
|
||||
filename: './assets/[name].[contenthash].js',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
optimization: {
|
||||
runtimeChunk: 'single',
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
vendor: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: 'vendors',
|
||||
chunks: 'all',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
@@ -42,8 +55,8 @@ module.exports = {
|
||||
}),
|
||||
new FaviconsWebpackPlugin('./assets/img/tractor.svg'),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
filename: './assets/[name].[contenthash].css',
|
||||
chunkFilename: './assets/[id].[contenthash].css',
|
||||
}),
|
||||
new CopyPlugin([
|
||||
{ from: './src/server/farm.scm', to: './[name].[ext]' },
|
||||
@@ -57,6 +70,7 @@ module.exports = {
|
||||
]
|
||||
}
|
||||
}),
|
||||
new CssUrlRelativePlugin()
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
@@ -71,11 +85,19 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
},
|
||||
// {
|
||||
// test: /mars-texture.png$/,
|
||||
// loader: 'file-loader',
|
||||
// options: {
|
||||
// name: './assets/img/[name].[contenthash].[ext]',
|
||||
// },
|
||||
// },
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf|svg|png|gif)$/,
|
||||
use: [
|
||||
'file-loader',
|
||||
],
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: './assets/img/[name].[contenthash].[ext]',
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.s[ac]ss$/i,
|
||||
|
||||
Reference in New Issue
Block a user