Using sqlite database, mt proctor animation.
2
Makefile
@@ -35,7 +35,7 @@ install:
|
|||||||
npm install
|
npm install
|
||||||
|
|
||||||
interactive:
|
interactive:
|
||||||
cd dist/ && csi -include-path $(assets) -s farm.scm
|
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
|
||||||
cd src/server/ && csc -include-path ../../$(assets) -O3 farm.scm
|
cd src/server/ && csc -include-path ../../$(assets) -O3 farm.scm
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
"20 Cows on Peridier Ridge"))))
|
"20 Cows on Peridier Ridge"))))
|
||||||
|
|
||||||
(define *ff-text*
|
(define *ff-text*
|
||||||
'(((p "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 "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 "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 "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.")))
|
((p "Kept back some of your cows and Proxima B steak goes viral.") (p (b "COLLECT $2,000 if you have cows.")))
|
||||||
|
|||||||
BIN
assets/img/volcano.gif
Normal file
|
After Width: | Height: | Size: 6.5 MiB |
73
assets/img/volcano.svg
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?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 83.521004 90"
|
||||||
|
enable-background="new 0 0 100 100"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg4827"
|
||||||
|
sodipodi:docname="volcano.svg"
|
||||||
|
width="83.521004"
|
||||||
|
height="90"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
|
||||||
|
id="metadata4833"><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="defs4831" /><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="namedview4829"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="16.931965"
|
||||||
|
inkscape:cx="34.840436"
|
||||||
|
inkscape:cy="58.282217"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer2" /><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="background"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 22.724,90 h 3.742 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 h -3.742 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 z"
|
||||||
|
id="path4848"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 31.709,48.246 c -0.5,0 -0.92,0.373 -0.991,0.868 C 26.776,76.3 7.844,86.928 5.8,88 H 1 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 17.541 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 H 9.625 C 15.767,83.846 29.057,72.489 32.57,50.247 H 46.913 C 50.775,72.775 66.307,83.893 73.711,88 H 63.602 C 55.695,83.379 50.214,73.507 50.159,73.407 c -0.267,-0.485 -0.875,-0.662 -1.357,-0.396 -0.484,0.266 -0.662,0.873 -0.396,1.357 0.21,0.383 4.67,8.425 11.601,13.632 H 33.441 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 49.08 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.553 -0.447,-1 -1,-1 H 78.222 C 76.161,87.159 53.146,77.158 48.752,49.104 c -0.077,-0.49 -0.493,-0.858 -0.99,-0.858"
|
||||||
|
id="path4821"
|
||||||
|
inkscape:connector-curvature="0" /></g><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="smoke"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 29.271,25.283 c 0.179,0.522 -0.101,1.091 -0.623,1.27 -0.107,0.037 -0.216,0.054 -0.323,0.054 -0.416,0 -0.804,-0.262 -0.946,-0.677 -0.976,-2.858 0.208,-6.044 2.816,-7.576 2.525,-1.483 5.727,-1.065 7.784,1.015 0.389,0.393 0.385,1.026 -0.008,1.414 -0.393,0.389 -1.026,0.385 -1.414,-0.008 -1.414,-1.43 -3.614,-1.716 -5.349,-0.697 -1.793,1.053 -2.607,3.242 -1.937,5.205 z"
|
||||||
|
id="path4856"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 59.002,9.435 c 4.279,0.188 8.044,3.055 9.37,7.136 0.137,0.422 0.529,0.691 0.951,0.691 0.102,0 0.207,-0.016 0.309,-0.049 0.525,-0.171 0.813,-0.735 0.642,-1.26 C 68.691,11.083 64.197,7.661 59.09,7.437 58.553,7.435 58.071,7.84 58.047,8.392 58.023,8.944 58.45,9.41 59.002,9.435 Z"
|
||||||
|
id="path4854"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 15.571,32.367 h 0.85 c 0.47,2.492 2.663,4.383 5.29,4.383 h 5.372 c 2.044,0 3.708,1.663 3.708,3.708 v 4.135 h 2 v -4.135 c 0,-3.147 -2.561,-5.708 -5.708,-5.708 h -5.372 c -1.865,0 -3.383,-1.518 -3.383,-3.383 0,-0.552 -0.448,-1 -1,-1 h -1.757 c -3.271,0 -5.933,-2.662 -5.933,-5.933 0,-3.271 2.662,-5.933 5.933,-5.933 h 3.212 c 0.552,0 1,-0.448 1,-1 v -1.073 c 0,-3.677 2.992,-6.668 6.668,-6.668 0.552,0 1,-0.448 1,-1 V 8.377 C 27.452,4.861 30.313,2 33.829,2 c 3.516,0 6.377,2.861 6.377,6.377 V 8.76 c 0,0.552 0.448,1 1,1 h 3.454 c 2.576,0 4.671,2.095 4.671,4.67 0,0.552 0.448,1 1,1 h 3.058 c 5.435,0 9.856,4.421 9.856,9.855 0,0.552 0.448,1 1,1 h 2.791 c 1.905,0 3.455,1.55 3.455,3.456 0,1.906 -1.55,3.455 -3.455,3.455 H 52.499 c -3.147,0 -5.708,2.561 -5.708,5.708 v 6.034 h 2 v -6.034 c 0,-2.044 1.664,-3.708 3.708,-3.708 h 14.536 c 3.008,0 5.455,-2.447 5.455,-5.455 0,-3.008 -2.447,-5.456 -5.455,-5.456 H 65.202 C 64.693,18.214 59.589,13.43 53.388,13.43 H 51.255 C 50.771,10.225 47.997,7.76 44.659,7.76 H 42.183 C 41.866,3.428 38.24,0 33.829,0 29.398,0 25.76,3.457 25.471,7.815 21.152,8.304 17.784,11.98 17.784,16.428 v 0.073 h -2.213 c -4.375,0 -7.933,3.559 -7.933,7.933 0,4.374 3.559,7.933 7.933,7.933 z"
|
||||||
|
id="path4852"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="M 43.531,44.77 V 30.819 c 0,-0.552 -0.448,-1 -1,-1 v 0 c -0.552,0 -1,0.448 -1,1 V 44.77 Z"
|
||||||
|
id="path4850"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 36.754563,48.297963 V 38.85399"
|
||||||
|
id="path4844"
|
||||||
|
inkscape:connector-curvature="0" /></g></svg>
|
||||||
|
After Width: | Height: | Size: 5.1 KiB |
80
assets/img/volcano0.svg
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?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 83.521004 90"
|
||||||
|
enable-background="new 0 0 100 100"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg4827"
|
||||||
|
sodipodi:docname="volcano0.svg"
|
||||||
|
width="83.521004"
|
||||||
|
height="90"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
inkscape:export-filename="/home/tjhintz/tmp/volcano/volcano0.png"
|
||||||
|
inkscape:export-xdpi="106.654"
|
||||||
|
inkscape:export-ydpi="106.654"><metadata
|
||||||
|
id="metadata4833"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs4831" /><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="namedview4829"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="11.972707"
|
||||||
|
inkscape:cx="3.3491555"
|
||||||
|
inkscape:cy="44.177135"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer2" /><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="background"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 22.724,90 h 3.742 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 h -3.742 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 z"
|
||||||
|
id="path4848"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 31.709,48.246 c -0.5,0 -0.92,0.373 -0.991,0.868 C 26.776,76.3 7.844,86.928 5.8,88 H 1 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 17.541 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 H 9.625 C 15.767,83.846 29.057,72.489 32.57,50.247 H 46.913 C 50.775,72.775 66.307,83.893 73.711,88 H 63.602 C 55.695,83.379 50.214,73.507 50.159,73.407 c -0.267,-0.485 -0.875,-0.662 -1.357,-0.396 -0.484,0.266 -0.662,0.873 -0.396,1.357 0.21,0.383 4.67,8.425 11.601,13.632 H 33.441 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 49.08 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.553 -0.447,-1 -1,-1 H 78.222 C 76.161,87.159 53.146,77.158 48.752,49.104 c -0.077,-0.49 -0.493,-0.858 -0.99,-0.858"
|
||||||
|
id="path4821"
|
||||||
|
inkscape:connector-curvature="0" /></g><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="smoke"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 38.275981,46.275652 c 0.0179,0.0522 -0.0101,0.1091 -0.0623,0.127 -0.0107,0.0037 -0.0216,0.0054 -0.0323,0.0054 -0.0416,0 -0.0804,-0.0262 -0.0946,-0.0677 -0.0976,-0.2858 0.0208,-0.6044 0.2816,-0.7576 0.2525,-0.1483 0.5727,-0.1065 0.7784,0.1015 0.0389,0.0393 0.0385,0.1026 -8e-4,0.1414 -0.0393,0.0389 -0.1026,0.0385 -0.1414,-8e-4 -0.1414,-0.143 -0.3614,-0.1716 -0.5349,-0.0697 -0.1793,0.1053 -0.2607,0.3242 -0.1937,0.5205 z"
|
||||||
|
id="path4856"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="stroke-width:0.1" /><path
|
||||||
|
d="m 41.249081,44.690852 c 0.4279,0.0188 0.8044,0.3055 0.937,0.7136 0.0137,0.0422 0.0529,0.0691 0.0951,0.0691 0.0102,0 0.0207,-0.0016 0.0309,-0.0049 0.0525,-0.0171 0.0813,-0.0735 0.0642,-0.126 -0.1583,-0.487 -0.6077,-0.8292 -1.1184,-0.8516 -0.0537,-2e-4 -0.1019,0.0403 -0.1043,0.0955 -0.0024,0.0552 0.0403,0.1018 0.0955,0.1043 z"
|
||||||
|
id="path4854"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="stroke-width:0.1" /><path
|
||||||
|
d="m 36.905981,46.984052 h 0.085 c 0.047,0.2492 0.2663,0.4383 0.529,0.4383 h 0.5372 c 0.2044,0 0.3708,0.1663 0.3708,0.3708 v 0.4135 h 0.2 v -0.4135 c 0,-0.3147 -0.2561,-0.5708 -0.5708,-0.5708 h -0.5372 c -0.1865,0 -0.3383,-0.1518 -0.3383,-0.3383 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 h -0.1757 c -0.3271,0 -0.5933,-0.2662 -0.5933,-0.5933 0,-0.3271 0.2662,-0.5933 0.5933,-0.5933 h 0.3212 c 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.1073 c 0,-0.3677 0.2992,-0.6668 0.6668,-0.6668 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.0383 c 1e-4,-0.3516 0.2862,-0.6377 0.6378,-0.6377 0.3516,0 0.6377,0.2861 0.6377,0.6377 v 0.0383 c 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3454 c 0.2576,0 0.4671,0.2095 0.4671,0.467 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3058 c 0.5435,0 0.9856,0.4421 0.9856,0.9855 0,0.0552 0.0448,0.1 0.1,0.1 h 0.2791 c 0.1905,0 0.3455,0.155 0.3455,0.3456 0,0.1906 -0.155,0.3455 -0.3455,0.3455 h -1.4537 c -0.3147,0 -0.5708,0.2561 -0.5708,0.5708 v 0.6034 h 0.2 v -0.6034 c 0,-0.2044 0.1664,-0.3708 0.3708,-0.3708 h 1.4536 c 0.3008,0 0.5455,-0.2447 0.5455,-0.5455 0,-0.3008 -0.2447,-0.5456 -0.5455,-0.5456 h -0.1833 c -0.0509,-0.6071 -0.5613,-1.0855 -1.1814,-1.0855 h -0.2133 c -0.0484,-0.3205 -0.3258,-0.567 -0.6596,-0.567 h -0.2476 c -0.0317,-0.4332 -0.3943,-0.776 -0.8354,-0.776 -0.4431,0 -0.8069,0.3457 -0.8358,0.7815 -0.4319,0.0489 -0.7687,0.4165 -0.7687,0.8613 v 0.0073 h -0.2213 c -0.4375,0 -0.7933,0.3559 -0.7933,0.7933 0,0.4374 0.3559,0.7933 0.7933,0.7933 z"
|
||||||
|
id="path4852"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="stroke-width:0.1" /><path
|
||||||
|
d="m 39.701981,48.224352 v -1.3951 c 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 v 0 c -0.0552,0 -0.1,0.0448 -0.1,0.1 v 1.3951 z"
|
||||||
|
id="path4850"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="stroke-width:0.1" /><path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 39.024337,48.577149 V 47.632751"
|
||||||
|
id="path4844"
|
||||||
|
inkscape:connector-curvature="0" /></g></svg>
|
||||||
|
After Width: | Height: | Size: 5.8 KiB |
82
assets/img/volcano1.svg
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?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 83.521004 90"
|
||||||
|
enable-background="new 0 0 100 100"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg4827"
|
||||||
|
sodipodi:docname="volcano1.svg"
|
||||||
|
width="83.521004"
|
||||||
|
height="90"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
inkscape:export-filename="/home/tjhintz/tmp/volcano/volcano1.png"
|
||||||
|
inkscape:export-xdpi="106.654"
|
||||||
|
inkscape:export-ydpi="106.654"><metadata
|
||||||
|
id="metadata4833"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs4831" /><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="namedview4829"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="16"
|
||||||
|
inkscape:cx="19.364384"
|
||||||
|
inkscape:cy="35.768813"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer2" /><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="background"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 22.724,90 h 3.742 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 h -3.742 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 z"
|
||||||
|
id="path4848"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 31.709,48.246 c -0.5,0 -0.92,0.373 -0.991,0.868 C 26.776,76.3 7.844,86.928 5.8,88 H 1 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 17.541 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 H 9.625 C 15.767,83.846 29.057,72.489 32.57,50.247 H 46.913 C 50.775,72.775 66.307,83.893 73.711,88 H 63.602 C 55.695,83.379 50.214,73.507 50.159,73.407 c -0.267,-0.485 -0.875,-0.662 -1.357,-0.396 -0.484,0.266 -0.662,0.873 -0.396,1.357 0.21,0.383 4.67,8.425 11.601,13.632 H 33.441 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 49.08 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.553 -0.447,-1 -1,-1 H 78.222 C 76.161,87.159 53.146,77.158 48.752,49.104 c -0.077,-0.49 -0.493,-0.858 -0.99,-0.858"
|
||||||
|
id="path4821"
|
||||||
|
inkscape:connector-curvature="0" /></g><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="smoke"
|
||||||
|
style="display:inline"><g
|
||||||
|
id="g4911"
|
||||||
|
transform="matrix(2,0,0,2,-39.355281,-48.923119)"><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4856"
|
||||||
|
d="m 38.275981,46.275652 c 0.0179,0.0522 -0.0101,0.1091 -0.0623,0.127 -0.0107,0.0037 -0.0216,0.0054 -0.0323,0.0054 -0.0416,0 -0.0804,-0.0262 -0.0946,-0.0677 -0.0976,-0.2858 0.0208,-0.6044 0.2816,-0.7576 0.2525,-0.1483 0.5727,-0.1065 0.7784,0.1015 0.0389,0.0393 0.0385,0.1026 -8e-4,0.1414 -0.0393,0.0389 -0.1026,0.0385 -0.1414,-8e-4 -0.1414,-0.143 -0.3614,-0.1716 -0.5349,-0.0697 -0.1793,0.1053 -0.2607,0.3242 -0.1937,0.5205 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4854"
|
||||||
|
d="m 41.249081,44.690852 c 0.4279,0.0188 0.8044,0.3055 0.937,0.7136 0.0137,0.0422 0.0529,0.0691 0.0951,0.0691 0.0102,0 0.0207,-0.0016 0.0309,-0.0049 0.0525,-0.0171 0.0813,-0.0735 0.0642,-0.126 -0.1583,-0.487 -0.6077,-0.8292 -1.1184,-0.8516 -0.0537,-2e-4 -0.1019,0.0403 -0.1043,0.0955 -0.0024,0.0552 0.0403,0.1018 0.0955,0.1043 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4852"
|
||||||
|
d="m 36.905981,46.984052 h 0.085 c 0.047,0.2492 0.2663,0.4383 0.529,0.4383 h 0.5372 c 0.2044,0 0.3708,0.1663 0.3708,0.3708 v 0.4135 h 0.2 v -0.4135 c 0,-0.3147 -0.2561,-0.5708 -0.5708,-0.5708 h -0.5372 c -0.1865,0 -0.3383,-0.1518 -0.3383,-0.3383 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 h -0.1757 c -0.3271,0 -0.5933,-0.2662 -0.5933,-0.5933 0,-0.3271 0.2662,-0.5933 0.5933,-0.5933 h 0.3212 c 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.1073 c 0,-0.3677 0.2992,-0.6668 0.6668,-0.6668 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.0383 c 1e-4,-0.3516 0.2862,-0.6377 0.6378,-0.6377 0.3516,0 0.6377,0.2861 0.6377,0.6377 v 0.0383 c 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3454 c 0.2576,0 0.4671,0.2095 0.4671,0.467 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3058 c 0.5435,0 0.9856,0.4421 0.9856,0.9855 0,0.0552 0.0448,0.1 0.1,0.1 h 0.2791 c 0.1905,0 0.3455,0.155 0.3455,0.3456 0,0.1906 -0.155,0.3455 -0.3455,0.3455 h -1.4537 c -0.3147,0 -0.5708,0.2561 -0.5708,0.5708 v 0.6034 h 0.2 v -0.6034 c 0,-0.2044 0.1664,-0.3708 0.3708,-0.3708 h 1.4536 c 0.3008,0 0.5455,-0.2447 0.5455,-0.5455 0,-0.3008 -0.2447,-0.5456 -0.5455,-0.5456 h -0.1833 c -0.0509,-0.6071 -0.5613,-1.0855 -1.1814,-1.0855 h -0.2133 c -0.0484,-0.3205 -0.3258,-0.567 -0.6596,-0.567 h -0.2476 c -0.0317,-0.4332 -0.3943,-0.776 -0.8354,-0.776 -0.4431,0 -0.8069,0.3457 -0.8358,0.7815 -0.4319,0.0489 -0.7687,0.4165 -0.7687,0.8613 v 0.0073 h -0.2213 c -0.4375,0 -0.7933,0.3559 -0.7933,0.7933 0,0.4374 0.3559,0.7933 0.7933,0.7933 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4850"
|
||||||
|
d="m 39.701981,48.224352 v -1.3951 c 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 v 0 c -0.0552,0 -0.1,0.0448 -0.1,0.1 v 1.3951 z" /><path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4844"
|
||||||
|
d="M 39.024337,48.577149 V 47.632751"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 5.9 KiB |
BIN
assets/img/volcano2.gif
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
82
assets/img/volcano2.svg
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?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 83.521004 90"
|
||||||
|
enable-background="new 0 0 100 100"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg4827"
|
||||||
|
sodipodi:docname="volcano2.svg"
|
||||||
|
width="83.521004"
|
||||||
|
height="90"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
inkscape:export-filename="/home/tjhintz/tmp/volcano/volcano2.png"
|
||||||
|
inkscape:export-xdpi="106.654"
|
||||||
|
inkscape:export-ydpi="106.654"><metadata
|
||||||
|
id="metadata4833"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs4831" /><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="namedview4829"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="11.313709"
|
||||||
|
inkscape:cx="-8.2897213"
|
||||||
|
inkscape:cy="46.522973"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer2" /><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="background"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 22.724,90 h 3.742 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 h -3.742 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 z"
|
||||||
|
id="path4848"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 31.709,48.246 c -0.5,0 -0.92,0.373 -0.991,0.868 C 26.776,76.3 7.844,86.928 5.8,88 H 1 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 17.541 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 H 9.625 C 15.767,83.846 29.057,72.489 32.57,50.247 H 46.913 C 50.775,72.775 66.307,83.893 73.711,88 H 63.602 C 55.695,83.379 50.214,73.507 50.159,73.407 c -0.267,-0.485 -0.875,-0.662 -1.357,-0.396 -0.484,0.266 -0.662,0.873 -0.396,1.357 0.21,0.383 4.67,8.425 11.601,13.632 H 33.441 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 49.08 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.553 -0.447,-1 -1,-1 H 78.222 C 76.161,87.159 53.146,77.158 48.752,49.104 c -0.077,-0.49 -0.493,-0.858 -0.99,-0.858"
|
||||||
|
id="path4821"
|
||||||
|
inkscape:connector-curvature="0" /></g><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="smoke"
|
||||||
|
style="display:inline"><g
|
||||||
|
id="g4911"
|
||||||
|
transform="matrix(4,0,0,4,-118.06584,-146.02873)"><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4856"
|
||||||
|
d="m 38.275981,46.275652 c 0.0179,0.0522 -0.0101,0.1091 -0.0623,0.127 -0.0107,0.0037 -0.0216,0.0054 -0.0323,0.0054 -0.0416,0 -0.0804,-0.0262 -0.0946,-0.0677 -0.0976,-0.2858 0.0208,-0.6044 0.2816,-0.7576 0.2525,-0.1483 0.5727,-0.1065 0.7784,0.1015 0.0389,0.0393 0.0385,0.1026 -8e-4,0.1414 -0.0393,0.0389 -0.1026,0.0385 -0.1414,-8e-4 -0.1414,-0.143 -0.3614,-0.1716 -0.5349,-0.0697 -0.1793,0.1053 -0.2607,0.3242 -0.1937,0.5205 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4854"
|
||||||
|
d="m 41.249081,44.690852 c 0.4279,0.0188 0.8044,0.3055 0.937,0.7136 0.0137,0.0422 0.0529,0.0691 0.0951,0.0691 0.0102,0 0.0207,-0.0016 0.0309,-0.0049 0.0525,-0.0171 0.0813,-0.0735 0.0642,-0.126 -0.1583,-0.487 -0.6077,-0.8292 -1.1184,-0.8516 -0.0537,-2e-4 -0.1019,0.0403 -0.1043,0.0955 -0.0024,0.0552 0.0403,0.1018 0.0955,0.1043 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4852"
|
||||||
|
d="m 36.905981,46.984052 h 0.085 c 0.047,0.2492 0.2663,0.4383 0.529,0.4383 h 0.5372 c 0.2044,0 0.3708,0.1663 0.3708,0.3708 v 0.4135 h 0.2 v -0.4135 c 0,-0.3147 -0.2561,-0.5708 -0.5708,-0.5708 h -0.5372 c -0.1865,0 -0.3383,-0.1518 -0.3383,-0.3383 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 h -0.1757 c -0.3271,0 -0.5933,-0.2662 -0.5933,-0.5933 0,-0.3271 0.2662,-0.5933 0.5933,-0.5933 h 0.3212 c 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.1073 c 0,-0.3677 0.2992,-0.6668 0.6668,-0.6668 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.0383 c 1e-4,-0.3516 0.2862,-0.6377 0.6378,-0.6377 0.3516,0 0.6377,0.2861 0.6377,0.6377 v 0.0383 c 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3454 c 0.2576,0 0.4671,0.2095 0.4671,0.467 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3058 c 0.5435,0 0.9856,0.4421 0.9856,0.9855 0,0.0552 0.0448,0.1 0.1,0.1 h 0.2791 c 0.1905,0 0.3455,0.155 0.3455,0.3456 0,0.1906 -0.155,0.3455 -0.3455,0.3455 h -1.4537 c -0.3147,0 -0.5708,0.2561 -0.5708,0.5708 v 0.6034 h 0.2 v -0.6034 c 0,-0.2044 0.1664,-0.3708 0.3708,-0.3708 h 1.4536 c 0.3008,0 0.5455,-0.2447 0.5455,-0.5455 0,-0.3008 -0.2447,-0.5456 -0.5455,-0.5456 h -0.1833 c -0.0509,-0.6071 -0.5613,-1.0855 -1.1814,-1.0855 h -0.2133 c -0.0484,-0.3205 -0.3258,-0.567 -0.6596,-0.567 h -0.2476 c -0.0317,-0.4332 -0.3943,-0.776 -0.8354,-0.776 -0.4431,0 -0.8069,0.3457 -0.8358,0.7815 -0.4319,0.0489 -0.7687,0.4165 -0.7687,0.8613 v 0.0073 h -0.2213 c -0.4375,0 -0.7933,0.3559 -0.7933,0.7933 0,0.4374 0.3559,0.7933 0.7933,0.7933 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4850"
|
||||||
|
d="m 39.701981,48.224352 v -1.3951 c 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 v 0 c -0.0552,0 -0.1,0.0448 -0.1,0.1 v 1.3951 z" /><path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4844"
|
||||||
|
d="M 39.024337,48.577149 V 47.632751"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 5.9 KiB |
82
assets/img/volcano3.svg
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?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 83.521004 90"
|
||||||
|
enable-background="new 0 0 100 100"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg4827"
|
||||||
|
sodipodi:docname="volcano3.svg"
|
||||||
|
width="83.521004"
|
||||||
|
height="90"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
inkscape:export-filename="/home/tjhintz/tmp/volcano/volcano3.png"
|
||||||
|
inkscape:export-xdpi="106.66666"
|
||||||
|
inkscape:export-ydpi="106.66666"><metadata
|
||||||
|
id="metadata4833"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs4831" /><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="namedview4829"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="8"
|
||||||
|
inkscape:cx="-43.021575"
|
||||||
|
inkscape:cy="60.241354"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer2" /><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="background"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 22.724,90 h 3.742 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 h -3.742 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 z"
|
||||||
|
id="path4848"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 31.709,48.246 c -0.5,0 -0.92,0.373 -0.991,0.868 C 26.776,76.3 7.844,86.928 5.8,88 H 1 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 17.541 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 H 9.625 C 15.767,83.846 29.057,72.489 32.57,50.247 H 46.913 C 50.775,72.775 66.307,83.893 73.711,88 H 63.602 C 55.695,83.379 50.214,73.507 50.159,73.407 c -0.267,-0.485 -0.875,-0.662 -1.357,-0.396 -0.484,0.266 -0.662,0.873 -0.396,1.357 0.21,0.383 4.67,8.425 11.601,13.632 H 33.441 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 49.08 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.553 -0.447,-1 -1,-1 H 78.222 C 76.161,87.159 53.146,77.158 48.752,49.104 c -0.077,-0.49 -0.493,-0.858 -0.99,-0.858"
|
||||||
|
id="path4821"
|
||||||
|
inkscape:connector-curvature="0" /></g><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="smoke"
|
||||||
|
style="display:inline"><g
|
||||||
|
id="g4911"
|
||||||
|
transform="matrix(8,0,0,8,-275.48696,-340.41183)"><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4856"
|
||||||
|
d="m 38.275981,46.275652 c 0.0179,0.0522 -0.0101,0.1091 -0.0623,0.127 -0.0107,0.0037 -0.0216,0.0054 -0.0323,0.0054 -0.0416,0 -0.0804,-0.0262 -0.0946,-0.0677 -0.0976,-0.2858 0.0208,-0.6044 0.2816,-0.7576 0.2525,-0.1483 0.5727,-0.1065 0.7784,0.1015 0.0389,0.0393 0.0385,0.1026 -8e-4,0.1414 -0.0393,0.0389 -0.1026,0.0385 -0.1414,-8e-4 -0.1414,-0.143 -0.3614,-0.1716 -0.5349,-0.0697 -0.1793,0.1053 -0.2607,0.3242 -0.1937,0.5205 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4854"
|
||||||
|
d="m 41.249081,44.690852 c 0.4279,0.0188 0.8044,0.3055 0.937,0.7136 0.0137,0.0422 0.0529,0.0691 0.0951,0.0691 0.0102,0 0.0207,-0.0016 0.0309,-0.0049 0.0525,-0.0171 0.0813,-0.0735 0.0642,-0.126 -0.1583,-0.487 -0.6077,-0.8292 -1.1184,-0.8516 -0.0537,-2e-4 -0.1019,0.0403 -0.1043,0.0955 -0.0024,0.0552 0.0403,0.1018 0.0955,0.1043 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4852"
|
||||||
|
d="m 36.905981,46.984052 h 0.085 c 0.047,0.2492 0.2663,0.4383 0.529,0.4383 h 0.5372 c 0.2044,0 0.3708,0.1663 0.3708,0.3708 v 0.4135 h 0.2 v -0.4135 c 0,-0.3147 -0.2561,-0.5708 -0.5708,-0.5708 h -0.5372 c -0.1865,0 -0.3383,-0.1518 -0.3383,-0.3383 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 h -0.1757 c -0.3271,0 -0.5933,-0.2662 -0.5933,-0.5933 0,-0.3271 0.2662,-0.5933 0.5933,-0.5933 h 0.3212 c 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.1073 c 0,-0.3677 0.2992,-0.6668 0.6668,-0.6668 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.0383 c 1e-4,-0.3516 0.2862,-0.6377 0.6378,-0.6377 0.3516,0 0.6377,0.2861 0.6377,0.6377 v 0.0383 c 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3454 c 0.2576,0 0.4671,0.2095 0.4671,0.467 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3058 c 0.5435,0 0.9856,0.4421 0.9856,0.9855 0,0.0552 0.0448,0.1 0.1,0.1 h 0.2791 c 0.1905,0 0.3455,0.155 0.3455,0.3456 0,0.1906 -0.155,0.3455 -0.3455,0.3455 h -1.4537 c -0.3147,0 -0.5708,0.2561 -0.5708,0.5708 v 0.6034 h 0.2 v -0.6034 c 0,-0.2044 0.1664,-0.3708 0.3708,-0.3708 h 1.4536 c 0.3008,0 0.5455,-0.2447 0.5455,-0.5455 0,-0.3008 -0.2447,-0.5456 -0.5455,-0.5456 h -0.1833 c -0.0509,-0.6071 -0.5613,-1.0855 -1.1814,-1.0855 h -0.2133 c -0.0484,-0.3205 -0.3258,-0.567 -0.6596,-0.567 h -0.2476 c -0.0317,-0.4332 -0.3943,-0.776 -0.8354,-0.776 -0.4431,0 -0.8069,0.3457 -0.8358,0.7815 -0.4319,0.0489 -0.7687,0.4165 -0.7687,0.8613 v 0.0073 h -0.2213 c -0.4375,0 -0.7933,0.3559 -0.7933,0.7933 0,0.4374 0.3559,0.7933 0.7933,0.7933 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4850"
|
||||||
|
d="m 39.701981,48.224352 v -1.3951 c 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 v 0 c -0.0552,0 -0.1,0.0448 -0.1,0.1 v 1.3951 z" /><path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4844"
|
||||||
|
d="M 39.024337,48.577149 V 47.632751"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 5.9 KiB |
82
assets/img/volcano4.svg
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?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 83.521004 90"
|
||||||
|
enable-background="new 0 0 100 100"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg4827"
|
||||||
|
sodipodi:docname="volcano4.svg"
|
||||||
|
width="83.521004"
|
||||||
|
height="90"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
inkscape:export-filename="/home/tjhintz/tmp/volcano/volcano4.png"
|
||||||
|
inkscape:export-xdpi="106.66666"
|
||||||
|
inkscape:export-ydpi="106.66666"><metadata
|
||||||
|
id="metadata4833"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs4831" /><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="namedview4829"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="8"
|
||||||
|
inkscape:cx="-14.5812"
|
||||||
|
inkscape:cy="44.273261"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer2" /><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="background"
|
||||||
|
style="display:inline"><path
|
||||||
|
d="m 22.724,90 h 3.742 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 h -3.742 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 z"
|
||||||
|
id="path4848"
|
||||||
|
inkscape:connector-curvature="0" /><path
|
||||||
|
d="m 31.709,48.246 c -0.5,0 -0.92,0.373 -0.991,0.868 C 26.776,76.3 7.844,86.928 5.8,88 H 1 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 17.541 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.552 -0.448,-1 -1,-1 H 9.625 C 15.767,83.846 29.057,72.489 32.57,50.247 H 46.913 C 50.775,72.775 66.307,83.893 73.711,88 H 63.602 C 55.695,83.379 50.214,73.507 50.159,73.407 c -0.267,-0.485 -0.875,-0.662 -1.357,-0.396 -0.484,0.266 -0.662,0.873 -0.396,1.357 0.21,0.383 4.67,8.425 11.601,13.632 H 33.441 c -0.552,0 -1,0.448 -1,1 v 0 c 0,0.552 0.448,1 1,1 h 49.08 c 0.552,0 1,-0.448 1,-1 v 0 c 0,-0.553 -0.447,-1 -1,-1 H 78.222 C 76.161,87.159 53.146,77.158 48.752,49.104 c -0.077,-0.49 -0.493,-0.858 -0.99,-0.858"
|
||||||
|
id="path4821"
|
||||||
|
inkscape:connector-curvature="0" /></g><g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="smoke"
|
||||||
|
style="display:inline"><g
|
||||||
|
id="g4911"
|
||||||
|
transform="matrix(9.9676375,0,0,9.9676375,-351.91862,-436.06862)"><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4856"
|
||||||
|
d="m 38.275981,46.275652 c 0.0179,0.0522 -0.0101,0.1091 -0.0623,0.127 -0.0107,0.0037 -0.0216,0.0054 -0.0323,0.0054 -0.0416,0 -0.0804,-0.0262 -0.0946,-0.0677 -0.0976,-0.2858 0.0208,-0.6044 0.2816,-0.7576 0.2525,-0.1483 0.5727,-0.1065 0.7784,0.1015 0.0389,0.0393 0.0385,0.1026 -8e-4,0.1414 -0.0393,0.0389 -0.1026,0.0385 -0.1414,-8e-4 -0.1414,-0.143 -0.3614,-0.1716 -0.5349,-0.0697 -0.1793,0.1053 -0.2607,0.3242 -0.1937,0.5205 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4854"
|
||||||
|
d="m 41.249081,44.690852 c 0.4279,0.0188 0.8044,0.3055 0.937,0.7136 0.0137,0.0422 0.0529,0.0691 0.0951,0.0691 0.0102,0 0.0207,-0.0016 0.0309,-0.0049 0.0525,-0.0171 0.0813,-0.0735 0.0642,-0.126 -0.1583,-0.487 -0.6077,-0.8292 -1.1184,-0.8516 -0.0537,-2e-4 -0.1019,0.0403 -0.1043,0.0955 -0.0024,0.0552 0.0403,0.1018 0.0955,0.1043 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4852"
|
||||||
|
d="m 36.905981,46.984052 h 0.085 c 0.047,0.2492 0.2663,0.4383 0.529,0.4383 h 0.5372 c 0.2044,0 0.3708,0.1663 0.3708,0.3708 v 0.4135 h 0.2 v -0.4135 c 0,-0.3147 -0.2561,-0.5708 -0.5708,-0.5708 h -0.5372 c -0.1865,0 -0.3383,-0.1518 -0.3383,-0.3383 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 h -0.1757 c -0.3271,0 -0.5933,-0.2662 -0.5933,-0.5933 0,-0.3271 0.2662,-0.5933 0.5933,-0.5933 h 0.3212 c 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.1073 c 0,-0.3677 0.2992,-0.6668 0.6668,-0.6668 0.0552,0 0.1,-0.0448 0.1,-0.1 v -0.0383 c 1e-4,-0.3516 0.2862,-0.6377 0.6378,-0.6377 0.3516,0 0.6377,0.2861 0.6377,0.6377 v 0.0383 c 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3454 c 0.2576,0 0.4671,0.2095 0.4671,0.467 0,0.0552 0.0448,0.1 0.1,0.1 h 0.3058 c 0.5435,0 0.9856,0.4421 0.9856,0.9855 0,0.0552 0.0448,0.1 0.1,0.1 h 0.2791 c 0.1905,0 0.3455,0.155 0.3455,0.3456 0,0.1906 -0.155,0.3455 -0.3455,0.3455 h -1.4537 c -0.3147,0 -0.5708,0.2561 -0.5708,0.5708 v 0.6034 h 0.2 v -0.6034 c 0,-0.2044 0.1664,-0.3708 0.3708,-0.3708 h 1.4536 c 0.3008,0 0.5455,-0.2447 0.5455,-0.5455 0,-0.3008 -0.2447,-0.5456 -0.5455,-0.5456 h -0.1833 c -0.0509,-0.6071 -0.5613,-1.0855 -1.1814,-1.0855 h -0.2133 c -0.0484,-0.3205 -0.3258,-0.567 -0.6596,-0.567 h -0.2476 c -0.0317,-0.4332 -0.3943,-0.776 -0.8354,-0.776 -0.4431,0 -0.8069,0.3457 -0.8358,0.7815 -0.4319,0.0489 -0.7687,0.4165 -0.7687,0.8613 v 0.0073 h -0.2213 c -0.4375,0 -0.7933,0.3559 -0.7933,0.7933 0,0.4374 0.3559,0.7933 0.7933,0.7933 z" /><path
|
||||||
|
style="stroke-width:0.1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4850"
|
||||||
|
d="m 39.701981,48.224352 v -1.3951 c 0,-0.0552 -0.0448,-0.1 -0.1,-0.1 v 0 c -0.0552,0 -0.1,0.0448 -0.1,0.1 v 1.3951 z" /><path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4844"
|
||||||
|
d="M 39.024337,48.577149 V 47.632751"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 5.9 KiB |
7
package-lock.json
generated
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "webpack-test",
|
"name": "farm",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
@@ -3462,6 +3462,11 @@
|
|||||||
"safe-buffer": "~5.1.1"
|
"safe-buffer": "~5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cookies-js": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookies-js/-/cookies-js-1.2.3.tgz",
|
||||||
|
"integrity": "sha1-AzFQSefFK+4/cxhqaRZ+qw3bLTE="
|
||||||
|
},
|
||||||
"copy-concurrently": {
|
"copy-concurrently": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
"@fortawesome/fontawesome-svg-core": "^1.2.26",
|
"@fortawesome/fontawesome-svg-core": "^1.2.26",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.12.0",
|
"@fortawesome/free-solid-svg-icons": "^5.12.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.8",
|
"@fortawesome/react-fontawesome": "^0.1.8",
|
||||||
|
"cookies-js": "^1.2.3",
|
||||||
"mobx": "^5.15.3",
|
"mobx": "^5.15.3",
|
||||||
"mobx-react": "^6.1.4",
|
"mobx-react": "^6.1.4",
|
||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ class Chrome extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className='flex-fullcenter'>
|
<div className='flex-fullcenter'>
|
||||||
<div className='background-heading'><h1>Alpha Centauri Farming</h1></div>
|
<div className='background-heading'><h1>Alpha Centauri Farming</h1></div>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
<Tractor spikes={this.props.spikes} className={this.props.tractorClass} />
|
<Tractor spikes={this.props.spikes} className={this.props.tractorClass} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -49,31 +49,43 @@ class App extends React.Component {
|
|||||||
case SCREENS.intro:
|
case SCREENS.intro:
|
||||||
view = (<Chrome spikes={true} tractorClass='intro'><Welcome /></Chrome>);
|
view = (<Chrome spikes={true} tractorClass='intro'><Welcome /></Chrome>);
|
||||||
break;
|
break;
|
||||||
case SCREENS.start:
|
case SCREENS.start:
|
||||||
view = (<Chrome><CreateOrJoin /></Chrome>);
|
view = (<Chrome><CreateOrJoin signOut={this.props.logout} /></Chrome>);
|
||||||
break;
|
break;
|
||||||
case SCREENS.newGame:
|
case SCREENS.newGame:
|
||||||
view = (<Chrome>
|
view = (<Chrome>
|
||||||
<div className='view-container'>
|
<div className='view-container'>
|
||||||
<NewGame colors={['green', 'red', 'blue', 'yellow', 'black']}
|
<NewGame colors={['green', 'red', 'blue', 'yellow', 'black']}
|
||||||
button={'Start'}
|
button={'Start'}
|
||||||
title={'New Game'}
|
title={'New Game'}
|
||||||
type={'new-game'}
|
type={'new-game'}
|
||||||
showGameName={true} />
|
showGameName={true}
|
||||||
|
createAccount={this.props.createAccount}
|
||||||
|
login={this.props.login}
|
||||||
|
errors={this.props.errors}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</Chrome>);
|
||||||
|
break;
|
||||||
|
case SCREENS.joinGame:
|
||||||
|
view = (
|
||||||
|
<Chrome>
|
||||||
|
<div className='view-container'>
|
||||||
|
<JoinGame createAccount={this.props.createAccount}
|
||||||
|
login={this.props.login}
|
||||||
|
errors={this.props.errors}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Chrome>);
|
</Chrome>);
|
||||||
break;
|
break;
|
||||||
case SCREENS.joinGame:
|
|
||||||
view = (<Chrome><div className='view-container'><JoinGame /></div></Chrome>);
|
|
||||||
break;
|
|
||||||
case SCREENS.play:
|
case SCREENS.play:
|
||||||
view = (<Board />);
|
view = (<Board />);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{view}
|
{view}
|
||||||
<div id={messagePanelId}><MessagePanel /></div>
|
<div id={messagePanelId}><MessagePanel /></div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
108
src/components/create-account/CreateAccount.jsx
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2020 Thomas Hintz
|
||||||
|
//
|
||||||
|
// This file is part of the Alpha Centauri Farming project.
|
||||||
|
//
|
||||||
|
// The Alpha Centauri Farming project is free software: you can
|
||||||
|
// redistribute it and/or modify it under the terms of the GNU General
|
||||||
|
// Public License as published by the Free Software Foundation, either
|
||||||
|
// version 3 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The Alpha Centauri Farming project is distributed in the hope that
|
||||||
|
// it will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||||
|
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE. See the GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Alpha Centauri Farming project. If not, see
|
||||||
|
// <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import React from 'react'
|
||||||
|
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||||
|
|
||||||
|
export default class CreateAccount extends React.Component {
|
||||||
|
state = {
|
||||||
|
username: '',
|
||||||
|
email: '',
|
||||||
|
password: '',
|
||||||
|
confirmPassword: '',
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
onChange = (e) => {
|
||||||
|
const target = e.target,
|
||||||
|
value = target.value,
|
||||||
|
name = target.name;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
[name]: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({ loading: true });
|
||||||
|
this.props.createAccount(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (this.state.loading && prevProps.errors !== this.props.errors) {
|
||||||
|
this.setState({ loading: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<GroupBox title="Create Account">
|
||||||
|
<form onSubmit={this.onSubmit}>
|
||||||
|
<Row>
|
||||||
|
<Col width="12">
|
||||||
|
<label>
|
||||||
|
Username
|
||||||
|
<input onChange={this.onChange} required name="username" type="text" />
|
||||||
|
</label>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col width="12">
|
||||||
|
<label>
|
||||||
|
Email (optional)
|
||||||
|
<input onChange={this.onChange} name="email" type="email" />
|
||||||
|
</label>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col width="12">
|
||||||
|
<label>
|
||||||
|
Password
|
||||||
|
<input onChange={this.onChange} required name="password" type="password" />
|
||||||
|
</label>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col width="12">
|
||||||
|
<label>
|
||||||
|
Confirm Password
|
||||||
|
<input onChange={this.onChange} required name="confirmPassword" type="password" />
|
||||||
|
</label>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col width="12">
|
||||||
|
{!this.state.loading ? (
|
||||||
|
<>
|
||||||
|
{this.props.errors.map((err, i) => (
|
||||||
|
<p key={i}>
|
||||||
|
Error: {err}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
<Button type="submit">Create Account</Button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<span>Creating Account...</span>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</form>
|
||||||
|
</GroupBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,21 +19,34 @@
|
|||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
|
||||||
|
import Cookies from 'cookies-js'
|
||||||
|
|
||||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||||
import { showNewGame, showJoinGame } from '../app/actions.js'
|
import { showNewGame, showJoinGame } from '../app/actions.js'
|
||||||
|
|
||||||
class CreateOrJoin extends React.Component {
|
class CreateOrJoin extends React.Component {
|
||||||
|
signOut = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.signOut();
|
||||||
|
Cookies.expire('awful-cookie');
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Button size='large' className='shadow' onClick={this.props.showNewGame}>
|
<Button size='large' className='shadow' onClick={this.props.showNewGame}>
|
||||||
New Game
|
New Game
|
||||||
</Button>
|
</Button>
|
||||||
{this.props.start.start.games.length > 0 ? (
|
{(this.props.start.start.games.length > 0) || (this.props.start.start.openGames.length > 0) ? (
|
||||||
<Button size='large' className='shadow' onClick={this.props.showJoinGame}>
|
<Button size='large' className='shadow' onClick={this.props.showJoinGame}>
|
||||||
Join Game
|
Join Game
|
||||||
</Button>
|
</Button>
|
||||||
) : (<Fragment />)}
|
) : (<Fragment />)}
|
||||||
|
{this.props.start.start.user ? (
|
||||||
|
<Button size='large' className='shadow sign-out-button' onClick={this.signOut}>
|
||||||
|
Sign Out
|
||||||
|
</Button>
|
||||||
|
) : (<></>)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import WheatImg from './../../../assets/img/wheat.svg'
|
|||||||
import TractorImg from './../../../assets/img/tractor-icon.svg'
|
import TractorImg from './../../../assets/img/tractor-icon.svg'
|
||||||
import TractorFullImg from './../../../assets/img/tractor-with-spikes.svg'
|
import TractorFullImg from './../../../assets/img/tractor-with-spikes.svg'
|
||||||
import HarvesterImg from './../../../assets/img/harvester.svg'
|
import HarvesterImg from './../../../assets/img/harvester.svg'
|
||||||
|
import VolcanoImg from './../../../assets/img/volcano2.gif'
|
||||||
|
|
||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
@@ -45,21 +46,21 @@ import { setSelectedCard, setMessagePanelSpace, setMPDims, movePlayer,
|
|||||||
setMovingSkip } from './actions.js'
|
setMovingSkip } from './actions.js'
|
||||||
import { buy, roll, endTurn, loan, trade, submitTradeAccept,
|
import { buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||||
submitTradeDeny, submitTradeCancel, audit,
|
submitTradeDeny, submitTradeCancel, audit,
|
||||||
buyUncleBert, skip, endAiTurn } from './interface.js'
|
buyUncleBert, skip, endAiTurn, startGame } from './interface.js'
|
||||||
|
|
||||||
function netWorth(player) {
|
function netWorth(player) {
|
||||||
return ((player.assets.hay + player.assets.grain) * 2000) +
|
return ((player.assets.hay + player.assets.grain) * 2000) +
|
||||||
(player.assets.fruit * 5000) +
|
(player.assets.fruit * 5000) +
|
||||||
(player.assets.cows * 500) +
|
(player.assets.cows * 500) +
|
||||||
((player.assets.harvester + player.assets.tractor) * 10000) +
|
((player.assets.harvester + player.assets.tractor) * 10000) +
|
||||||
player.displayCash - player.debt;
|
player.displayCash - player.debt;
|
||||||
}
|
}
|
||||||
|
|
||||||
function assetsValue(player) {
|
function assetsValue(player) {
|
||||||
return ((player.assets.hay + player.assets.grain) * 2000) +
|
return ((player.assets.hay + player.assets.grain) * 2000) +
|
||||||
(player.assets.fruit * 5000) +
|
(player.assets.fruit * 5000) +
|
||||||
(player.assets.cows * 500) +
|
(player.assets.cows * 500) +
|
||||||
((player.assets.harvester + player.assets.tractor) * 10000);
|
((player.assets.harvester + player.assets.tractor) * 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getElementValue(id) {
|
function getElementValue(id) {
|
||||||
@@ -464,20 +465,20 @@ class FarmsContainer extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<GroupBox title='Farms'>
|
<GroupBox title='Farms'>
|
||||||
<b>Ridges</b>:
|
<b>Ridges</b>:
|
||||||
{ridgeNames.map((ridge, idx) => (
|
{ridgeNames.map((ridge, idx) => (
|
||||||
<div key={idx} className={"farms-ridge player-" + ridges['ridge' + (idx + 1)]}>
|
<div key={idx} className={"farms-ridge player-" + ridges['ridge' + (idx + 1)]}>
|
||||||
<span>{ridge}</span>
|
<span>{ridge}</span>
|
||||||
<span className='num-cows'>{'(' + ((idx + 2) * 10) + ' cows)'}</span>
|
<span className='num-cows'>{'(' + ((idx + 2) * 10) + ' cows)'}</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<br />
|
<br />
|
||||||
{this.props.otherPlayers
|
{this.props.otherPlayers
|
||||||
.map(p => (
|
.map(p => (
|
||||||
<div key={p.player.name}>
|
<div key={p.player.name}>
|
||||||
<PlayerColorIcon color={p.player.color} />{'\u00A0'}
|
<PlayerColorIcon color={p.player.color} />{'\u00A0'}
|
||||||
<b>{p.player.name}</b> <PlayerResources player={p.player} />
|
<b>{p.player.name}</b> <PlayerResources player={p.player} />
|
||||||
<br /> <br />
|
<br /> <br />
|
||||||
</div>))}
|
</div>))}
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -521,11 +522,11 @@ const makeDefaultToTrade = () => {
|
|||||||
|
|
||||||
class TradeContainer2 extends React.Component {
|
class TradeContainer2 extends React.Component {
|
||||||
resources = [{ img: HayImg,
|
resources = [{ img: HayImg,
|
||||||
h: '120',
|
h: '120',
|
||||||
s: '100',
|
s: '100',
|
||||||
label: 'acres of Hay',
|
label: 'acres of Hay',
|
||||||
key: 'hay',
|
key: 'hay',
|
||||||
amount: 10
|
amount: 10
|
||||||
}, {
|
}, {
|
||||||
img: WheatImg,
|
img: WheatImg,
|
||||||
h: '41',
|
h: '41',
|
||||||
@@ -859,7 +860,7 @@ class CCBY extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
License Creative Commons <a href='https://creativecommons.org/licenses/by/3.0/us/legalcode'>CCBY</a>
|
License Creative Commons <a href={`https://creativecommons.org/licenses/by/${this.props.version ? this.props.version : 3}.0/us/legalcode`}>CCBY</a>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -880,6 +881,9 @@ class Misc extends React.Component {
|
|||||||
<li>
|
<li>
|
||||||
<img src={TractorFullImg} /> <img src={TractorImg} /> Copyright Nick Roach with modifications by Thomas Hintz - License <a href='GPL http://www.gnu.org/copyleft/gpl.html'>GPL</a>
|
<img src={TractorFullImg} /> <img src={TractorImg} /> Copyright Nick Roach with modifications by Thomas Hintz - License <a href='GPL http://www.gnu.org/copyleft/gpl.html'>GPL</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<img src={VolcanoImg} /> Copyright <a href="https://thenounproject.com/Maludk/">Laymik</a> - <CCBY />
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<img src={CornImg} /> <img src={FruitImg} /> Copyright <a href='https://madexmade.com/'>Made</a> - <CCBY />
|
<img src={CornImg} /> <img src={FruitImg} /> Copyright <a href='https://madexmade.com/'>Made</a> - <CCBY />
|
||||||
</li>
|
</li>
|
||||||
@@ -1090,6 +1094,7 @@ class Die extends React.Component {
|
|||||||
trigger = 0;
|
trigger = 0;
|
||||||
decayFactorPct = 0.4;
|
decayFactorPct = 0.4;
|
||||||
showScreenTimerId = false;
|
showScreenTimerId = false;
|
||||||
|
rollIndex = 0;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -1107,12 +1112,16 @@ class Die extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
roll() {
|
roll() {
|
||||||
let roll = random(6);
|
if (!this.props.rolls) {
|
||||||
while (roll === this.lastRoll) {
|
let roll = random(6);
|
||||||
roll = random(6);
|
while (roll === this.lastRoll) {
|
||||||
|
roll = random(6);
|
||||||
|
}
|
||||||
|
this.lastRoll = roll;
|
||||||
|
return roll;
|
||||||
|
} else {
|
||||||
|
return this.props.rolls[++this.rollIndex];
|
||||||
}
|
}
|
||||||
this.lastRoll = roll;
|
|
||||||
return roll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tick = () => {
|
tick = () => {
|
||||||
@@ -1272,6 +1281,7 @@ class Rolling extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<GroupBox title={this.props.name + ' is rolling!'}>
|
<GroupBox title={this.props.name + ' is rolling!'}>
|
||||||
<Die decay={true} num={this.props.num} ms={2000} roll={true}
|
<Die decay={true} num={this.props.num} ms={2000} roll={true}
|
||||||
|
rolls={this.props.rolls}
|
||||||
showScreen={this.props.showScreen}
|
showScreen={this.props.showScreen}
|
||||||
skip={this.props.skip}
|
skip={this.props.skip}
|
||||||
autoSkip={this.props.autoSkip}
|
autoSkip={this.props.autoSkip}
|
||||||
@@ -1354,6 +1364,7 @@ class Harvest extends React.Component {
|
|||||||
break;
|
break;
|
||||||
case 'roll':
|
case 'roll':
|
||||||
view = (<Die decay={true} num={this.props.rolled} ms={2000} roll={true}
|
view = (<Die decay={true} num={this.props.rolled} ms={2000} roll={true}
|
||||||
|
rolls={this.props.rolls}
|
||||||
showScreen={() => this.nextView('income')}
|
showScreen={() => this.nextView('income')}
|
||||||
skip={this.props.player.name === this.props.game.currentPlayer}
|
skip={this.props.player.name === this.props.game.currentPlayer}
|
||||||
autoSkip={this.props.autoSkip === 'die'}
|
autoSkip={this.props.autoSkip === 'die'}
|
||||||
@@ -1569,6 +1580,7 @@ class Action extends React.Component {
|
|||||||
break;
|
break;
|
||||||
case 'harvest':
|
case 'harvest':
|
||||||
view = (<Harvest rolled={this.props.ui.actionValue.rolled}
|
view = (<Harvest rolled={this.props.ui.actionValue.rolled}
|
||||||
|
rolls={this.props.ui.actionValue.rolls}
|
||||||
player={this.props.player}
|
player={this.props.player}
|
||||||
currentPlayer={currentPlayer}
|
currentPlayer={currentPlayer}
|
||||||
harvestMult={this.props.ui.actionValue.harvestMult}
|
harvestMult={this.props.ui.actionValue.harvestMult}
|
||||||
@@ -1635,6 +1647,7 @@ class Action extends React.Component {
|
|||||||
(this.props.ui.actionValue.to < this.props.ui.actionValue.from ?
|
(this.props.ui.actionValue.to < this.props.ui.actionValue.from ?
|
||||||
this.props.ui.actionValue.from - 49 : this.props.ui.actionValue.from);
|
this.props.ui.actionValue.from - 49 : this.props.ui.actionValue.from);
|
||||||
view = (<Rolling num={roll}
|
view = (<Rolling num={roll}
|
||||||
|
rolls={this.props.ui.actionValue.rolls}
|
||||||
name={this.props.game.currentPlayer}
|
name={this.props.game.currentPlayer}
|
||||||
showScreen={(this.props.player.name === this.props.game.currentPlayer ||
|
showScreen={(this.props.player.name === this.props.game.currentPlayer ||
|
||||||
currentPlayer.ai)
|
currentPlayer.ai)
|
||||||
@@ -1764,14 +1777,16 @@ class AlertOverlay extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={'alert-overlay' + (this.state.visible ? '' : ' hidden') }>
|
<div className={'alert-overlay' + (this.state.visible ? '' : ' hidden') }>
|
||||||
<div onClick={this.hide} className='alert-overlay-hide'>
|
{!this.props.preventHiding ? (
|
||||||
<FontAwesomeIcon icon={faTimes} />
|
<div onClick={this.hide} className='alert-overlay-hide'>
|
||||||
</div>
|
<FontAwesomeIcon icon={faTimes} />
|
||||||
|
</div>
|
||||||
|
) : (<></>)}
|
||||||
<div className='alert-overlay-contents'>
|
<div className='alert-overlay-contents'>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
<br />
|
<br />
|
||||||
<Button onClick={this.buttonClick}>{this.props.buttonText}</Button>
|
<Button onClick={this.buttonClick}>{this.props.buttonText}</Button>
|
||||||
<a onClick={this.hide}>close</a>
|
{!this.props.preventHiding ? (<a onClick={this.hide}>close</a>) : (<></>)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -2015,6 +2030,30 @@ class BoardApp extends React.Component {
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
</AlertOverlay>
|
</AlertOverlay>
|
||||||
);
|
);
|
||||||
|
} else if (alert && alert.type === ALERTS.preGame) {
|
||||||
|
alertOverlay = (
|
||||||
|
<AlertOverlay visible={true}
|
||||||
|
id={alert.id}
|
||||||
|
alertHandled={this.props.alertHandled}
|
||||||
|
buttonText='Start Game'
|
||||||
|
hideHandler={() => 'nothing'}
|
||||||
|
preventHiding={true}
|
||||||
|
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>
|
||||||
|
</AlertOverlay>
|
||||||
|
);
|
||||||
} else if (alert && alert.type === ALERTS.proposedTrade) {
|
} else if (alert && alert.type === ALERTS.proposedTrade) {
|
||||||
alertOverlay = (
|
alertOverlay = (
|
||||||
<AlertOverlay visible={true}
|
<AlertOverlay visible={true}
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ import { itemCard, fateCard } from 'game.js'
|
|||||||
|
|
||||||
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
|
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||||
submitTradeDeny, submitTradeCancel, audit, handleMessage,
|
submitTradeDeny, submitTradeCancel, audit, handleMessage,
|
||||||
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn }
|
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
|
||||||
|
startGame }
|
||||||
|
|
||||||
let store;
|
let store;
|
||||||
let movingTimer = 0;
|
let movingTimer = 0;
|
||||||
@@ -44,6 +45,13 @@ function handleMessage(evt) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
batch(() => {
|
batch(() => {
|
||||||
|
if (data.game.state === GAME_STATES.preGame) {
|
||||||
|
store.dispatch(alert(ALERTS.preGame, '', 'pre-game'));
|
||||||
|
}
|
||||||
|
if (store.getState().farm.game.state === GAME_STATES.preGame &&
|
||||||
|
data.game.state === GAME_STATES.preTurn) {
|
||||||
|
store.dispatch(alertHandled('pre-game'));
|
||||||
|
}
|
||||||
if (data.player.state === GAME_STATES.preTurn &&
|
if (data.player.state === GAME_STATES.preTurn &&
|
||||||
data.game.otherPlayers.length > 0 &&
|
data.game.otherPlayers.length > 0 &&
|
||||||
store.getState().farm.player.state !== GAME_STATES.preTurn) {
|
store.getState().farm.player.state !== GAME_STATES.preTurn) {
|
||||||
@@ -186,6 +194,10 @@ function skip(component) {
|
|||||||
sendCommand({ type: 'skip', component });
|
sendCommand({ type: 'skip', component });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startGame() {
|
||||||
|
sendCommand({ type: 'start-game' });
|
||||||
|
}
|
||||||
|
|
||||||
// TODO share with Board.jsx
|
// TODO share with Board.jsx
|
||||||
// http://stackoverflow.com/questions/149055
|
// http://stackoverflow.com/questions/149055
|
||||||
function formatMoney(n) {
|
function formatMoney(n) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
|||||||
|
|
||||||
import { startOrJoinGame } from '../start/actions.js'
|
import { startOrJoinGame } from '../start/actions.js'
|
||||||
import { start } from '../app/actions.js'
|
import { start } from '../app/actions.js'
|
||||||
|
import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccount.jsx';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faArrowCircleLeft } from '@fortawesome/free-solid-svg-icons'
|
import { faArrowCircleLeft } from '@fortawesome/free-solid-svg-icons'
|
||||||
@@ -36,14 +37,15 @@ class JoinGame extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
screen: JoinGameScreens.list,
|
screen: JoinGameScreens.list,
|
||||||
game: null
|
game: null,
|
||||||
|
showSignIn: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickGame = game => {
|
handleClickGame = game => {
|
||||||
this.setState({ screen: JoinGameScreens.details,
|
this.setState({ screen: JoinGameScreens.details,
|
||||||
game: game
|
game: game
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleBack = e => {
|
handleBack = e => {
|
||||||
@@ -54,59 +56,82 @@ class JoinGame extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleJoinAsExisting = e => {
|
handleJoinAsExisting = (e, id) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.startOrJoinGame({ type: 'join-as-existing',
|
this.props.startOrJoinGame({ type: 'join-as-existing',
|
||||||
playerName: e.target.text,
|
gameId: id });
|
||||||
gameId: this.state.game.id,
|
}
|
||||||
gameName: this.state.game.name });
|
|
||||||
|
showSignIn = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState(state => { return { showSignIn: !state.showSignIn }; });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<GroupBox title={(
|
<GroupBox title={(
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<a href="#" onClick={this.handleBack}>
|
<a href="#" onClick={this.handleBack}>
|
||||||
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
||||||
</a>
|
</a>
|
||||||
Join Game
|
Join Game
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}>
|
)}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col width='12'>
|
<Col width='12'>
|
||||||
{this.state.screen === JoinGameScreens.list ?
|
{this.state.screen === JoinGameScreens.list ?
|
||||||
(<ul>
|
(<>
|
||||||
|
<h3>My Games</h3>
|
||||||
|
{(!this.props.user && !this.state.showSignIn) ? (
|
||||||
|
<a onClick={this.showSignIn}>Sign In to see your games</a>
|
||||||
|
) : (<></>)}
|
||||||
|
{(!this.props.user && this.state.showSignIn) ? (
|
||||||
|
<>
|
||||||
|
<hr />
|
||||||
|
<LoginOrCreateAccount login={this.props.login}
|
||||||
|
createAccount={this.props.createAccount}
|
||||||
|
errors={this.props.errors}
|
||||||
|
showLogin={true}
|
||||||
|
/>
|
||||||
|
<hr />
|
||||||
|
</>
|
||||||
|
) : (<></>)}
|
||||||
|
<ul>
|
||||||
{this.props.games
|
{this.props.games
|
||||||
.map((g, i) =>
|
.map((g, i) =>
|
||||||
(<li key={i}>
|
(<li key={i}>
|
||||||
<a onClick={e => {
|
<a onClick={(e) => this.handleJoinAsExisting(e, g.id)}>{g.name}</a>
|
||||||
e.preventDefault();
|
</li>))}
|
||||||
this.handleClickGame(g); }}>{g.name}</a>
|
</ul>
|
||||||
</li>))}
|
<h3>Open Games</h3>
|
||||||
</ul>)
|
<ul>
|
||||||
: (
|
{this.props.openGames
|
||||||
<Fragment>
|
.map((g, i) =>
|
||||||
<h3><b>Game:</b> {this.state.game.name}</h3>
|
(<li key={i}>
|
||||||
<h4>Join as existing player:</h4>
|
<a onClick={e => {
|
||||||
<ul>
|
e.preventDefault();
|
||||||
{this.state.game.players.map((p, i) =>
|
this.handleClickGame(g); }}>{g.name}</a>
|
||||||
(<li key={i}>
|
</li>))}
|
||||||
<a onClick={this.handleJoinAsExisting}>
|
</ul>
|
||||||
{p}
|
</>
|
||||||
</a>
|
)
|
||||||
</li>))}
|
: (
|
||||||
</ul>
|
<Fragment>
|
||||||
<NewGame colors={this.state.game.colors}
|
<h3><b>Game:</b> {this.state.game.name}</h3>
|
||||||
button={'Join'}
|
<NewGame colors={this.state.game.colors}
|
||||||
showGameName={false}
|
button={'Join'}
|
||||||
gameName={this.state.game.name}
|
showGameName={false}
|
||||||
gameId={this.state.game.id}
|
gameName={this.state.game.name}
|
||||||
type={'join-game'}
|
gameId={this.state.game.id}
|
||||||
hideBack={true}
|
type={'join-game'}
|
||||||
title={'Join as New Player'} />
|
hideBack={true}
|
||||||
</Fragment>)}
|
createAccount={this.props.createAccount}
|
||||||
</Col>
|
login={this.props.login}
|
||||||
</Row>
|
errors={this.props.errors}
|
||||||
|
title={'Join as New Player'} />
|
||||||
|
</Fragment>)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2020 Thomas Hintz
|
||||||
|
//
|
||||||
|
// This file is part of the Alpha Centauri Farming project.
|
||||||
|
//
|
||||||
|
// The Alpha Centauri Farming project is free software: you can
|
||||||
|
// redistribute it and/or modify it under the terms of the GNU General
|
||||||
|
// Public License as published by the Free Software Foundation, either
|
||||||
|
// version 3 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The Alpha Centauri Farming project is distributed in the hope that
|
||||||
|
// it will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||||
|
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE. See the GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Alpha Centauri Farming project. If not, see
|
||||||
|
// <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import React from 'react'
|
||||||
|
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||||
|
|
||||||
|
import CreateAccount from '../create-account/CreateAccount.jsx';
|
||||||
|
import Login from '../login/Login.jsx';
|
||||||
|
|
||||||
|
export default class LoginOrCreateAccount extends React.Component {
|
||||||
|
state = {
|
||||||
|
showLogin: !!this.props.showLogin
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleLogin = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState(state => { return { showLogin: !state.showLogin }; });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{this.state.showLogin ? (
|
||||||
|
<Login errors={this.props.errors} login={this.props.login} />
|
||||||
|
) : (
|
||||||
|
<CreateAccount errors={this.props.errors}
|
||||||
|
createAccount={this.props.createAccount} />
|
||||||
|
)}
|
||||||
|
<div className="center">
|
||||||
|
<a onClick={this.toggleLogin}>{this.state.showLogin ? 'Create Account' : 'Login'}</a>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
90
src/components/login/Login.jsx
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// Copyright 2020 Thomas Hintz
|
||||||
|
//
|
||||||
|
// This file is part of the Alpha Centauri Farming project.
|
||||||
|
//
|
||||||
|
// The Alpha Centauri Farming project is free software: you can
|
||||||
|
// redistribute it and/or modify it under the terms of the GNU General
|
||||||
|
// Public License as published by the Free Software Foundation, either
|
||||||
|
// version 3 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The Alpha Centauri Farming project is distributed in the hope that
|
||||||
|
// it will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||||
|
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE. See the GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Alpha Centauri Farming project. If not, see
|
||||||
|
// <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import React from 'react'
|
||||||
|
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||||
|
|
||||||
|
export default class Login extends React.Component {
|
||||||
|
state = {
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
onChange = (e) => {
|
||||||
|
const target = e.target,
|
||||||
|
value = target.value,
|
||||||
|
name = target.name;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
[name]: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({ loading: true });
|
||||||
|
this.props.login(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (this.state.loading && prevProps.errors !== this.props.errors) {
|
||||||
|
this.setState({ loading: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<GroupBox title="Login">
|
||||||
|
<form onSubmit={this.onSubmit}>
|
||||||
|
<Row>
|
||||||
|
<Col width="12">
|
||||||
|
<label>
|
||||||
|
Username
|
||||||
|
<input onChange={this.onChange} required name="username" type="text" />
|
||||||
|
</label>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col width="12">
|
||||||
|
<label>
|
||||||
|
Password
|
||||||
|
<input onChange={this.onChange} required name="password" type="password" />
|
||||||
|
</label>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col width="12">
|
||||||
|
{!this.state.loading ? (
|
||||||
|
<>
|
||||||
|
{this.props.errors.map((err, i) => (
|
||||||
|
<p key={i}>
|
||||||
|
Error: {err}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
<Button type="submit">Login</Button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<span>Logging in...</span>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</form>
|
||||||
|
</GroupBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import React, { Fragment } from 'react'
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
|
||||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||||
|
import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccount.jsx';
|
||||||
|
|
||||||
import { startOrJoinGame } from '../start/actions.js'
|
import { startOrJoinGame } from '../start/actions.js'
|
||||||
import { start } from '../app/actions.js'
|
import { start } from '../app/actions.js'
|
||||||
@@ -53,7 +54,6 @@ class NewGame extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
showSettings: false,
|
showSettings: false,
|
||||||
playerName: '',
|
|
||||||
checkedColor: props.colors[0],
|
checkedColor: props.colors[0],
|
||||||
gameId: typeof props.gameId === 'undefined' ? -1 : props.gameId,
|
gameId: typeof props.gameId === 'undefined' ? -1 : props.gameId,
|
||||||
gameName: props.gameName || '',
|
gameName: props.gameName || '',
|
||||||
@@ -63,7 +63,8 @@ class NewGame extends React.Component {
|
|||||||
auditThreshold: 250000,
|
auditThreshold: 250000,
|
||||||
startingCash: 5000,
|
startingCash: 5000,
|
||||||
startingDebt: 5000,
|
startingDebt: 5000,
|
||||||
trade: true
|
trade: true,
|
||||||
|
showLogin: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,8 +97,7 @@ class NewGame extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let playerNameInput,
|
let titleBar = !this.props.hideBack ? (
|
||||||
titleBar = !this.props.hideBack ? (
|
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<a onClick={this.handleBack}>
|
<a onClick={this.handleBack}>
|
||||||
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
||||||
@@ -129,97 +129,97 @@ class NewGame extends React.Component {
|
|||||||
mainScreenClass = !this.state.showSettings ? '' : 'hidden';
|
mainScreenClass = !this.state.showSettings ? '' : 'hidden';
|
||||||
return (
|
return (
|
||||||
<GroupBox title={titleBar}>
|
<GroupBox title={titleBar}>
|
||||||
<form onSubmit={this.handleSubmit}>
|
{this.props.user ? (
|
||||||
<div className={mainScreenClass}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
<Row>
|
<div className={mainScreenClass}>
|
||||||
<Col width='12'>
|
<Row>
|
||||||
<label>Your Name
|
<Col width='12'>
|
||||||
<input type='text' name='playerName'
|
<label>Your Color</label>
|
||||||
required
|
{colors}
|
||||||
value={this.state.playerName}
|
<br /><br />
|
||||||
onChange={this.handleInputChange} />
|
</Col>
|
||||||
</label>
|
</Row>
|
||||||
</Col>
|
{gameName}
|
||||||
</Row>
|
</div>
|
||||||
<Row>
|
<div className={settingsClass}>
|
||||||
<Col width='12'>
|
<InputRow label='Down Payment'
|
||||||
<label>Your Color</label>
|
name='downPayment'
|
||||||
{colors}
|
min={0}
|
||||||
<br /><br />
|
max={1}
|
||||||
</Col>
|
step={0.1}
|
||||||
</Row>
|
value={this.state.downPayment}
|
||||||
{gameName}
|
onChange={this.handleInputChange} />
|
||||||
</div>
|
<InputRow label='Loan Interest'
|
||||||
<div className={settingsClass}>
|
name='loanInterest'
|
||||||
<InputRow label='Down Payment'
|
min={0}
|
||||||
name='downPayment'
|
max={1}
|
||||||
min={0}
|
step={0.1}
|
||||||
max={1}
|
value={this.state.loanInterest}
|
||||||
step={0.1}
|
onChange={this.handleInputChange} />
|
||||||
value={this.state.downPayment}
|
<InputRow label='Maximum Debt'
|
||||||
onChange={this.handleInputChange} />
|
name='maxDebt'
|
||||||
<InputRow label='Loan Interest'
|
min={0}
|
||||||
name='loanInterest'
|
step={5000}
|
||||||
min={0}
|
value={this.state.maxDebt}
|
||||||
max={1}
|
onChange={this.handleInputChange} />
|
||||||
step={0.1}
|
<InputRow label='Audit Threshold'
|
||||||
value={this.state.loanInterest}
|
name='auditThreshold'
|
||||||
onChange={this.handleInputChange} />
|
min={0}
|
||||||
<InputRow label='Maximum Debt'
|
step={25000}
|
||||||
name='maxDebt'
|
value={this.state.auditThreshold}
|
||||||
min={0}
|
onChange={this.handleInputChange} />
|
||||||
step={5000}
|
<InputRow label='Starting Cash'
|
||||||
value={this.state.maxDebt}
|
name='startingCash'
|
||||||
onChange={this.handleInputChange} />
|
min={0}
|
||||||
<InputRow label='Audit Threshold'
|
step={1000}
|
||||||
name='auditThreshold'
|
value={this.state.startingCash}
|
||||||
min={0}
|
onChange={this.handleInputChange} />
|
||||||
step={25000}
|
<InputRow label='Starting Debt'
|
||||||
value={this.state.auditThreshold}
|
name='startingDebt'
|
||||||
onChange={this.handleInputChange} />
|
min={0}
|
||||||
<InputRow label='Starting Cash'
|
step={1000}
|
||||||
name='startingCash'
|
value={this.state.startingDebt}
|
||||||
min={0}
|
onChange={this.handleInputChange} />
|
||||||
step={1000}
|
<Row>
|
||||||
value={this.state.startingCash}
|
<Col width='12'>
|
||||||
onChange={this.handleInputChange} />
|
<label>
|
||||||
<InputRow label='Starting Debt'
|
<input type='checkbox'
|
||||||
name='startingDebt'
|
checked={this.state.trade}
|
||||||
min={0}
|
onChange={this.handleInputChange}
|
||||||
step={1000}
|
name='trade' />
|
||||||
value={this.state.startingDebt}
|
Enable Trading
|
||||||
onChange={this.handleInputChange} />
|
</label>
|
||||||
<Row>
|
</Col>
|
||||||
<Col width='12'>
|
</Row>
|
||||||
<label>
|
</div>
|
||||||
<input type='checkbox'
|
<Row>
|
||||||
checked={this.state.trade}
|
<Col width='12'>
|
||||||
onChange={this.handleInputChange}
|
<div className='new-game-submit-container'>
|
||||||
name='trade' />
|
<Button type='submit'>{this.props.button} Game</Button>
|
||||||
Enable Trading
|
{this.props.showGameName ? (
|
||||||
</label>
|
<a onClick={this.toggleSettings}>
|
||||||
</Col>
|
<FontAwesomeIcon icon={faCog} size='lg' />
|
||||||
</Row>
|
</a>
|
||||||
</div>
|
) : (<Fragment />)}
|
||||||
<Row>
|
</div>
|
||||||
<Col width='12'>
|
</Col>
|
||||||
<div className='new-game-submit-container'>
|
</Row>
|
||||||
<Button type='submit'>{this.props.button} Game</Button>
|
</form>
|
||||||
{this.props.showGameName ? (
|
) : (
|
||||||
<a onClick={this.toggleSettings}>
|
<>
|
||||||
<FontAwesomeIcon icon={faCog} size='lg' />
|
<span>Sign in or create account to continue</span>
|
||||||
</a>
|
<LoginOrCreateAccount login={this.props.login}
|
||||||
) : (<Fragment />)}
|
createAccount={this.props.createAccount}
|
||||||
</div>
|
errors={this.props.errors}
|
||||||
</Col>
|
/>
|
||||||
</Row>
|
</>
|
||||||
</form>
|
)}
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
null,
|
state => state.start.start,
|
||||||
{ startOrJoinGame, start }
|
{ startOrJoinGame, start }
|
||||||
)(NewGame)
|
)(NewGame)
|
||||||
|
|||||||
@@ -17,4 +17,7 @@
|
|||||||
// <https://www.gnu.org/licenses/>.
|
// <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export const SET_START_GAMES = 'set-start-games';
|
export const SET_START_GAMES = 'set-start-games';
|
||||||
|
export const SET_OPEN_GAMES = 'set-open-games';
|
||||||
|
export const SET_USER = 'set-user';
|
||||||
|
export const SET_ERRORS = 'set-errors';
|
||||||
export const START_OR_JOIN_GAME = 'start-or-join-game';
|
export const START_OR_JOIN_GAME = 'start-or-join-game';
|
||||||
|
|||||||
@@ -16,16 +16,32 @@
|
|||||||
// 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/>.
|
||||||
|
|
||||||
import { SET_START_GAMES, START_OR_JOIN_GAME } from './actionTypes.js'
|
import { SET_START_GAMES, START_OR_JOIN_GAME, SET_USER, SET_OPEN_GAMES,
|
||||||
|
SET_ERRORS } from './actionTypes.js'
|
||||||
|
|
||||||
export { setStartGames, startOrJoinGame }
|
export { setStartGames, startOrJoinGame, setUser, setOpenGames, setErrors }
|
||||||
|
|
||||||
function setStartGames(games) {
|
function setStartGames(games) {
|
||||||
return { type: SET_START_GAMES,
|
return { type: SET_START_GAMES,
|
||||||
games };
|
games };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setOpenGames(games) {
|
||||||
|
return { type: SET_OPEN_GAMES,
|
||||||
|
games };
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUser(user) {
|
||||||
|
return { type: SET_USER,
|
||||||
|
user };
|
||||||
|
}
|
||||||
|
|
||||||
function startOrJoinGame(msg) {
|
function startOrJoinGame(msg) {
|
||||||
return { type: START_OR_JOIN_GAME,
|
return { type: START_OR_JOIN_GAME,
|
||||||
msg };
|
msg };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setErrors(errors) {
|
||||||
|
return { type: SET_ERRORS,
|
||||||
|
errors };
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,11 +16,15 @@
|
|||||||
// 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/>.
|
||||||
|
|
||||||
import { SET_START_GAMES, START_OR_JOIN_GAME } from './actionTypes.js'
|
import { SET_START_GAMES, START_OR_JOIN_GAME, SET_USER, SET_OPEN_GAMES,
|
||||||
|
SET_ERRORS } from './actionTypes.js'
|
||||||
import { SCREENS } from '../../constants.js'
|
import { SCREENS } from '../../constants.js'
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
start: { games: [] },
|
start: { games: [],
|
||||||
|
openGames: [],
|
||||||
|
errors: [],
|
||||||
|
user: false },
|
||||||
msg: null
|
msg: null
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,6 +32,12 @@ export default function(state = initialState, action) {
|
|||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case SET_START_GAMES:
|
case SET_START_GAMES:
|
||||||
return { ...state, start: { ...state.start, games: action.games }};
|
return { ...state, start: { ...state.start, games: action.games }};
|
||||||
|
case SET_OPEN_GAMES:
|
||||||
|
return { ...state, start: { ...state.start, openGames: action.games }};
|
||||||
|
case SET_USER:
|
||||||
|
return { ...state, start: { ...state.start, user: action.user }};
|
||||||
|
case SET_ERRORS:
|
||||||
|
return { ...state, start: { ...state.start, errors: action.errors }};
|
||||||
case START_OR_JOIN_GAME:
|
case START_OR_JOIN_GAME:
|
||||||
return { ...state, msg: action.msg };
|
return { ...state, msg: action.msg };
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ export const SCREENS = {
|
|||||||
|
|
||||||
export const GAME_STATES = { preTurn: 'pre-turn',
|
export const GAME_STATES = { preTurn: 'pre-turn',
|
||||||
midTurn: 'mid-turn',
|
midTurn: 'mid-turn',
|
||||||
turnEnded: 'turn-ended' };
|
turnEnded: 'turn-ended',
|
||||||
|
preGame: 'pre-game' };
|
||||||
export const rootId = 'initial-element';
|
export const rootId = 'initial-element';
|
||||||
export const messagePanelId = 'message-panel';
|
export const messagePanelId = 'message-panel';
|
||||||
export const ALERTS = { beginTurn: 'begin-turn',
|
export const ALERTS = { beginTurn: 'begin-turn',
|
||||||
@@ -34,4 +35,5 @@ export const ALERTS = { beginTurn: 'begin-turn',
|
|||||||
endOfGame: 'end-of-game',
|
endOfGame: 'end-of-game',
|
||||||
auditCalled: 'audit-called',
|
auditCalled: 'audit-called',
|
||||||
raiseMoney: 'raise-money',
|
raiseMoney: 'raise-money',
|
||||||
proposedTrade: 'proposed-trade' }
|
proposedTrade: 'proposed-trade',
|
||||||
|
preGame: 'pre-game' }
|
||||||
|
|||||||
23
src/main.jsx
@@ -28,7 +28,8 @@ import { rootId } from './constants.js'
|
|||||||
import App from './components/app/App.jsx'
|
import App from './components/app/App.jsx'
|
||||||
import { initialize, handleMessage as handleMessageFarm } from './components/farm/interface.js'
|
import { initialize, handleMessage as handleMessageFarm } from './components/farm/interface.js'
|
||||||
|
|
||||||
import { setStartGames, startOrJoinGame } from './components/start/actions.js'
|
import { setStartGames, startOrJoinGame, setUser, setOpenGames,
|
||||||
|
setErrors } from './components/start/actions.js'
|
||||||
import { play } from './components/app/actions.js'
|
import { play } from './components/app/actions.js'
|
||||||
import { createStore } from 'redux'
|
import { createStore } from 'redux'
|
||||||
import rootReducer from './rootReducers.js'
|
import rootReducer from './rootReducers.js'
|
||||||
@@ -46,9 +47,24 @@ document.body.appendChild(makeDiv(rootId));
|
|||||||
|
|
||||||
window.store = store;
|
window.store = store;
|
||||||
|
|
||||||
|
const createAccount = (msg) => {
|
||||||
|
Ws.sendCommand({ type: 'create-account', ...msg});
|
||||||
|
}
|
||||||
|
|
||||||
|
const login = (msg) => {
|
||||||
|
Ws.sendCommand({ type: 'login', ...msg});
|
||||||
|
}
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
Ws.sendCommand({ type: 'logout'});
|
||||||
|
}
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App />
|
<App createAccount={createAccount}
|
||||||
|
login={login}
|
||||||
|
logout={logout}
|
||||||
|
/>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
document.getElementById(rootId)
|
document.getElementById(rootId)
|
||||||
);
|
);
|
||||||
@@ -78,6 +94,9 @@ function handleMessage(evt) {
|
|||||||
store.dispatch(play());
|
store.dispatch(play());
|
||||||
} else if (data.event === 'start-init') {
|
} else if (data.event === 'start-init') {
|
||||||
store.dispatch(setStartGames(data.games.games));
|
store.dispatch(setStartGames(data.games.games));
|
||||||
|
store.dispatch(setOpenGames(data.openGames.games));
|
||||||
|
store.dispatch(setUser(data.user));
|
||||||
|
store.dispatch(setErrors(data.errors));
|
||||||
if (autostart) {
|
if (autostart) {
|
||||||
if (data.games.games.length === 0) {
|
if (data.games.games.length === 0) {
|
||||||
store.dispatch(startOrJoinGame({ type: 'new-game',
|
store.dispatch(startOrJoinGame({ type: 'new-game',
|
||||||
|
|||||||
134
src/server/db.scm
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
(use sql-de-lite crypt)
|
||||||
|
|
||||||
|
(define *db* "/home/tjhintz/db")
|
||||||
|
|
||||||
|
(define-syntax with-db
|
||||||
|
(syntax-rules ()
|
||||||
|
((_ (var) body ...)
|
||||||
|
(call-with-database *db*
|
||||||
|
(lambda (var)
|
||||||
|
body ...)))))
|
||||||
|
|
||||||
|
(define (create-tables)
|
||||||
|
(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 players(id INTEGER PRIMARY KEY, object TEXT);"))
|
||||||
|
(exec (sql db "create table user_games(user_id INTEGER, game_id INTEGER);"))))
|
||||||
|
|
||||||
|
(define (db-session-set! sid bindings)
|
||||||
|
(with-db (db)
|
||||||
|
(exec (sql db "insert or replace into sessions(bindings, session_id) values (?, ?);")
|
||||||
|
(with-output-to-string (lambda () (write bindings)))
|
||||||
|
sid)))
|
||||||
|
|
||||||
|
(define (db-session-ref sid)
|
||||||
|
(with-input-from-string
|
||||||
|
(or (alist-ref
|
||||||
|
'bindings
|
||||||
|
(with-db (db)
|
||||||
|
(query fetch-alist
|
||||||
|
(sql db "select * from sessions where session_id=?;")
|
||||||
|
sid)))
|
||||||
|
"#f")
|
||||||
|
read))
|
||||||
|
|
||||||
|
(define (add-user username email password)
|
||||||
|
(let ((salt (crypt-gensalt)))
|
||||||
|
(with-db (db)
|
||||||
|
(exec (sql db "insert into users(username, password, salt, email) values(?, ?, ?, ?);")
|
||||||
|
username (crypt password salt) salt email)
|
||||||
|
(last-insert-rowid db))))
|
||||||
|
|
||||||
|
(define (fetch-user username)
|
||||||
|
(with-db (db)
|
||||||
|
(query fetch-alist
|
||||||
|
(sql db "select * from users where username=?;")
|
||||||
|
username)))
|
||||||
|
|
||||||
|
(define (fetch-user-by-id id)
|
||||||
|
(with-db (db)
|
||||||
|
(query fetch-alist
|
||||||
|
(sql db "select * from users where id=?;")
|
||||||
|
id)))
|
||||||
|
|
||||||
|
(define (valid-password? username password)
|
||||||
|
(and-let* ((user (fetch-user username))
|
||||||
|
(_ (if (null? user)
|
||||||
|
(begin (crypt password "$2a$12$OW1wyLclJvq.PIxgoHCjdu")
|
||||||
|
#f)
|
||||||
|
#t)))
|
||||||
|
(string=? (crypt password (alist-ref 'salt user))
|
||||||
|
(alist-ref 'password user))))
|
||||||
|
|
||||||
|
(define (alist->string alist)
|
||||||
|
(with-output-to-string (lambda () (write alist))))
|
||||||
|
|
||||||
|
(define (string->alist s)
|
||||||
|
(with-input-from-string s read))
|
||||||
|
|
||||||
|
(define (db-add-game status object)
|
||||||
|
(with-db (db)
|
||||||
|
(exec (sql db "insert into games(status, object) values (?, ?);")
|
||||||
|
status (alist->string object))
|
||||||
|
(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))))
|
||||||
|
|
||||||
|
(define (db-fetch-game id)
|
||||||
|
(string->alist
|
||||||
|
(with-db (db)
|
||||||
|
(query fetch-value
|
||||||
|
(sql db "select object from games where id=?;")
|
||||||
|
id))))
|
||||||
|
|
||||||
|
(define (db-fetch-open-games)
|
||||||
|
(map
|
||||||
|
string->alist
|
||||||
|
(with-db (db)
|
||||||
|
(query fetch-column
|
||||||
|
(sql db "select object from games where status=?;")
|
||||||
|
"pre-game"))))
|
||||||
|
|
||||||
|
(define (db-fetch-game-row id)
|
||||||
|
(let ((res
|
||||||
|
(with-db (db)
|
||||||
|
(query fetch-alist
|
||||||
|
(sql db "select * from games where id=?;")
|
||||||
|
id))))
|
||||||
|
`((id . ,(alist-ref 'id res))
|
||||||
|
(status . ,(alist-ref 'status res))
|
||||||
|
(object . ,(string->alist (alist-ref 'object res))))))
|
||||||
|
|
||||||
|
(define (db-add-player object)
|
||||||
|
(with-db (db)
|
||||||
|
(exec (sql db "insert into players(object) values (?);")
|
||||||
|
(alist->string object))
|
||||||
|
(last-insert-rowid db)))
|
||||||
|
|
||||||
|
(define (db-update-player id object)
|
||||||
|
(with-db (db)
|
||||||
|
(exec (sql db "replace into players(id, object) values (?, ?);")
|
||||||
|
id (alist->string object))))
|
||||||
|
|
||||||
|
(define (db-fetch-player id)
|
||||||
|
(string->alist
|
||||||
|
(with-db (db)
|
||||||
|
(query fetch-value
|
||||||
|
(sql db "select object from players where id=?;")
|
||||||
|
id))))
|
||||||
|
|
||||||
|
(define (db-add-user-game user-id game-id)
|
||||||
|
(with-db (db)
|
||||||
|
(exec (sql db "insert into user_games(user_id, game_id) values (?, ?);")
|
||||||
|
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)))
|
||||||
@@ -29,6 +29,33 @@
|
|||||||
(else
|
(else
|
||||||
(include "game")))
|
(include "game")))
|
||||||
|
|
||||||
|
(include "db.scm")
|
||||||
|
|
||||||
|
(session-storage-initialize
|
||||||
|
(lambda ()
|
||||||
|
'no-op))
|
||||||
|
|
||||||
|
(session-storage-set!
|
||||||
|
(lambda (sid session-item)
|
||||||
|
(db-session-set! sid (session-item-bindings session-item))))
|
||||||
|
|
||||||
|
(define (expiration)
|
||||||
|
(+ (current-milliseconds)
|
||||||
|
(inexact->exact (floor (* (session-lifetime) 1000)))))
|
||||||
|
|
||||||
|
(session-storage-ref
|
||||||
|
(lambda (sid)
|
||||||
|
(let ((data (db-session-ref sid)))
|
||||||
|
(if data
|
||||||
|
(make-session-item (expiration) (remote-address) data #f)
|
||||||
|
(error "session not found")))
|
||||||
|
;; (make-session-item (+ (current-milliseconds) 100000000) (remote-address) `((user-id . ,(db-session-ref sid))) #f)
|
||||||
|
))
|
||||||
|
|
||||||
|
(session-storage-delete!
|
||||||
|
(lambda (sid)
|
||||||
|
(error "session storage delete not handled")))
|
||||||
|
|
||||||
(root-path "./")
|
(root-path "./")
|
||||||
|
|
||||||
(define (neq? a b) (not (eq? a b)))
|
(define (neq? a b) (not (eq? a b)))
|
||||||
@@ -55,6 +82,7 @@
|
|||||||
(SRV:send-reply (pre-post-order* sxml rules)))))))
|
(SRV:send-reply (pre-post-order* sxml rules)))))))
|
||||||
|
|
||||||
(define *game* (make-parameter #f))
|
(define *game* (make-parameter #f))
|
||||||
|
(define *player* (make-parameter #f))
|
||||||
|
|
||||||
(define-syntax safe-set!
|
(define-syntax safe-set!
|
||||||
(ir-macro-transformer
|
(ir-macro-transformer
|
||||||
@@ -90,6 +118,7 @@
|
|||||||
(next-year-rules initform: '() accessor: player-next-year-rules)
|
(next-year-rules initform: '() accessor: player-next-year-rules)
|
||||||
(color initform: #f accessor: player-color)
|
(color initform: #f accessor: player-color)
|
||||||
(name initform: "PLAYER X" accessor: player-name)
|
(name initform: "PLAYER X" accessor: player-name)
|
||||||
|
(user-id initform: #f accessor: player-user-id)
|
||||||
(trade initform: '() accessor: player-trade)
|
(trade initform: '() accessor: player-trade)
|
||||||
(last-updated initform: 0 accessor: player-last-updated)
|
(last-updated initform: 0 accessor: player-last-updated)
|
||||||
(last-cash initform: 5000 accessor: player-last-cash)
|
(last-cash initform: 5000 accessor: player-last-cash)
|
||||||
@@ -114,7 +143,7 @@
|
|||||||
(colors initform: '() accessor: game-colors)
|
(colors initform: '() accessor: game-colors)
|
||||||
(last-updated initform: 0 accessor: game-last-updated)
|
(last-updated initform: 0 accessor: game-last-updated)
|
||||||
(called-audit initform: #f accessor: game-called-audit)
|
(called-audit initform: #f accessor: game-called-audit)
|
||||||
(state initform: 'playing accessor: game-state)
|
(state initform: 'pre-game accessor: game-state)
|
||||||
(name initform: "game" accessor: game-name)
|
(name initform: "game" accessor: game-name)
|
||||||
(turn initform: 1 accessor: game-turn)
|
(turn initform: 1 accessor: game-turn)
|
||||||
(current-player initform: #f accessor: game-current-player)
|
(current-player initform: #f accessor: game-current-player)
|
||||||
@@ -154,6 +183,7 @@
|
|||||||
(next-year-rules . ,(player-next-year-rules player))
|
(next-year-rules . ,(player-next-year-rules player))
|
||||||
(color . ,(player-color player))
|
(color . ,(player-color player))
|
||||||
(name . ,(player-name player))
|
(name . ,(player-name player))
|
||||||
|
(user-id . ,(player-user-id player))
|
||||||
(trade . ())
|
(trade . ())
|
||||||
(last-updated . 0)
|
(last-updated . 0)
|
||||||
(last-cash . ,(player-cash player))
|
(last-cash . ,(player-cash player))
|
||||||
@@ -196,11 +226,11 @@
|
|||||||
*operating-expense-cards*)))
|
*operating-expense-cards*)))
|
||||||
'called-audit (if (alist-ref 'called-audit x)
|
'called-audit (if (alist-ref 'called-audit x)
|
||||||
(find (lambda (p)
|
(find (lambda (p)
|
||||||
(string=? (player-name p) (alist-ref 'called-audit x)))
|
(equal? (player-name p) (alist-ref 'called-audit x)))
|
||||||
players)
|
players)
|
||||||
#f)
|
#f)
|
||||||
'current-player (find (lambda (p)
|
'current-player (find (lambda (p)
|
||||||
(string=? (player-name p) (alist-ref 'current-player x)))
|
(equal? (player-name p) (alist-ref 'current-player x)))
|
||||||
players)
|
players)
|
||||||
(fold (lambda (k r) (cons k (cons (alist-ref k x) r)))
|
(fold (lambda (k r) (cons k (cons (alist-ref k x) r)))
|
||||||
'()
|
'()
|
||||||
@@ -221,6 +251,10 @@
|
|||||||
(lambda ()
|
(lambda ()
|
||||||
(write (app->sexp *app*)))))
|
(write (app->sexp *app*)))))
|
||||||
|
|
||||||
|
(define (save-game game)
|
||||||
|
(db-update-game (game-id game) (symbol->string (game-state game))
|
||||||
|
(game->sexp game)))
|
||||||
|
|
||||||
(define (load-app)
|
(define (load-app)
|
||||||
(with-input-from-file "/home/tjhintz/app.scm"
|
(with-input-from-file "/home/tjhintz/app.scm"
|
||||||
(lambda ()
|
(lambda ()
|
||||||
@@ -236,7 +270,7 @@
|
|||||||
(fold (lambda (k r) (cons k (cons (alist-ref k x) r)))
|
(fold (lambda (k r) (cons k (cons (alist-ref k x) r)))
|
||||||
'()
|
'()
|
||||||
'(cash debt space previous-space state assets ridges
|
'(cash debt space previous-space state assets ridges
|
||||||
harvest-mult otbs
|
harvest-mult otbs user-id
|
||||||
year-rules next-year-rules hay-doubled corn-doubled
|
year-rules next-year-rules hay-doubled corn-doubled
|
||||||
color name trade last-updated last-cash))))
|
color name trade last-updated last-cash))))
|
||||||
|
|
||||||
@@ -310,13 +344,14 @@
|
|||||||
(safe-set! (game-colors game) (cdr (game-colors game)))
|
(safe-set! (game-colors game) (cdr (game-colors game)))
|
||||||
color))
|
color))
|
||||||
|
|
||||||
(define (add-player-to-game game color name)
|
(define (add-player-to-game game color name user-id)
|
||||||
(let ((player (make <player>
|
(let ((player (make <player>
|
||||||
'cash (game-setting 'starting-cash game)
|
'cash (game-setting 'starting-cash game)
|
||||||
'display-cash (game-setting 'starting-cash game)
|
'display-cash (game-setting 'starting-cash game)
|
||||||
'debt (game-setting 'starting-debt game)
|
'debt (game-setting 'starting-debt game)
|
||||||
'color color
|
'color color
|
||||||
'name name
|
'name name
|
||||||
|
'user-id user-id
|
||||||
'state (if (= (length (game-players game)) 0)
|
'state (if (= (length (game-players game)) 0)
|
||||||
'pre-turn 'turn-ended))))
|
'pre-turn 'turn-ended))))
|
||||||
(safe-set! (game-players game) (append (game-players game) (list player)))
|
(safe-set! (game-players game) (append (game-players game) (list player)))
|
||||||
@@ -441,6 +476,7 @@
|
|||||||
(player-otbs p))))
|
(player-otbs p))))
|
||||||
(color . ,(symbol->string (player-color p)))
|
(color . ,(symbol->string (player-color p)))
|
||||||
(name . ,(player-name p))
|
(name . ,(player-name p))
|
||||||
|
(user-id . ,(player-user-id p))
|
||||||
(trade . ,(player-trade p))
|
(trade . ,(player-trade p))
|
||||||
(lastCash . ,(player-last-cash p))
|
(lastCash . ,(player-last-cash p))
|
||||||
(hayDoubled . ,(player-hay-doubled p))
|
(hayDoubled . ,(player-hay-doubled p))
|
||||||
@@ -459,6 +495,7 @@
|
|||||||
(player-otbs p))))
|
(player-otbs p))))
|
||||||
(color . ,(symbol->string (player-color p)))
|
(color . ,(symbol->string (player-color p)))
|
||||||
(name . ,(player-name p))
|
(name . ,(player-name p))
|
||||||
|
(user-id . ,(player-user-id p))
|
||||||
(trade . ,(player-trade p))
|
(trade . ,(player-trade p))
|
||||||
(lastCash . ,(player-last-cash p))
|
(lastCash . ,(player-last-cash p))
|
||||||
(hayDoubled . ,(player-hay-doubled p))
|
(hayDoubled . ,(player-hay-doubled p))
|
||||||
@@ -535,13 +572,23 @@
|
|||||||
(define (finish-year player #!optional (collect-wages #t))
|
(define (finish-year player #!optional (collect-wages #t))
|
||||||
(let ((game (*game*)))
|
(let ((game (*game*)))
|
||||||
(when collect-wages
|
(when collect-wages
|
||||||
(safe-set! (player-cash player)
|
(let* ((richest (car (sort (game-players game)
|
||||||
(+ (player-cash player) 5000))
|
(lambda (p1 p2)
|
||||||
(safe-set! (player-display-cash player) (player-cash player))
|
(> (player-net-worth p1)
|
||||||
(safe-set! (game-actions game)
|
(player-net-worth p2))))))
|
||||||
(cons '((?action . info)
|
(bonus (max (farming-round
|
||||||
(?value . "You earned $5,000 from your city job!"))
|
(* (- (player-net-worth richest)
|
||||||
(game-actions game))))
|
(player-net-worth player))
|
||||||
|
0.2))
|
||||||
|
2500)))
|
||||||
|
(safe-set! (player-cash player)
|
||||||
|
;; (+ (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)
|
||||||
|
(?value . ,(conc "You earned $" bonus " from your city job!")))
|
||||||
|
(game-actions game)))))
|
||||||
(when (game-called-audit game)
|
(when (game-called-audit game)
|
||||||
(safe-set! (game-actions game)
|
(safe-set! (game-actions game)
|
||||||
(append (game-actions game)
|
(append (game-actions game)
|
||||||
@@ -810,7 +857,7 @@
|
|||||||
(player->list player)
|
(player->list player)
|
||||||
(game->list (*game*) player)))
|
(game->list (*game*) player)))
|
||||||
|
|
||||||
(define (create-start-response event)
|
(define (create-start-response event #!key (errors '()))
|
||||||
`((event . ,event)
|
`((event . ,event)
|
||||||
(games . ((games . ,(list->vector
|
(games . ((games . ,(list->vector
|
||||||
(map (lambda (game)
|
(map (lambda (game)
|
||||||
@@ -820,7 +867,24 @@
|
|||||||
(map symbol->string (game-colors game))))
|
(map symbol->string (game-colors game))))
|
||||||
(players . ,(list->vector
|
(players . ,(list->vector
|
||||||
(map player-name (game-players game))))))
|
(map player-name (game-players game))))))
|
||||||
(app-games *app*))))))))
|
(map (lambda (gid)
|
||||||
|
(sexp->game (db-fetch-game gid)))
|
||||||
|
(db-fetch-user-games (session-ref (sid) 'user-id -1))))))))
|
||||||
|
(openGames . ((games . ,(list->vector
|
||||||
|
(map (lambda (game)
|
||||||
|
`((name . ,(game-name game))
|
||||||
|
(id . ,(game-id game))
|
||||||
|
(colors . ,(list->vector
|
||||||
|
(map symbol->string (game-colors game))))
|
||||||
|
(players . ,(list->vector
|
||||||
|
(map player-name (game-players game))))))
|
||||||
|
(map sexp->game (db-fetch-open-games)))))))
|
||||||
|
(user . ,(let ((id (session-ref (sid) 'user-id #f)))
|
||||||
|
(if (and id (not (equal? id -1)))
|
||||||
|
id
|
||||||
|
#f)))
|
||||||
|
(errors . ,(list->vector errors))))
|
||||||
|
|
||||||
(define (message-players! game player message #!key (type "action"))
|
(define (message-players! game player message #!key (type "action"))
|
||||||
(for-each (lambda (p)
|
(for-each (lambda (p)
|
||||||
(when (not (eq? p player))
|
(when (not (eq? p player))
|
||||||
@@ -855,13 +919,35 @@
|
|||||||
(safe-set! (player-display-cash player) (player-cash player)))
|
(safe-set! (player-display-cash player) (player-cash player)))
|
||||||
(game-players game))))
|
(game-players game))))
|
||||||
|
|
||||||
|
(define (find-game id)
|
||||||
|
(let ((game-in-memory (find (lambda (g) (= (game-id g) id))
|
||||||
|
(app-games *app*))))
|
||||||
|
(if game-in-memory
|
||||||
|
game-in-memory
|
||||||
|
(let ((db-game (sexp->game (db-fetch-game id))))
|
||||||
|
(push! db-game (app-games *app*))
|
||||||
|
db-game))))
|
||||||
|
|
||||||
|
(define (next-roll last-roll)
|
||||||
|
(let ((roll (+ (random 6) 1)))
|
||||||
|
(if (= roll last-roll)
|
||||||
|
(next-roll last-roll)
|
||||||
|
roll)))
|
||||||
|
|
||||||
|
(define (make-rolls n)
|
||||||
|
(define (_make-rolls n i rolls)
|
||||||
|
(if (<= i n)
|
||||||
|
(_make-rolls n (+ i 1) (cons (next-roll (car rolls)) rolls))
|
||||||
|
rolls))
|
||||||
|
(_make-rolls n 1 (list (next-roll -1))))
|
||||||
|
|
||||||
(define (process-message player game type msg)
|
(define (process-message player game type msg)
|
||||||
(when game
|
(when player
|
||||||
(safe-set! (game-messages game) '())
|
|
||||||
(safe-set! (player-last-cash player) (player-cash player)))
|
(safe-set! (player-last-cash player) (player-cash player)))
|
||||||
(print "message type: " type)
|
(print "message type: " type)
|
||||||
(cond ((string=? type "roll")
|
(cond ((string=? type "roll")
|
||||||
(let ((num (+ (random 6) 1)))
|
(let ((num (+ (random 6) 1))
|
||||||
|
(rolls (make-rolls 22)))
|
||||||
(when *next-roll* (set! num *next-roll*))
|
(when *next-roll* (set! num *next-roll*))
|
||||||
(safe-set! (player-previous-space player)
|
(safe-set! (player-previous-space player)
|
||||||
(player-space player))
|
(player-space player))
|
||||||
@@ -876,7 +962,8 @@
|
|||||||
(finish-year player))
|
(finish-year player))
|
||||||
(safe-set! (player-harvest-mult player) 1)
|
(safe-set! (player-harvest-mult player) 1)
|
||||||
(let ((resp `((from . ,(player-previous-space player))
|
(let ((resp `((from . ,(player-previous-space player))
|
||||||
(to . ,(player-space player)))))
|
(to . ,(player-space player))
|
||||||
|
(rolls . ,(list->vector rolls)))))
|
||||||
(safe-set! (game-actions game)
|
(safe-set! (game-actions game)
|
||||||
(append (game-actions game)
|
(append (game-actions game)
|
||||||
`(((?action . move) (?value . ,resp))
|
`(((?action . move) (?value . ,resp))
|
||||||
@@ -1169,7 +1256,7 @@
|
|||||||
(print exn)
|
(print exn)
|
||||||
(print-error-message exn)
|
(print-error-message exn)
|
||||||
(print "error saving app"))
|
(print "error saving app"))
|
||||||
(save-app))
|
(save-game game))
|
||||||
(if (eq? (game-state game) 'finished)
|
(if (eq? (game-state game) 'finished)
|
||||||
(do-end-of-game game)
|
(do-end-of-game game)
|
||||||
(message-players! game player '() type: "update"))
|
(message-players! game player '() type: "update"))
|
||||||
@@ -1180,6 +1267,7 @@
|
|||||||
(create-start-response "start-init"))
|
(create-start-response "start-init"))
|
||||||
((string=? type "new-game")
|
((string=? type "new-game")
|
||||||
(let* ((color (string->symbol (alist-ref 'checkedColor msg)))
|
(let* ((color (string->symbol (alist-ref 'checkedColor msg)))
|
||||||
|
(user (fetch-user-by-id (session-ref (sid) 'user-id)))
|
||||||
(game (make <game> 'colors (filter (cut neq? <> color)
|
(game (make <game> 'colors (filter (cut neq? <> color)
|
||||||
'(green red blue yellow black))
|
'(green red blue yellow black))
|
||||||
'name (alist-ref 'gameName msg)
|
'name (alist-ref 'gameName msg)
|
||||||
@@ -1200,49 +1288,81 @@
|
|||||||
(trade . ,(or (alist-ref 'trade msg) #t)))))
|
(trade . ,(or (alist-ref 'trade msg) #t)))))
|
||||||
(player (add-player-to-game game
|
(player (add-player-to-game game
|
||||||
color
|
color
|
||||||
(alist-ref 'playerName msg)))
|
(alist-ref 'username user)
|
||||||
|
(alist-ref 'id user)))
|
||||||
;; (ai-player (add-ai-to-game game 'red "AI Player 1"))
|
;; (ai-player (add-ai-to-game game 'red "AI Player 1"))
|
||||||
)
|
)
|
||||||
(push! game (app-games *app*))
|
(push! game (app-games *app*))
|
||||||
(session-set! (sid) 'player player)
|
(let ((gid (db-add-game "pre-game" (game->sexp game))))
|
||||||
(session-set! (sid) 'game game)
|
(safe-set! (game-id game) gid)
|
||||||
|
(db-update-game gid "pre-game" (game->sexp game))
|
||||||
|
(db-add-user-game (alist-ref 'id user) (game-id game))
|
||||||
|
(session-set! (sid) 'game-id (game-id game)))
|
||||||
(*game* game)
|
(*game* game)
|
||||||
|
(*player* player)
|
||||||
(set-startup-otbs game player 2)
|
(set-startup-otbs game player 2)
|
||||||
;; (set-startup-otbs game ai-player 2)
|
;; (set-startup-otbs game ai-player 2)
|
||||||
;; (thread-start! (make-ai-push-receiver game ai-player))
|
;; (thread-start! (make-ai-push-receiver game ai-player))
|
||||||
(create-start-response "new-game-started")))
|
(create-start-response "new-game-started")))
|
||||||
((string=? type "join-game")
|
((string=? type "join-game")
|
||||||
(let* ((name (alist-ref 'gameName msg))
|
(let* ((user (fetch-user-by-id (session-ref (sid) 'user-id)))
|
||||||
|
(name (alist-ref 'username user))
|
||||||
(id (alist-ref 'gameId msg))
|
(id (alist-ref 'gameId msg))
|
||||||
(game (find (lambda (g) (= (game-id g) id))
|
(game (find-game id))
|
||||||
(app-games *app*)))
|
|
||||||
(color-raw (string->symbol (alist-ref 'checkedColor msg)))
|
(color-raw (string->symbol (alist-ref 'checkedColor msg)))
|
||||||
(color (if (not (member color-raw (game-colors game)))
|
(color (if (not (member color-raw (game-colors game)))
|
||||||
(car (game-colors game))
|
(car (game-colors game))
|
||||||
color-raw))
|
color-raw))
|
||||||
(player (add-player-to-game game
|
(player (add-player-to-game game
|
||||||
color
|
color
|
||||||
(alist-ref 'playerName msg))))
|
(alist-ref 'username user)
|
||||||
|
(alist-ref 'id user))))
|
||||||
(safe-set! (game-colors game) (filter (cut neq? <> color) (game-colors game)))
|
(safe-set! (game-colors game) (filter (cut neq? <> color) (game-colors game)))
|
||||||
(session-set! (sid) 'player player)
|
(session-set! (sid) 'game-id (game-id game))
|
||||||
(session-set! (sid) 'game game)
|
(db-add-user-game (alist-ref 'id user) (game-id game))
|
||||||
(*game* game)
|
(*game* game)
|
||||||
|
(*player* player)
|
||||||
(set-startup-otbs game player 2)
|
(set-startup-otbs game player 2)
|
||||||
(message-players! game player '() type: "update")
|
(message-players! game player '() type: "update")
|
||||||
(create-start-response "new-game-started")))
|
(create-start-response "new-game-started")))
|
||||||
((string=? type "join-as-existing")
|
((string=? type "join-as-existing")
|
||||||
(let* ((name (alist-ref 'gameName msg))
|
(let* ((id (alist-ref 'gameId msg))
|
||||||
(pname (alist-ref 'playerName msg))
|
(user-id (session-ref (sid) 'user-id))
|
||||||
(id (alist-ref 'gameId msg))
|
(game (find-game id))
|
||||||
(game (find (lambda (g) (= (game-id g) id))
|
(player (find (lambda (p) (equal? (player-user-id p) user-id))
|
||||||
(app-games *app*)))
|
|
||||||
(player (find (lambda (p) (string=? (player-name p) pname))
|
|
||||||
(game-players game))))
|
(game-players game))))
|
||||||
(session-set! (sid) 'player player)
|
|
||||||
(session-set! (sid) 'game game)
|
|
||||||
(*game* game)
|
(*game* game)
|
||||||
|
(*player* player)
|
||||||
(create-start-response "new-game-started")))
|
(create-start-response "new-game-started")))
|
||||||
))
|
((string=? type "create-account")
|
||||||
|
(let ((username (alist-ref 'username msg))
|
||||||
|
(email (alist-ref 'email msg))
|
||||||
|
(password (alist-ref 'password msg))
|
||||||
|
(confirm-password (alist-ref 'confirmPassword msg)))
|
||||||
|
(if (string=? password confirm-password)
|
||||||
|
(if (null? (fetch-user username))
|
||||||
|
(let ((id (add-user username email password)))
|
||||||
|
(session-set! (sid) 'user-id id)
|
||||||
|
(create-start-response "start-init"))
|
||||||
|
(create-start-response "start-init" errors: '("Account already exists")))
|
||||||
|
(create-start-response "start-init" errors: '("Passwords don't match")))))
|
||||||
|
((string=? type "login")
|
||||||
|
(let ((username (alist-ref 'username msg))
|
||||||
|
(password (alist-ref 'password msg)))
|
||||||
|
(if (valid-password? username password)
|
||||||
|
(begin (session-set! (sid) 'user-id (alist-ref 'id (fetch-user username)))
|
||||||
|
(create-start-response "start-init"))
|
||||||
|
(create-start-response "start-init" errors: '("Invalid password or account doesn't exist")))))
|
||||||
|
((string=? type "logout")
|
||||||
|
(session-set! (sid) 'game-id #f)
|
||||||
|
(session-set! (sid) 'user-id #f)
|
||||||
|
(create-start-response "start-init"))
|
||||||
|
((string=? type "start-game")
|
||||||
|
(safe-set! (game-state (*game*)) 'pre-turn)
|
||||||
|
(db-update-game (game-id (*game*)) (symbol->string (game-state (*game*)))
|
||||||
|
(game->sexp (*game*)))
|
||||||
|
(message-players! (*game*) (*player*) '() type: "update")
|
||||||
|
(create-ws-response (*player*) "update" '()))))
|
||||||
|
|
||||||
(define (process-ai-push-message player game msg)
|
(define (process-ai-push-message player game msg)
|
||||||
(print (player-name player))
|
(print (player-name player))
|
||||||
@@ -1297,6 +1417,18 @@
|
|||||||
(process-ai-push-message player game msg)
|
(process-ai-push-message player game msg)
|
||||||
(loop (mailbox-receive! (player-mailbox player))))))
|
(loop (mailbox-receive! (player-mailbox player))))))
|
||||||
|
|
||||||
|
(define (session-game)
|
||||||
|
(let ((user-id (session-ref (sid) 'user-id)))
|
||||||
|
(if (and (not (*game*)) (session-ref (sid) 'game-id #f))
|
||||||
|
(let ((possible-game (find-game (session-ref (sid) 'game-id))))
|
||||||
|
(when possible-game
|
||||||
|
(*game* possible-game)
|
||||||
|
(*player* (find (lambda (p)
|
||||||
|
(equal? (player-user-id p) user-id))
|
||||||
|
(game-players (*game*))))
|
||||||
|
(*game*)))
|
||||||
|
(and (*game*)))))
|
||||||
|
|
||||||
(define (websocket-page)
|
(define (websocket-page)
|
||||||
(sid (read-cookie (session-cookie-name)))
|
(sid (read-cookie (session-cookie-name)))
|
||||||
;; TODO some kind of error handling if (sid) #f
|
;; TODO some kind of error handling if (sid) #f
|
||||||
@@ -1321,16 +1453,28 @@
|
|||||||
(print-call-chain)
|
(print-call-chain)
|
||||||
(print-error-message exn))))
|
(print-error-message exn))))
|
||||||
(event . "error"))
|
(event . "error"))
|
||||||
(let* ((game (session-ref (sid) 'game #f))
|
(session-game)
|
||||||
(player (session-ref (sid) 'player #f))
|
(let* ((game (*game*))
|
||||||
(res (process-message player
|
(res (process-message (*player*)
|
||||||
game
|
game
|
||||||
(alist-ref 'type msg)
|
(alist-ref 'type msg)
|
||||||
msg)))
|
msg)))
|
||||||
(when game
|
(when game
|
||||||
(safe-set! (game-last-updated game) (+ (game-last-updated game) 1))
|
(safe-set! (game-last-updated game) (+ (game-last-updated game) 1))
|
||||||
(safe-set! (player-last-updated player) (game-last-updated game)))
|
(when (*player*)
|
||||||
res)))))
|
(safe-set! (player-last-updated (*player*)) (game-last-updated game))))
|
||||||
|
res)
|
||||||
|
;; (let* ((game (session-ref (sid) 'game #f))
|
||||||
|
;; (player (session-ref (sid) 'player #f))
|
||||||
|
;; (res (process-message player
|
||||||
|
;; game
|
||||||
|
;; (alist-ref 'type msg)
|
||||||
|
;; msg)))
|
||||||
|
;; (when game
|
||||||
|
;; (safe-set! (game-last-updated game) (+ (game-last-updated game) 1))
|
||||||
|
;; (safe-set! (player-last-updated player) (game-last-updated game)))
|
||||||
|
;; res)
|
||||||
|
))))
|
||||||
(loop (read-json (receive-message)))))))
|
(loop (read-json (receive-message)))))))
|
||||||
|
|
||||||
(define (push-websocket-page)
|
(define (push-websocket-page)
|
||||||
@@ -1338,39 +1482,33 @@
|
|||||||
;; TODO some kind of error handling if (sid) #f
|
;; TODO some kind of error handling if (sid) #f
|
||||||
(with-concurrent-websocket
|
(with-concurrent-websocket
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(let ((game (session-ref (sid) 'game))
|
(session-game)
|
||||||
(player (session-ref (sid) 'player)))
|
(let loop ((msg (mailbox-receive! (player-mailbox (*player*)))))
|
||||||
(*game* game)
|
(session-game)
|
||||||
(let loop ((msg (mailbox-receive! (player-mailbox player))))
|
;; when (< (player-last-updated player)
|
||||||
(print msg)
|
;; (game-last-updated game))
|
||||||
(when (not game)
|
(handle-exceptions
|
||||||
(set! game (session-ref (sid) 'game)))
|
exn
|
||||||
(when (not player)
|
(send-message
|
||||||
(set! player (session-ref (sid) 'player)))
|
(json->string
|
||||||
;; when (< (player-last-updated player)
|
`((exn . ,(with-output-to-string
|
||||||
;; (game-last-updated game))
|
(lambda ()
|
||||||
(handle-exceptions
|
(print-call-chain)
|
||||||
exn
|
(print-error-message exn)))))))
|
||||||
(send-message
|
(send-message
|
||||||
(json->string
|
(json->string
|
||||||
|
(handle-exceptions
|
||||||
|
exn
|
||||||
`((exn . ,(with-output-to-string
|
`((exn . ,(with-output-to-string
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(print-call-chain)
|
(print-call-chain)
|
||||||
(print-error-message exn)))))))
|
(print-error-message exn))))
|
||||||
(send-message
|
(event . "error"))
|
||||||
(json->string
|
(create-ws-response (*player*)
|
||||||
(handle-exceptions
|
(alist-ref 'type msg)
|
||||||
exn
|
(alist-ref 'value msg))
|
||||||
`((exn . ,(with-output-to-string
|
))))
|
||||||
(lambda ()
|
(loop (mailbox-receive! (player-mailbox (*player*))))))))
|
||||||
(print-call-chain)
|
|
||||||
(print-error-message exn))))
|
|
||||||
(event . "error"))
|
|
||||||
(create-ws-response player
|
|
||||||
(alist-ref 'type msg)
|
|
||||||
(alist-ref 'value msg))
|
|
||||||
))))
|
|
||||||
(loop (mailbox-receive! (player-mailbox player))))))))
|
|
||||||
|
|
||||||
(define (otb-spec->otb-cards spec id)
|
(define (otb-spec->otb-cards spec id)
|
||||||
`((contents . ,(sxml->html* (list-ref spec 5)))
|
`((contents . ,(sxml->html* (list-ref spec 5)))
|
||||||
@@ -2034,6 +2172,7 @@
|
|||||||
(game-players game)))))
|
(game-players game)))))
|
||||||
((alist-ref 'action operating-expense) player)
|
((alist-ref 'action operating-expense) player)
|
||||||
`((rolled . ,rolled)
|
`((rolled . ,rolled)
|
||||||
|
(rolls . ,(list->vector (make-rolls 22)))
|
||||||
(income . ,income)
|
(income . ,income)
|
||||||
(harvestMult . ,harvest-mult)
|
(harvestMult . ,harvest-mult)
|
||||||
(operatingExpense . ,(alist-ref 'contents operating-expense))
|
(operatingExpense . ,(alist-ref 'contents operating-expense))
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ $tab-margin: 0.3rem;
|
|||||||
align-items: center; }
|
align-items: center; }
|
||||||
|
|
||||||
.view-container {
|
.view-container {
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow: auto;
|
||||||
border: 0.3rem solid $dark-color;
|
border: 0.3rem solid $dark-color;
|
||||||
background: linear-gradient(180deg, $light-color 0%, $orange-color 100%);
|
background: linear-gradient(180deg, $light-color 0%, $orange-color 100%);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
@@ -919,3 +921,75 @@ $intro-time: 6s;
|
|||||||
|
|
||||||
.pad-right {
|
.pad-right {
|
||||||
padding-right: 0.3rem; }
|
padding-right: 0.3rem; }
|
||||||
|
|
||||||
|
.sign-out-button {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1rem; }
|
||||||
|
|
||||||
|
/* -------- MENU ------- */
|
||||||
|
/* Position and sizing of burger button */
|
||||||
|
.bm-burger-button {
|
||||||
|
position: fixed;
|
||||||
|
width: 36px;
|
||||||
|
height: 30px;
|
||||||
|
left: 36px;
|
||||||
|
top: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color/shape of burger icon bars */
|
||||||
|
.bm-burger-bars {
|
||||||
|
background: #373a47;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color/shape of burger icon bars on hover*/
|
||||||
|
.bm-burger-bars-hover {
|
||||||
|
background: #a90000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Position and sizing of clickable cross button */
|
||||||
|
.bm-cross-button {
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color/shape of close button cross */
|
||||||
|
.bm-cross {
|
||||||
|
background: #bdc3c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sidebar wrapper styles
|
||||||
|
Note: Beware of modifying this element as it can break the animations - you should not need to touch it in most cases
|
||||||
|
*/
|
||||||
|
.bm-menu-wrap {
|
||||||
|
position: fixed;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* General sidebar styles */
|
||||||
|
.bm-menu {
|
||||||
|
background: #373a47;
|
||||||
|
padding: 2.5em 1.5em 0;
|
||||||
|
font-size: 1.15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Morph shape necessary with bubble or elastic */
|
||||||
|
.bm-morph-shape {
|
||||||
|
fill: #373a47;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper for item list */
|
||||||
|
.bm-item-list {
|
||||||
|
color: #b8b7ad;
|
||||||
|
padding: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Individual item */
|
||||||
|
.bm-item {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styling of overlay */
|
||||||
|
.bm-overlay {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ export { sendCommand, setMainOnMessage, setSecondaryOnMessage,
|
|||||||
|
|
||||||
class WebSocketConnection {
|
class WebSocketConnection {
|
||||||
location = '';
|
location = '';
|
||||||
|
fullPath = '';
|
||||||
reopen = true;
|
reopen = true;
|
||||||
|
onmessageProc = () => 'nothing'
|
||||||
ws = null;
|
ws = null;
|
||||||
|
|
||||||
constructor(location) {
|
constructor(location) {
|
||||||
@@ -35,6 +37,7 @@ class WebSocketConnection {
|
|||||||
uri = "ws:";
|
uri = "ws:";
|
||||||
}
|
}
|
||||||
uri += "//" + loc.host;
|
uri += "//" + loc.host;
|
||||||
|
this.fullPath = uri + '/websocket/' + location;
|
||||||
this.ws = new WebSocket(uri + '/websocket/' + location);
|
this.ws = new WebSocket(uri + '/websocket/' + location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,8 +50,17 @@ class WebSocketConnection {
|
|||||||
this.ws.send(JSON.stringify(cmd));
|
this.ws.send(JSON.stringify(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reestablish = () => {
|
||||||
|
this.ws = new WebSocket(this.fullPath);
|
||||||
|
this.ws.onmessage = this.onmessageProc;
|
||||||
|
}
|
||||||
|
|
||||||
onmessage(proc) {
|
onmessage(proc) {
|
||||||
|
this.onmessageProc = proc;
|
||||||
this.ws.onmessage = proc;
|
this.ws.onmessage = proc;
|
||||||
|
// this.ws.onclose = () => {
|
||||||
|
// setTimeout(this.reestablish, 500);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
onopen(proc) {
|
onopen(proc) {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(woff|woff2|eot|ttf|otf|svg|png)$/,
|
test: /\.(woff|woff2|eot|ttf|otf|svg|png|gif)$/,
|
||||||
use: [
|
use: [
|
||||||
'file-loader',
|
'file-loader',
|
||||||
],
|
],
|
||||||
|
|||||||