Using sqlite database, mt proctor animation.
2
Makefile
@@ -35,7 +35,7 @@ install:
|
||||
npm install
|
||||
|
||||
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
|
||||
cd src/server/ && csc -include-path ../../$(assets) -O3 farm.scm
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"20 Cows on Peridier Ridge"))))
|
||||
|
||||
(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 "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.")))
|
||||
|
||||
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",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
@@ -3462,6 +3462,11 @@
|
||||
"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": {
|
||||
"version": "1.0.5",
|
||||
"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/free-solid-svg-icons": "^5.12.0",
|
||||
"@fortawesome/react-fontawesome": "^0.1.8",
|
||||
"cookies-js": "^1.2.3",
|
||||
"mobx": "^5.15.3",
|
||||
"mobx-react": "^6.1.4",
|
||||
"react": "^16.12.0",
|
||||
|
||||
@@ -50,7 +50,7 @@ class App extends React.Component {
|
||||
view = (<Chrome spikes={true} tractorClass='intro'><Welcome /></Chrome>);
|
||||
break;
|
||||
case SCREENS.start:
|
||||
view = (<Chrome><CreateOrJoin /></Chrome>);
|
||||
view = (<Chrome><CreateOrJoin signOut={this.props.logout} /></Chrome>);
|
||||
break;
|
||||
case SCREENS.newGame:
|
||||
view = (<Chrome>
|
||||
@@ -59,12 +59,24 @@ class App extends React.Component {
|
||||
button={'Start'}
|
||||
title={'New Game'}
|
||||
type={'new-game'}
|
||||
showGameName={true} />
|
||||
showGameName={true}
|
||||
createAccount={this.props.createAccount}
|
||||
login={this.props.login}
|
||||
errors={this.props.errors}
|
||||
/>
|
||||
</div>
|
||||
</Chrome>);
|
||||
break;
|
||||
case SCREENS.joinGame:
|
||||
view = (<Chrome><div className='view-container'><JoinGame /></div></Chrome>);
|
||||
view = (
|
||||
<Chrome>
|
||||
<div className='view-container'>
|
||||
<JoinGame createAccount={this.props.createAccount}
|
||||
login={this.props.login}
|
||||
errors={this.props.errors}
|
||||
/>
|
||||
</div>
|
||||
</Chrome>);
|
||||
break;
|
||||
case SCREENS.play:
|
||||
view = (<Board />);
|
||||
|
||||
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 { connect } from 'react-redux'
|
||||
|
||||
import Cookies from 'cookies-js'
|
||||
|
||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
import { showNewGame, showJoinGame } from '../app/actions.js'
|
||||
|
||||
class CreateOrJoin extends React.Component {
|
||||
signOut = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.signOut();
|
||||
Cookies.expire('awful-cookie');
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Fragment>
|
||||
<Button size='large' className='shadow' onClick={this.props.showNewGame}>
|
||||
New Game
|
||||
</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}>
|
||||
Join Game
|
||||
</Button>
|
||||
) : (<Fragment />)}
|
||||
{this.props.start.start.user ? (
|
||||
<Button size='large' className='shadow sign-out-button' onClick={this.signOut}>
|
||||
Sign Out
|
||||
</Button>
|
||||
) : (<></>)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import WheatImg from './../../../assets/img/wheat.svg'
|
||||
import TractorImg from './../../../assets/img/tractor-icon.svg'
|
||||
import TractorFullImg from './../../../assets/img/tractor-with-spikes.svg'
|
||||
import HarvesterImg from './../../../assets/img/harvester.svg'
|
||||
import VolcanoImg from './../../../assets/img/volcano2.gif'
|
||||
|
||||
import React, { Fragment } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
@@ -45,7 +46,7 @@ import { setSelectedCard, setMessagePanelSpace, setMPDims, movePlayer,
|
||||
setMovingSkip } from './actions.js'
|
||||
import { buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||
submitTradeDeny, submitTradeCancel, audit,
|
||||
buyUncleBert, skip, endAiTurn } from './interface.js'
|
||||
buyUncleBert, skip, endAiTurn, startGame } from './interface.js'
|
||||
|
||||
function netWorth(player) {
|
||||
return ((player.assets.hay + player.assets.grain) * 2000) +
|
||||
@@ -859,7 +860,7 @@ class CCBY extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
@@ -880,6 +881,9 @@ class Misc extends React.Component {
|
||||
<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>
|
||||
</li>
|
||||
<li>
|
||||
<img src={VolcanoImg} /> Copyright <a href="https://thenounproject.com/Maludk/">Laymik</a> - <CCBY />
|
||||
</li>
|
||||
<li>
|
||||
<img src={CornImg} /> <img src={FruitImg} /> Copyright <a href='https://madexmade.com/'>Made</a> - <CCBY />
|
||||
</li>
|
||||
@@ -1090,6 +1094,7 @@ class Die extends React.Component {
|
||||
trigger = 0;
|
||||
decayFactorPct = 0.4;
|
||||
showScreenTimerId = false;
|
||||
rollIndex = 0;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -1107,12 +1112,16 @@ class Die extends React.Component {
|
||||
}
|
||||
|
||||
roll() {
|
||||
if (!this.props.rolls) {
|
||||
let roll = random(6);
|
||||
while (roll === this.lastRoll) {
|
||||
roll = random(6);
|
||||
}
|
||||
this.lastRoll = roll;
|
||||
return roll;
|
||||
} else {
|
||||
return this.props.rolls[++this.rollIndex];
|
||||
}
|
||||
}
|
||||
|
||||
tick = () => {
|
||||
@@ -1272,6 +1281,7 @@ class Rolling extends React.Component {
|
||||
return (
|
||||
<GroupBox title={this.props.name + ' is rolling!'}>
|
||||
<Die decay={true} num={this.props.num} ms={2000} roll={true}
|
||||
rolls={this.props.rolls}
|
||||
showScreen={this.props.showScreen}
|
||||
skip={this.props.skip}
|
||||
autoSkip={this.props.autoSkip}
|
||||
@@ -1354,6 +1364,7 @@ class Harvest extends React.Component {
|
||||
break;
|
||||
case 'roll':
|
||||
view = (<Die decay={true} num={this.props.rolled} ms={2000} roll={true}
|
||||
rolls={this.props.rolls}
|
||||
showScreen={() => this.nextView('income')}
|
||||
skip={this.props.player.name === this.props.game.currentPlayer}
|
||||
autoSkip={this.props.autoSkip === 'die'}
|
||||
@@ -1569,6 +1580,7 @@ class Action extends React.Component {
|
||||
break;
|
||||
case 'harvest':
|
||||
view = (<Harvest rolled={this.props.ui.actionValue.rolled}
|
||||
rolls={this.props.ui.actionValue.rolls}
|
||||
player={this.props.player}
|
||||
currentPlayer={currentPlayer}
|
||||
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.from - 49 : this.props.ui.actionValue.from);
|
||||
view = (<Rolling num={roll}
|
||||
rolls={this.props.ui.actionValue.rolls}
|
||||
name={this.props.game.currentPlayer}
|
||||
showScreen={(this.props.player.name === this.props.game.currentPlayer ||
|
||||
currentPlayer.ai)
|
||||
@@ -1764,14 +1777,16 @@ class AlertOverlay extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className={'alert-overlay' + (this.state.visible ? '' : ' hidden') }>
|
||||
{!this.props.preventHiding ? (
|
||||
<div onClick={this.hide} className='alert-overlay-hide'>
|
||||
<FontAwesomeIcon icon={faTimes} />
|
||||
</div>
|
||||
) : (<></>)}
|
||||
<div className='alert-overlay-contents'>
|
||||
{this.props.children}
|
||||
<br />
|
||||
<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>
|
||||
);
|
||||
@@ -2015,6 +2030,30 @@ class BoardApp extends React.Component {
|
||||
</Fragment>
|
||||
</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) {
|
||||
alertOverlay = (
|
||||
<AlertOverlay visible={true}
|
||||
|
||||
@@ -30,7 +30,8 @@ import { itemCard, fateCard } from 'game.js'
|
||||
|
||||
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||
submitTradeDeny, submitTradeCancel, audit, handleMessage,
|
||||
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn }
|
||||
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
|
||||
startGame }
|
||||
|
||||
let store;
|
||||
let movingTimer = 0;
|
||||
@@ -44,6 +45,13 @@ function handleMessage(evt) {
|
||||
return;
|
||||
}
|
||||
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 &&
|
||||
data.game.otherPlayers.length > 0 &&
|
||||
store.getState().farm.player.state !== GAME_STATES.preTurn) {
|
||||
@@ -186,6 +194,10 @@ function skip(component) {
|
||||
sendCommand({ type: 'skip', component });
|
||||
}
|
||||
|
||||
function startGame() {
|
||||
sendCommand({ type: 'start-game' });
|
||||
}
|
||||
|
||||
// TODO share with Board.jsx
|
||||
// http://stackoverflow.com/questions/149055
|
||||
function formatMoney(n) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
|
||||
import { startOrJoinGame } from '../start/actions.js'
|
||||
import { start } from '../app/actions.js'
|
||||
import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccount.jsx';
|
||||
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faArrowCircleLeft } from '@fortawesome/free-solid-svg-icons'
|
||||
@@ -36,7 +37,8 @@ class JoinGame extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
screen: JoinGameScreens.list,
|
||||
game: null
|
||||
game: null,
|
||||
showSignIn: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -54,12 +56,15 @@ class JoinGame extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleJoinAsExisting = e => {
|
||||
handleJoinAsExisting = (e, id) => {
|
||||
e.preventDefault();
|
||||
this.props.startOrJoinGame({ type: 'join-as-existing',
|
||||
playerName: e.target.text,
|
||||
gameId: this.state.game.id,
|
||||
gameName: this.state.game.name });
|
||||
gameId: id });
|
||||
}
|
||||
|
||||
showSignIn = (e) => {
|
||||
e.preventDefault();
|
||||
this.setState(state => { return { showSignIn: !state.showSignIn }; });
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -75,27 +80,44 @@ class JoinGame extends React.Component {
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
{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
|
||||
.map((g, i) =>
|
||||
(<li key={i}>
|
||||
<a onClick={(e) => this.handleJoinAsExisting(e, g.id)}>{g.name}</a>
|
||||
</li>))}
|
||||
</ul>
|
||||
<h3>Open Games</h3>
|
||||
<ul>
|
||||
{this.props.openGames
|
||||
.map((g, i) =>
|
||||
(<li key={i}>
|
||||
<a onClick={e => {
|
||||
e.preventDefault();
|
||||
this.handleClickGame(g); }}>{g.name}</a>
|
||||
</li>))}
|
||||
</ul>)
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
: (
|
||||
<Fragment>
|
||||
<h3><b>Game:</b> {this.state.game.name}</h3>
|
||||
<h4>Join as existing player:</h4>
|
||||
<ul>
|
||||
{this.state.game.players.map((p, i) =>
|
||||
(<li key={i}>
|
||||
<a onClick={this.handleJoinAsExisting}>
|
||||
{p}
|
||||
</a>
|
||||
</li>))}
|
||||
</ul>
|
||||
<NewGame colors={this.state.game.colors}
|
||||
button={'Join'}
|
||||
showGameName={false}
|
||||
@@ -103,6 +125,9 @@ class JoinGame extends React.Component {
|
||||
gameId={this.state.game.id}
|
||||
type={'join-game'}
|
||||
hideBack={true}
|
||||
createAccount={this.props.createAccount}
|
||||
login={this.props.login}
|
||||
errors={this.props.errors}
|
||||
title={'Join as New Player'} />
|
||||
</Fragment>)}
|
||||
</Col>
|
||||
|
||||
@@ -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 { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccount.jsx';
|
||||
|
||||
import { startOrJoinGame } from '../start/actions.js'
|
||||
import { start } from '../app/actions.js'
|
||||
@@ -53,7 +54,6 @@ class NewGame extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
showSettings: false,
|
||||
playerName: '',
|
||||
checkedColor: props.colors[0],
|
||||
gameId: typeof props.gameId === 'undefined' ? -1 : props.gameId,
|
||||
gameName: props.gameName || '',
|
||||
@@ -63,7 +63,8 @@ class NewGame extends React.Component {
|
||||
auditThreshold: 250000,
|
||||
startingCash: 5000,
|
||||
startingDebt: 5000,
|
||||
trade: true
|
||||
trade: true,
|
||||
showLogin: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -96,8 +97,7 @@ class NewGame extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let playerNameInput,
|
||||
titleBar = !this.props.hideBack ? (
|
||||
let titleBar = !this.props.hideBack ? (
|
||||
<Fragment>
|
||||
<a onClick={this.handleBack}>
|
||||
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
||||
@@ -129,18 +129,9 @@ class NewGame extends React.Component {
|
||||
mainScreenClass = !this.state.showSettings ? '' : 'hidden';
|
||||
return (
|
||||
<GroupBox title={titleBar}>
|
||||
{this.props.user ? (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className={mainScreenClass}>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>Your Name
|
||||
<input type='text' name='playerName'
|
||||
required
|
||||
value={this.state.playerName}
|
||||
onChange={this.handleInputChange} />
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>Your Color</label>
|
||||
@@ -214,12 +205,21 @@ class NewGame extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
) : (
|
||||
<>
|
||||
<span>Sign in or create account to continue</span>
|
||||
<LoginOrCreateAccount login={this.props.login}
|
||||
createAccount={this.props.createAccount}
|
||||
errors={this.props.errors}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</GroupBox>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
state => state.start.start,
|
||||
{ startOrJoinGame, start }
|
||||
)(NewGame)
|
||||
|
||||
@@ -17,4 +17,7 @@
|
||||
// <https://www.gnu.org/licenses/>.
|
||||
|
||||
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';
|
||||
|
||||
@@ -16,16 +16,32 @@
|
||||
// along with the Alpha Centauri Farming project. If not, see
|
||||
// <https://www.gnu.org/licenses/>.
|
||||
|
||||
import { SET_START_GAMES, START_OR_JOIN_GAME } from './actionTypes.js'
|
||||
import { 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) {
|
||||
return { type: SET_START_GAMES,
|
||||
games };
|
||||
}
|
||||
|
||||
function setOpenGames(games) {
|
||||
return { type: SET_OPEN_GAMES,
|
||||
games };
|
||||
}
|
||||
|
||||
function setUser(user) {
|
||||
return { type: SET_USER,
|
||||
user };
|
||||
}
|
||||
|
||||
function startOrJoinGame(msg) {
|
||||
return { type: START_OR_JOIN_GAME,
|
||||
msg };
|
||||
}
|
||||
|
||||
function setErrors(errors) {
|
||||
return { type: SET_ERRORS,
|
||||
errors };
|
||||
}
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
// along with the Alpha Centauri Farming project. If not, see
|
||||
// <https://www.gnu.org/licenses/>.
|
||||
|
||||
import { SET_START_GAMES, START_OR_JOIN_GAME } from './actionTypes.js'
|
||||
import { SET_START_GAMES, START_OR_JOIN_GAME, SET_USER, SET_OPEN_GAMES,
|
||||
SET_ERRORS } from './actionTypes.js'
|
||||
import { SCREENS } from '../../constants.js'
|
||||
|
||||
const initialState = {
|
||||
start: { games: [] },
|
||||
start: { games: [],
|
||||
openGames: [],
|
||||
errors: [],
|
||||
user: false },
|
||||
msg: null
|
||||
};
|
||||
|
||||
@@ -28,6 +32,12 @@ export default function(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case SET_START_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:
|
||||
return { ...state, msg: action.msg };
|
||||
default:
|
||||
|
||||
@@ -26,7 +26,8 @@ export const SCREENS = {
|
||||
|
||||
export const GAME_STATES = { preTurn: 'pre-turn',
|
||||
midTurn: 'mid-turn',
|
||||
turnEnded: 'turn-ended' };
|
||||
turnEnded: 'turn-ended',
|
||||
preGame: 'pre-game' };
|
||||
export const rootId = 'initial-element';
|
||||
export const messagePanelId = 'message-panel';
|
||||
export const ALERTS = { beginTurn: 'begin-turn',
|
||||
@@ -34,4 +35,5 @@ export const ALERTS = { beginTurn: 'begin-turn',
|
||||
endOfGame: 'end-of-game',
|
||||
auditCalled: 'audit-called',
|
||||
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 { 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 { createStore } from 'redux'
|
||||
import rootReducer from './rootReducers.js'
|
||||
@@ -46,9 +47,24 @@ document.body.appendChild(makeDiv(rootId));
|
||||
|
||||
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(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
<App createAccount={createAccount}
|
||||
login={login}
|
||||
logout={logout}
|
||||
/>
|
||||
</Provider>,
|
||||
document.getElementById(rootId)
|
||||
);
|
||||
@@ -78,6 +94,9 @@ function handleMessage(evt) {
|
||||
store.dispatch(play());
|
||||
} else if (data.event === 'start-init') {
|
||||
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 (data.games.games.length === 0) {
|
||||
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
|
||||
(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 "./")
|
||||
|
||||
(define (neq? a b) (not (eq? a b)))
|
||||
@@ -55,6 +82,7 @@
|
||||
(SRV:send-reply (pre-post-order* sxml rules)))))))
|
||||
|
||||
(define *game* (make-parameter #f))
|
||||
(define *player* (make-parameter #f))
|
||||
|
||||
(define-syntax safe-set!
|
||||
(ir-macro-transformer
|
||||
@@ -90,6 +118,7 @@
|
||||
(next-year-rules initform: '() accessor: player-next-year-rules)
|
||||
(color initform: #f accessor: player-color)
|
||||
(name initform: "PLAYER X" accessor: player-name)
|
||||
(user-id initform: #f accessor: player-user-id)
|
||||
(trade initform: '() accessor: player-trade)
|
||||
(last-updated initform: 0 accessor: player-last-updated)
|
||||
(last-cash initform: 5000 accessor: player-last-cash)
|
||||
@@ -114,7 +143,7 @@
|
||||
(colors initform: '() accessor: game-colors)
|
||||
(last-updated initform: 0 accessor: game-last-updated)
|
||||
(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)
|
||||
(turn initform: 1 accessor: game-turn)
|
||||
(current-player initform: #f accessor: game-current-player)
|
||||
@@ -154,6 +183,7 @@
|
||||
(next-year-rules . ,(player-next-year-rules player))
|
||||
(color . ,(player-color player))
|
||||
(name . ,(player-name player))
|
||||
(user-id . ,(player-user-id player))
|
||||
(trade . ())
|
||||
(last-updated . 0)
|
||||
(last-cash . ,(player-cash player))
|
||||
@@ -196,11 +226,11 @@
|
||||
*operating-expense-cards*)))
|
||||
'called-audit (if (alist-ref 'called-audit x)
|
||||
(find (lambda (p)
|
||||
(string=? (player-name p) (alist-ref 'called-audit x)))
|
||||
(equal? (player-name p) (alist-ref 'called-audit x)))
|
||||
players)
|
||||
#f)
|
||||
'current-player (find (lambda (p)
|
||||
(string=? (player-name p) (alist-ref 'current-player x)))
|
||||
(equal? (player-name p) (alist-ref 'current-player x)))
|
||||
players)
|
||||
(fold (lambda (k r) (cons k (cons (alist-ref k x) r)))
|
||||
'()
|
||||
@@ -221,6 +251,10 @@
|
||||
(lambda ()
|
||||
(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)
|
||||
(with-input-from-file "/home/tjhintz/app.scm"
|
||||
(lambda ()
|
||||
@@ -236,7 +270,7 @@
|
||||
(fold (lambda (k r) (cons k (cons (alist-ref k x) r)))
|
||||
'()
|
||||
'(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
|
||||
color name trade last-updated last-cash))))
|
||||
|
||||
@@ -310,13 +344,14 @@
|
||||
(safe-set! (game-colors game) (cdr (game-colors game)))
|
||||
color))
|
||||
|
||||
(define (add-player-to-game game color name)
|
||||
(define (add-player-to-game game color name user-id)
|
||||
(let ((player (make <player>
|
||||
'cash (game-setting 'starting-cash game)
|
||||
'display-cash (game-setting 'starting-cash game)
|
||||
'debt (game-setting 'starting-debt game)
|
||||
'color color
|
||||
'name name
|
||||
'user-id user-id
|
||||
'state (if (= (length (game-players game)) 0)
|
||||
'pre-turn 'turn-ended))))
|
||||
(safe-set! (game-players game) (append (game-players game) (list player)))
|
||||
@@ -441,6 +476,7 @@
|
||||
(player-otbs p))))
|
||||
(color . ,(symbol->string (player-color p)))
|
||||
(name . ,(player-name p))
|
||||
(user-id . ,(player-user-id p))
|
||||
(trade . ,(player-trade p))
|
||||
(lastCash . ,(player-last-cash p))
|
||||
(hayDoubled . ,(player-hay-doubled p))
|
||||
@@ -459,6 +495,7 @@
|
||||
(player-otbs p))))
|
||||
(color . ,(symbol->string (player-color p)))
|
||||
(name . ,(player-name p))
|
||||
(user-id . ,(player-user-id p))
|
||||
(trade . ,(player-trade p))
|
||||
(lastCash . ,(player-last-cash p))
|
||||
(hayDoubled . ,(player-hay-doubled p))
|
||||
@@ -535,13 +572,23 @@
|
||||
(define (finish-year player #!optional (collect-wages #t))
|
||||
(let ((game (*game*)))
|
||||
(when collect-wages
|
||||
(let* ((richest (car (sort (game-players game)
|
||||
(lambda (p1 p2)
|
||||
(> (player-net-worth p1)
|
||||
(player-net-worth p2))))))
|
||||
(bonus (max (farming-round
|
||||
(* (- (player-net-worth richest)
|
||||
(player-net-worth player))
|
||||
0.2))
|
||||
2500)))
|
||||
(safe-set! (player-cash player)
|
||||
(+ (player-cash player) 5000))
|
||||
;; (+ (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 . "You earned $5,000 from your city job!"))
|
||||
(game-actions game))))
|
||||
(cons `((?action . info)
|
||||
(?value . ,(conc "You earned $" bonus " from your city job!")))
|
||||
(game-actions game)))))
|
||||
(when (game-called-audit game)
|
||||
(safe-set! (game-actions game)
|
||||
(append (game-actions game)
|
||||
@@ -810,7 +857,7 @@
|
||||
(player->list player)
|
||||
(game->list (*game*) player)))
|
||||
|
||||
(define (create-start-response event)
|
||||
(define (create-start-response event #!key (errors '()))
|
||||
`((event . ,event)
|
||||
(games . ((games . ,(list->vector
|
||||
(map (lambda (game)
|
||||
@@ -820,7 +867,24 @@
|
||||
(map symbol->string (game-colors game))))
|
||||
(players . ,(list->vector
|
||||
(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"))
|
||||
(for-each (lambda (p)
|
||||
(when (not (eq? p player))
|
||||
@@ -855,13 +919,35 @@
|
||||
(safe-set! (player-display-cash player) (player-cash player)))
|
||||
(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)
|
||||
(when game
|
||||
(safe-set! (game-messages game) '())
|
||||
(when player
|
||||
(safe-set! (player-last-cash player) (player-cash player)))
|
||||
(print "message type: " type)
|
||||
(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*))
|
||||
(safe-set! (player-previous-space player)
|
||||
(player-space player))
|
||||
@@ -876,7 +962,8 @@
|
||||
(finish-year player))
|
||||
(safe-set! (player-harvest-mult player) 1)
|
||||
(let ((resp `((from . ,(player-previous-space player))
|
||||
(to . ,(player-space player)))))
|
||||
(to . ,(player-space player))
|
||||
(rolls . ,(list->vector rolls)))))
|
||||
(safe-set! (game-actions game)
|
||||
(append (game-actions game)
|
||||
`(((?action . move) (?value . ,resp))
|
||||
@@ -1169,7 +1256,7 @@
|
||||
(print exn)
|
||||
(print-error-message exn)
|
||||
(print "error saving app"))
|
||||
(save-app))
|
||||
(save-game game))
|
||||
(if (eq? (game-state game) 'finished)
|
||||
(do-end-of-game game)
|
||||
(message-players! game player '() type: "update"))
|
||||
@@ -1180,6 +1267,7 @@
|
||||
(create-start-response "start-init"))
|
||||
((string=? type "new-game")
|
||||
(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)
|
||||
'(green red blue yellow black))
|
||||
'name (alist-ref 'gameName msg)
|
||||
@@ -1200,49 +1288,81 @@
|
||||
(trade . ,(or (alist-ref 'trade msg) #t)))))
|
||||
(player (add-player-to-game game
|
||||
color
|
||||
(alist-ref 'playerName msg)))
|
||||
(alist-ref 'username user)
|
||||
(alist-ref 'id user)))
|
||||
;; (ai-player (add-ai-to-game game 'red "AI Player 1"))
|
||||
)
|
||||
(push! game (app-games *app*))
|
||||
(session-set! (sid) 'player player)
|
||||
(session-set! (sid) 'game game)
|
||||
(let ((gid (db-add-game "pre-game" (game->sexp 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)
|
||||
(*player* player)
|
||||
(set-startup-otbs game player 2)
|
||||
;; (set-startup-otbs game ai-player 2)
|
||||
;; (thread-start! (make-ai-push-receiver game ai-player))
|
||||
(create-start-response "new-game-started")))
|
||||
((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))
|
||||
(game (find (lambda (g) (= (game-id g) id))
|
||||
(app-games *app*)))
|
||||
(game (find-game id))
|
||||
(color-raw (string->symbol (alist-ref 'checkedColor msg)))
|
||||
(color (if (not (member color-raw (game-colors game)))
|
||||
(car (game-colors game))
|
||||
color-raw))
|
||||
(player (add-player-to-game game
|
||||
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)))
|
||||
(session-set! (sid) 'player player)
|
||||
(session-set! (sid) 'game game)
|
||||
(session-set! (sid) 'game-id (game-id game))
|
||||
(db-add-user-game (alist-ref 'id user) (game-id game))
|
||||
(*game* game)
|
||||
(*player* player)
|
||||
(set-startup-otbs game player 2)
|
||||
(message-players! game player '() type: "update")
|
||||
(create-start-response "new-game-started")))
|
||||
((string=? type "join-as-existing")
|
||||
(let* ((name (alist-ref 'gameName msg))
|
||||
(pname (alist-ref 'playerName msg))
|
||||
(id (alist-ref 'gameId msg))
|
||||
(game (find (lambda (g) (= (game-id g) id))
|
||||
(app-games *app*)))
|
||||
(player (find (lambda (p) (string=? (player-name p) pname))
|
||||
(let* ((id (alist-ref 'gameId msg))
|
||||
(user-id (session-ref (sid) 'user-id))
|
||||
(game (find-game id))
|
||||
(player (find (lambda (p) (equal? (player-user-id p) user-id))
|
||||
(game-players game))))
|
||||
(session-set! (sid) 'player player)
|
||||
(session-set! (sid) 'game game)
|
||||
(*game* game)
|
||||
(*player* player)
|
||||
(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)
|
||||
(print (player-name player))
|
||||
@@ -1297,6 +1417,18 @@
|
||||
(process-ai-push-message player game msg)
|
||||
(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)
|
||||
(sid (read-cookie (session-cookie-name)))
|
||||
;; TODO some kind of error handling if (sid) #f
|
||||
@@ -1321,16 +1453,28 @@
|
||||
(print-call-chain)
|
||||
(print-error-message exn))))
|
||||
(event . "error"))
|
||||
(let* ((game (session-ref (sid) 'game #f))
|
||||
(player (session-ref (sid) 'player #f))
|
||||
(res (process-message player
|
||||
(session-game)
|
||||
(let* ((game (*game*))
|
||||
(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)))))
|
||||
(when (*player*)
|
||||
(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)))))))
|
||||
|
||||
(define (push-websocket-page)
|
||||
@@ -1338,15 +1482,9 @@
|
||||
;; TODO some kind of error handling if (sid) #f
|
||||
(with-concurrent-websocket
|
||||
(lambda ()
|
||||
(let ((game (session-ref (sid) 'game))
|
||||
(player (session-ref (sid) 'player)))
|
||||
(*game* game)
|
||||
(let loop ((msg (mailbox-receive! (player-mailbox player))))
|
||||
(print msg)
|
||||
(when (not game)
|
||||
(set! game (session-ref (sid) 'game)))
|
||||
(when (not player)
|
||||
(set! player (session-ref (sid) 'player)))
|
||||
(session-game)
|
||||
(let loop ((msg (mailbox-receive! (player-mailbox (*player*)))))
|
||||
(session-game)
|
||||
;; when (< (player-last-updated player)
|
||||
;; (game-last-updated game))
|
||||
(handle-exceptions
|
||||
@@ -1366,11 +1504,11 @@
|
||||
(print-call-chain)
|
||||
(print-error-message exn))))
|
||||
(event . "error"))
|
||||
(create-ws-response player
|
||||
(create-ws-response (*player*)
|
||||
(alist-ref 'type msg)
|
||||
(alist-ref 'value msg))
|
||||
))))
|
||||
(loop (mailbox-receive! (player-mailbox player))))))))
|
||||
(loop (mailbox-receive! (player-mailbox (*player*))))))))
|
||||
|
||||
(define (otb-spec->otb-cards spec id)
|
||||
`((contents . ,(sxml->html* (list-ref spec 5)))
|
||||
@@ -2034,6 +2172,7 @@
|
||||
(game-players game)))))
|
||||
((alist-ref 'action operating-expense) player)
|
||||
`((rolled . ,rolled)
|
||||
(rolls . ,(list->vector (make-rolls 22)))
|
||||
(income . ,income)
|
||||
(harvestMult . ,harvest-mult)
|
||||
(operatingExpense . ,(alist-ref 'contents operating-expense))
|
||||
|
||||
@@ -141,6 +141,8 @@ $tab-margin: 0.3rem;
|
||||
align-items: center; }
|
||||
|
||||
.view-container {
|
||||
max-height: 90vh;
|
||||
overflow: auto;
|
||||
border: 0.3rem solid $dark-color;
|
||||
background: linear-gradient(180deg, $light-color 0%, $orange-color 100%);
|
||||
padding: 1rem;
|
||||
@@ -919,3 +921,75 @@ $intro-time: 6s;
|
||||
|
||||
.pad-right {
|
||||
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 {
|
||||
location = '';
|
||||
fullPath = '';
|
||||
reopen = true;
|
||||
onmessageProc = () => 'nothing'
|
||||
ws = null;
|
||||
|
||||
constructor(location) {
|
||||
@@ -35,6 +37,7 @@ class WebSocketConnection {
|
||||
uri = "ws:";
|
||||
}
|
||||
uri += "//" + loc.host;
|
||||
this.fullPath = uri + '/websocket/' + location;
|
||||
this.ws = new WebSocket(uri + '/websocket/' + location);
|
||||
}
|
||||
|
||||
@@ -47,8 +50,17 @@ class WebSocketConnection {
|
||||
this.ws.send(JSON.stringify(cmd));
|
||||
}
|
||||
|
||||
reestablish = () => {
|
||||
this.ws = new WebSocket(this.fullPath);
|
||||
this.ws.onmessage = this.onmessageProc;
|
||||
}
|
||||
|
||||
onmessage(proc) {
|
||||
this.onmessageProc = proc;
|
||||
this.ws.onmessage = proc;
|
||||
// this.ws.onclose = () => {
|
||||
// setTimeout(this.reestablish, 500);
|
||||
// }
|
||||
}
|
||||
|
||||
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: [
|
||||
'file-loader',
|
||||
],
|
||||
|
||||