Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 945011c052 | |||
| c764b63d10 | |||
| a4c41785ce | |||
| 526c4ae365 | |||
| 9fdbcc34f9 | |||
| 17723fc52c | |||
| 1b9e94ba1f | |||
| 191a6081b7 | |||
| 3a97c128b6 | |||
| b2d0dc3268 | |||
| a38c55e877 | |||
| 6219e65e66 | |||
| 92eb1d9653 | |||
| dd644387f1 | |||
| 4cbfe0b394 | |||
| 5609720876 | |||
| cb983ae1c9 | |||
| 99b60b5aba | |||
| ce0070ed7e | |||
| 9160fdc92a | |||
| 802a0efcbb | |||
| 856ab034d5 | |||
| 11361fd814 | |||
| b22aea2507 | |||
| 70ed9465b8 | |||
| 1f5b1e1eae | |||
| 48b178327b | |||
| fbc8706893 | |||
| db47e5e6e9 | |||
| 250fdb9ca7 | |||
| d6692bc64d | |||
| ae8d0d8193 | |||
| bea133bee4 | |||
| c34fc7dcbe | |||
| 2599c6fa33 | |||
| 90f4e959cd | |||
| 54ec20ab6b | |||
| 2f770d2d63 | |||
| a5c13d40eb | |||
| f43d9e5d19 | |||
| 80399ac7b1 | |||
| a066a507ef | |||
| 8893a50596 | |||
| 2a6a0b038e | |||
| 7ba6f19133 | |||
| 70d8b50ac3 | |||
| b06d1b4513 | |||
| ced8faf6f6 | |||
| afd548ae0b | |||
| 775ec7ed70 | |||
| 333bd70d1a | |||
| 197e4ffc5d |
3
.babelrc
3
.babelrc
@@ -21,5 +21,6 @@
|
|||||||
"@babel/preset-react"
|
"@babel/preset-react"
|
||||||
],
|
],
|
||||||
"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }],
|
"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }],
|
||||||
"@babel/plugin-proposal-class-properties"]
|
"@babel/plugin-proposal-class-properties",
|
||||||
|
"emotion"]
|
||||||
}
|
}
|
||||||
|
|||||||
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/node_modules/
|
||||||
|
/node_modules_bak/
|
||||||
|
/dist/
|
||||||
|
*~
|
||||||
|
/src/server/farm
|
||||||
58
Dockerfile
Normal file
58
Dockerfile
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
FROM alpine as chicken
|
||||||
|
|
||||||
|
ENV CHICKEN_VERSION 4.11.0
|
||||||
|
ENV PLATFORM linux
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
apk update; \
|
||||||
|
apk --no-cache --update add build-base; \
|
||||||
|
wget -qO- https://code.call-cc.org/releases/${CHICKEN_VERSION}/chicken-${CHICKEN_VERSION}.tar.gz | tar xzv; \
|
||||||
|
cd /chicken-${CHICKEN_VERSION}; \
|
||||||
|
make PLATFORM=${PLATFORM}; \
|
||||||
|
make PLATFORM=${PLATFORM} install; \
|
||||||
|
make PLATFORM=${PLATFORM} check; \
|
||||||
|
cd /; \
|
||||||
|
rm -rf /chicken-${CHICKEN_VERSION}
|
||||||
|
|
||||||
|
FROM chicken as deps
|
||||||
|
RUN chicken-install http-session srfi-69 coops uri-common srfi-18 medea numbers spiffy spiffy-cookies sql-de-lite crypt intarweb sxml-transforms websockets miscmacros
|
||||||
|
|
||||||
|
FROM deps as deps2
|
||||||
|
RUN chicken-install -r pll; \
|
||||||
|
cd pll; \
|
||||||
|
sed -i '1s/^/(import scheme)\n/' amb.scm; \
|
||||||
|
chicken-install
|
||||||
|
|
||||||
|
FROM deps2 as compat
|
||||||
|
RUN apk --no-cache --update add libc6-compat
|
||||||
|
|
||||||
|
FROM node:16 as node
|
||||||
|
WORKDIR /farm
|
||||||
|
# COPY ./ /farm
|
||||||
|
COPY package.json package.json
|
||||||
|
COPY package-lock.json package-lock.json
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
FROM node as buildfe
|
||||||
|
WORKDIR /farm
|
||||||
|
COPY ./ /farm
|
||||||
|
RUN make prodfe
|
||||||
|
|
||||||
|
FROM compat as buildfarm
|
||||||
|
WORKDIR /farm
|
||||||
|
COPY ./ /farm
|
||||||
|
RUN make farm
|
||||||
|
|
||||||
|
FROM buildfarm as farm
|
||||||
|
WORKDIR /farm
|
||||||
|
RUN mkdir dist
|
||||||
|
COPY --from=buildfe /farm/dist /farm/dist
|
||||||
|
RUN cp src/server/farm dist/; \
|
||||||
|
chmod +x dist/farm
|
||||||
|
|
||||||
|
FROM farm as run
|
||||||
|
WORKDIR /farm/dist
|
||||||
|
ENTRYPOINT ["./farm"]
|
||||||
|
CMD ["-:a50"]
|
||||||
|
# CMD ./farm
|
||||||
|
|
||||||
24
Makefile
24
Makefile
@@ -17,38 +17,54 @@
|
|||||||
# along with the Alpha Centauri Farming project. If not, see
|
# along with the Alpha Centauri Farming project. If not, see
|
||||||
# <https://www.gnu.org/licenses/>.
|
# <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
.PHONY: clean install interactive
|
.PHONY: clean install interactive cypress
|
||||||
|
|
||||||
assets := assets/game/acf/
|
assets := assets/game/acf/
|
||||||
|
|
||||||
|
docker:
|
||||||
|
sudo docker build --network=host . -t farm
|
||||||
|
|
||||||
dev:
|
dev:
|
||||||
npx webpack --config webpack.dev.js --env.assets ./$(assets)
|
npx webpack --config webpack.dev.js --env.assets ./$(assets)
|
||||||
|
|
||||||
rundev:
|
rundev:
|
||||||
|
webpack-dev-server --open --config webpack.dev.js --env.assets ./$(assets)
|
||||||
|
# make interactive
|
||||||
|
|
||||||
|
rundevserver:
|
||||||
make interactive
|
make interactive
|
||||||
|
|
||||||
prod: src/server/farm
|
prod: src/server/farm
|
||||||
npx webpack --config webpack.prod.js --env.assets ./$(assets)
|
npx webpack --config webpack.prod.js --env.assets ./$(assets)
|
||||||
|
|
||||||
|
prodfe:
|
||||||
|
npx webpack --config webpack.prod.js --env.assets ./$(assets)
|
||||||
|
|
||||||
install:
|
install:
|
||||||
npm init -y
|
npm init -y
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
interactive:
|
interactive:
|
||||||
cd dist/ && csi -include-path $(assets) -include-path ../src/server -s farm.scm
|
csi -include-path $(assets) -include-path src/server -s src/server/farm.scm
|
||||||
|
|
||||||
src/server/farm: src/server/farm.scm
|
interactiveserver:
|
||||||
|
cd dist ; csi -include-path $(assets) -include-path ../src/server -s farm.scm
|
||||||
|
|
||||||
|
src/server/farm: src/server/farm.scm src/server/db.scm
|
||||||
cd src/server/ && csc -include-path ../../$(assets) -O3 farm.scm
|
cd src/server/ && csc -include-path ../../$(assets) -O3 farm.scm
|
||||||
|
|
||||||
farm:
|
farm:
|
||||||
make src/server/farm
|
make src/server/farm
|
||||||
|
|
||||||
runprod:
|
runprod:
|
||||||
cd dist/ && chmod +x farm && ./farm
|
cd dist/ && chmod +x farm && ./farm -:a50
|
||||||
|
|
||||||
upload:
|
upload:
|
||||||
rsync -rtvz dist/ $(SERVER):~/farm
|
rsync -rtvz dist/ $(SERVER):~/farm
|
||||||
|
|
||||||
|
cypress:
|
||||||
|
npm run cypress:open
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *~ res/js/app.js
|
rm -f *~ res/js/app.js
|
||||||
|
|
||||||
|
|||||||
BIN
assets/font/IndieFlower-Regular.ttf
Normal file
BIN
assets/font/IndieFlower-Regular.ttf
Normal file
Binary file not shown.
BIN
assets/font/IndieFlower-Regular.woff
Normal file
BIN
assets/font/IndieFlower-Regular.woff
Normal file
Binary file not shown.
BIN
assets/font/IndieFlower-Regular.woff2
Normal file
BIN
assets/font/IndieFlower-Regular.woff2
Normal file
Binary file not shown.
BIN
assets/font/LibreBaskerville-Regular.ttf
Normal file
BIN
assets/font/LibreBaskerville-Regular.ttf
Normal file
Binary file not shown.
BIN
assets/font/LibreBaskerville-Regular.woff
Normal file
BIN
assets/font/LibreBaskerville-Regular.woff
Normal file
Binary file not shown.
BIN
assets/font/LibreBaskerville-Regular.woff2
Normal file
BIN
assets/font/LibreBaskerville-Regular.woff2
Normal file
Binary file not shown.
BIN
assets/font/LibreBaskerville-Regular.zip
Normal file
BIN
assets/font/LibreBaskerville-Regular.zip
Normal file
Binary file not shown.
BIN
assets/font/Libre_Baskerville.zip
Normal file
BIN
assets/font/Libre_Baskerville.zip
Normal file
Binary file not shown.
BIN
assets/font/Libre_Baskerville/LibreBaskerville-Bold.ttf
Normal file
BIN
assets/font/Libre_Baskerville/LibreBaskerville-Bold.ttf
Normal file
Binary file not shown.
BIN
assets/font/Libre_Baskerville/LibreBaskerville-Italic.ttf
Normal file
BIN
assets/font/Libre_Baskerville/LibreBaskerville-Italic.ttf
Normal file
Binary file not shown.
BIN
assets/font/Libre_Baskerville/LibreBaskerville-Regular.ttf
Normal file
BIN
assets/font/Libre_Baskerville/LibreBaskerville-Regular.ttf
Normal file
Binary file not shown.
94
assets/font/Libre_Baskerville/OFL.txt
Normal file
94
assets/font/Libre_Baskerville/OFL.txt
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
Copyright (c) 2012, Pablo Impallari (www.impallari.com|impallari@gmail.com),
|
||||||
|
Copyright (c) 2012, Rodrigo Fuenzalida (www.rfuenzalida.com|hello<6C>rfuenzalida.com), with Reserved Font Name Libre Baskerville.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
93
assets/font/OFL.txt
Normal file
93
assets/font/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright (c) 2010, Kimberly Geswein (kimberlygeswein.com)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
BIN
assets/font/fonts/LibreBaskerville-Regular.woff
Normal file
BIN
assets/font/fonts/LibreBaskerville-Regular.woff
Normal file
Binary file not shown.
BIN
assets/font/fonts/LibreBaskerville-Regular.woff2
Normal file
BIN
assets/font/fonts/LibreBaskerville-Regular.woff2
Normal file
Binary file not shown.
@@ -47,7 +47,7 @@
|
|||||||
"20 Cows on Peridier Ridge"))))
|
"20 Cows on Peridier Ridge"))))
|
||||||
|
|
||||||
(define *ff-text*
|
(define *ff-text*
|
||||||
'(((p (img (@ (src "53c3a93b0867eee67b9b9f6ebc4c1f4a.gif") (style "float: left;"))) "Natural Disaster--The Solar Winds break through the atmosphere. You are luckily shielded by Mt Proctor. Your hay survives and jumps in price. " (b "COLLECT $500 per Hay acre") ". To see if they escaped, other players must roll. Odd: escaped, Even: hit. " (b "Wind hit players must clean up all acres at $100 per acre.")))
|
'(((p (img (@ (src "./assets/img/volcano2.53c3a93b0867eee67b9b9f6ebc4c1f4a.gif") (style "float: left;"))) "Natural Disaster--The Solar Winds break through the atmosphere. You are luckily shielded by Mt Proctor. Your hay survives and jumps in price. " (b "COLLECT $500 per Hay acre") ". To see if they escaped, other players must roll. Odd: escaped, Even: hit. " (b "Wind hit players must clean up all acres at $100 per acre.")))
|
||||||
((p "Planetary Disaster Fund comes through." (p (b "COLLECT $100 per Grain acre."))))
|
((p "Planetary Disaster Fund comes through." (p (b "COLLECT $100 per Grain acre."))))
|
||||||
((p "Another high wind spring and your wheat didn't get sprayed. Weeds take over and cut your harvest in half. Hold this card through Wheat Harvest for this year."))
|
((p "Another high wind spring and your wheat didn't get sprayed. Weeds take over and cut your harvest in half. Hold this card through Wheat Harvest for this year."))
|
||||||
((p "Kept back some of your cows and Proxima B steak goes viral.") (p (b "COLLECT $2,000 if you have cows.")))
|
((p "Kept back some of your cows and Proxima B steak goes viral.") (p (b "COLLECT $2,000 if you have cows.")))
|
||||||
|
|||||||
45
assets/img/cake.svg
Normal file
45
assets/img/cake.svg
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 80.125 79.983627"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg4786"
|
||||||
|
sodipodi:docname="cake.svg"
|
||||||
|
width="80.125"
|
||||||
|
height="79.983627"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
|
||||||
|
id="metadata4792"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs4790" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1375"
|
||||||
|
id="namedview4788"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="9.424"
|
||||||
|
inkscape:cx="40.23"
|
||||||
|
inkscape:cy="27.714"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg4786" /><path
|
||||||
|
d="M 79.125,21.572625 H 62.26 v -7.523 c 2.469,-0.565 4.319,-2.775 4.319,-5.4129999 0,-2.758 -4.007,-7.411 -4.811,-8.31599999 -0.379,-0.428 -1.116,-0.427 -1.496,0 -0.803,0.90499999 -4.81,5.55899999 -4.81,8.31599999 0,2.8059999 2.092,5.1269999 4.798,5.4989999 v 7.437 H 48.247 v -7.523 c 2.469,-0.565 4.319,-2.775 4.319,-5.4129999 0,-2.758 -4.007,-7.411 -4.811,-8.31599999 -0.38,-0.428 -1.116,-0.427 -1.496,0 -0.803,0.90499999 -4.81,5.55899999 -4.81,8.31599999 0,2.8059999 2.092,5.1269999 4.798,5.4989999 v 7.437 H 34.233 v -7.523 c 2.469,-0.565 4.319,-2.775 4.319,-5.4129999 0,-2.758 -4.007,-7.411 -4.811,-8.31599999 -0.379,-0.428 -1.116,-0.427 -1.496,0 -0.803,0.90499999 -4.81,5.55899999 -4.81,8.31599999 0,2.8059999 2.092,5.1269999 4.798,5.4989999 v 7.437 H 20.219 v -7.523 c 2.469,-0.565 4.319,-2.775 4.319,-5.4129999 0,-2.758 -4.007,-7.411 -4.811,-8.31599999 -0.38,-0.428 -1.116,-0.427 -1.496,0 -0.803,0.90499999 -4.81,5.55899999 -4.81,8.31599999 0,2.8059999 2.092,5.1269999 4.798,5.4989999 v 7.437 H 1.129 c -0.552,0 -1,0.447 -1,1 v 8.891 c 0,0.062 0.006,0.123 0.017,0.182 0.062,3.042 1.68,5.705 4.084,7.237 v 26.175 H 3.543 c -1.954,0 -3.543,1.59 -3.543,3.543 v 2.023 c 0,1.683 1.181,3.089 2.757,3.449 0.007,0.027 0.002,0.054 0.012,0.081 l 1.717,4.771 c 0.254,0.702 1.133,1.059 2.613,1.059 h 65.803 c 1.48,0 2.359,-0.356 2.613,-1.06 l 1.717,-4.771 c 0.01,-0.027 0.005,-0.054 0.012,-0.081 1.575,-0.36 2.756,-1.766 2.756,-3.449 v -2.023 c 0,-1.953 -1.589,-3.543 -3.543,-3.543 H 75.77 v -26.013 c 2.601,-1.53 4.355,-4.351 4.355,-7.581 v -8.891 c 0,-0.552 -0.448,-0.999 -1,-0.999 z M 57.462,8.6356251 c 0,-1.337 1.953,-4.153 3.558,-6.11 1.668,2.035 3.559,4.833 3.559,6.11 0,1.9619999 -1.596,3.5579999 -3.559,3.5579999 -1.961,0 -3.558,-1.596 -3.558,-3.5579999 z m -14.013,0 c 0,-1.337 1.953,-4.153 3.558,-6.11 1.668,2.035 3.559,4.833 3.559,6.11 0,1.9619999 -1.596,3.5579999 -3.559,3.5579999 -1.962,0 -3.558,-1.596 -3.558,-3.5579999 z m -14.014,0 c 0,-1.337 1.953,-4.153 3.558,-6.11 1.668,2.035 3.559,4.833 3.559,6.11 0,1.9619999 -1.596,3.5579999 -3.559,3.5579999 -1.962,0 -3.558,-1.596 -3.558,-3.5579999 z m -14.014,0 c 0,-1.337 1.953,-4.153 3.558,-6.11 1.668,2.035 3.559,4.833 3.559,6.11 0,1.9619999 -1.596,3.5579999 -3.559,3.5579999 -1.961,0 -3.558,-1.596 -3.558,-3.5579999 z M 72.901,77.983625 H 7.099 c -0.38,0 -0.672,-0.038 -0.854,-0.077 l -1.346,-3.739 h 70.202 l -1.346,3.739 c -0.181,0.039 -0.474,0.077 -0.854,0.077 z m 5.099,-9.384 v 2.023 c 0,0.852 -0.692,1.544 -1.543,1.544 H 3.543 c -0.851,0 -1.543,-0.692 -1.543,-1.544 v -2.023 c 0,-0.851 0.692,-1.543 1.543,-1.543 h 72.914 c 0.851,0 1.543,0.692 1.543,1.543 z m -4.23,-3.543 H 6.23 v -25.229 c 0.855,0.278 1.765,0.433 2.712,0.433 3.383,0 6.327,-1.919 7.798,-4.727 1.472,2.808 4.415,4.727 7.798,4.727 3.383,0 6.327,-1.919 7.798,-4.727 1.472,2.808 4.415,4.727 7.798,4.727 3.383,0 6.327,-1.919 7.798,-4.727 1.472,2.808 4.415,4.727 7.798,4.727 3.383,0 6.326,-1.919 7.798,-4.727 1.472,2.808 4.415,4.727 7.798,4.727 0.848,0 1.666,-0.127 2.442,-0.352 v 25.148 z m 4.355,-33.594 c 0,3.748 -3.049,6.798 -6.798,6.798 -3.749,0 -6.798,-3.05 -6.798,-6.798 0,-0.553 -0.448,-1 -1,-1 -0.552,0 -1,0.447 -1,1 0,3.748 -3.049,6.798 -6.798,6.798 -3.749,0 -6.798,-3.05 -6.798,-6.798 0,-0.553 -0.448,-1 -1,-1 -0.552,0 -1,0.447 -1,1 0,3.748 -3.05,6.798 -6.798,6.798 -3.748,0 -6.798,-3.05 -6.798,-6.798 0,-0.553 -0.448,-1 -1,-1 -0.552,0 -1,0.447 -1,1 0,3.748 -3.05,6.798 -6.798,6.798 -3.748,0 -6.798,-3.05 -6.798,-6.798 0,-0.553 -0.448,-1 -1,-1 -0.552,0 -1,0.447 -1,1 0,3.748 -3.05,6.798 -6.798,6.798 -3.748,0 -6.798,-3.05 -6.798,-6.798 0,-0.059 -0.005,-0.116 -0.015,-0.172 v -7.719 h 75.996 v 7.891 z"
|
||||||
|
id="path4780"
|
||||||
|
inkscape:connector-curvature="0" /></svg>
|
||||||
|
After Width: | Height: | Size: 5.1 KiB |
BIN
assets/img/mars-texture-clipped.png
Normal file
BIN
assets/img/mars-texture-clipped.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
3
cypress.json
Normal file
3
cypress.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"baseUrl": "http://localhost:8080"
|
||||||
|
}
|
||||||
5
cypress/fixtures/example.json
Normal file
5
cypress/fixtures/example.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Using fixtures to represent data",
|
||||||
|
"email": "hello@cypress.io",
|
||||||
|
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||||
|
}
|
||||||
25
cypress/integration/sample_spec.js
Normal file
25
cypress/integration/sample_spec.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
describe('My First Test', () => {
|
||||||
|
it('Visits the Kitchen Sink', () => {
|
||||||
|
cy.visit('/')
|
||||||
|
|
||||||
|
cy.contains('Begin').click()
|
||||||
|
|
||||||
|
cy.contains('New Game').click()
|
||||||
|
|
||||||
|
cy.contains('Login').click()
|
||||||
|
|
||||||
|
cy.get('form [name="username"]').type('test')
|
||||||
|
cy.get('form [name="password"]').type('food')
|
||||||
|
cy.get('button[type="submit"]').click()
|
||||||
|
|
||||||
|
cy.get('form [name="gameName"]').type('test')
|
||||||
|
cy.get('button[type="submit"]').click()
|
||||||
|
|
||||||
|
cy.get('span[class="add-ai"]').click()
|
||||||
|
|
||||||
|
cy.contains('Ready to start').click()
|
||||||
|
cy.contains('Start Game').click()
|
||||||
|
|
||||||
|
cy.get('.show .action-item').first().click()
|
||||||
|
})
|
||||||
|
})
|
||||||
21
cypress/plugins/index.js
Normal file
21
cypress/plugins/index.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
// ***********************************************************
|
||||||
|
// This example plugins/index.js can be used to load plugins
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off loading
|
||||||
|
// the plugins file with the 'pluginsFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/plugins-guide
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// This function is called when a project is opened or re-opened (e.g. due to
|
||||||
|
// the project's config changing)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Cypress.PluginConfig}
|
||||||
|
*/
|
||||||
|
module.exports = (on, config) => {
|
||||||
|
// `on` is used to hook into various events Cypress emits
|
||||||
|
// `config` is the resolved Cypress config
|
||||||
|
}
|
||||||
25
cypress/support/commands.js
Normal file
25
cypress/support/commands.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// ***********************************************
|
||||||
|
// This example commands.js shows you how to
|
||||||
|
// create various custom commands and overwrite
|
||||||
|
// existing commands.
|
||||||
|
//
|
||||||
|
// For more comprehensive examples of custom
|
||||||
|
// commands please read more here:
|
||||||
|
// https://on.cypress.io/custom-commands
|
||||||
|
// ***********************************************
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a parent command --
|
||||||
|
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a child command --
|
||||||
|
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a dual command --
|
||||||
|
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This will overwrite an existing command --
|
||||||
|
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||||
20
cypress/support/index.js
Normal file
20
cypress/support/index.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// ***********************************************************
|
||||||
|
// This example support/index.js is processed and
|
||||||
|
// loaded automatically before your test files.
|
||||||
|
//
|
||||||
|
// This is a great place to put global configuration and
|
||||||
|
// behavior that modifies Cypress.
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off
|
||||||
|
// automatically serving support files with the
|
||||||
|
// 'supportFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/configuration
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// Import commands.js using ES2015 syntax:
|
||||||
|
import './commands'
|
||||||
|
|
||||||
|
// Alternatively you can use CommonJS syntax:
|
||||||
|
// require('./commands')
|
||||||
22411
package-lock.json
generated
22411
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@@ -2,6 +2,8 @@
|
|||||||
"name": "farm",
|
"name": "farm",
|
||||||
"sideEffects": [
|
"sideEffects": [
|
||||||
"*.css",
|
"*.css",
|
||||||
|
"*.scss",
|
||||||
|
"*.ttf",
|
||||||
"*.woff",
|
"*.woff",
|
||||||
"*.woff2"
|
"*.woff2"
|
||||||
],
|
],
|
||||||
@@ -11,7 +13,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build": "webpack --config webpack.dev.js",
|
"build": "webpack --config webpack.dev.js",
|
||||||
"prod": "webpack --config webpack.prod.js"
|
"prod": "webpack --config webpack.prod.js",
|
||||||
|
"cypress:open": "cypress open"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
@@ -22,35 +25,39 @@
|
|||||||
"@babel/plugin-proposal-decorators": "^7.8.3",
|
"@babel/plugin-proposal-decorators": "^7.8.3",
|
||||||
"@babel/preset-env": "^7.8.3",
|
"@babel/preset-env": "^7.8.3",
|
||||||
"@babel/preset-react": "^7.8.3",
|
"@babel/preset-react": "^7.8.3",
|
||||||
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.1",
|
||||||
"autoprefixer": "^9.7.4",
|
"autoprefixer": "^9.7.4",
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-plugin-transform-decorators-legacy": "^1.3.5",
|
"babel-plugin-transform-decorators-legacy": "^1.3.5",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"copy-webpack-plugin": "^5.1.1",
|
"copy-webpack-plugin": "^5.1.1",
|
||||||
"css-loader": "^3.4.2",
|
"css-loader": "^3.4.2",
|
||||||
"favicons-webpack-plugin": "^2.1.0",
|
"css-url-relative-plugin": "^1.0.0",
|
||||||
|
"cypress": "^4.4.1",
|
||||||
"file-loader": "^4.3.0",
|
"file-loader": "^4.3.0",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"mini-css-extract-plugin": "^0.8.2",
|
"mini-css-extract-plugin": "^0.8.2",
|
||||||
"node-sass": "^4.13.1",
|
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
|
"react-refresh": "^0.8.3",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
"style-loader": "^1.1.3",
|
"style-loader": "^1.1.3",
|
||||||
|
"terser-webpack-plugin": "^2.3.5",
|
||||||
"webpack": "^4.41.5",
|
"webpack": "^4.41.5",
|
||||||
"webpack-cli": "^3.3.10",
|
"webpack-cli": "^3.3.10",
|
||||||
|
"webpack-dev-server": "^3.11.0",
|
||||||
"webpack-merge": "^4.2.2"
|
"webpack-merge": "^4.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/core": "^10.0.35",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.26",
|
"@fortawesome/fontawesome-svg-core": "^1.2.26",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.12.0",
|
"@fortawesome/free-solid-svg-icons": "^5.12.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.8",
|
"@fortawesome/react-fontawesome": "^0.1.8",
|
||||||
"cookies-js": "^1.2.3",
|
"cookies-js": "^1.2.3",
|
||||||
"mobx": "^5.15.3",
|
|
||||||
"mobx-react": "^6.1.4",
|
|
||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
"react-dom": "^16.12.0",
|
"react-dom": "^16.12.0",
|
||||||
"react-redux": "^7.1.3",
|
"react-redux": "^7.1.3",
|
||||||
"redux": "^4.0.5"
|
"redux": "^4.0.5",
|
||||||
|
"sass": "^1.69.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,29 +28,25 @@ import Welcome from '../welcome/Welcome.jsx'
|
|||||||
import Tractor from '../tractor/Tractor.jsx'
|
import Tractor from '../tractor/Tractor.jsx'
|
||||||
|
|
||||||
import { SCREENS, messagePanelId } from '../../constants.js'
|
import { SCREENS, messagePanelId } from '../../constants.js'
|
||||||
import { play } from './actions.js'
|
|
||||||
|
|
||||||
class Chrome extends React.Component {
|
const Chrome = ({ children, spikes, tractorClass }) => {
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<div className='flex-fullcenter'>
|
<div className='flex-fullcenter'>
|
||||||
<div className='background-heading'><h1>Alpha Centauri Farming</h1></div>
|
<div className='background-heading'><h1>Alpha Centauri Farming</h1></div>
|
||||||
{this.props.children}
|
{children}
|
||||||
<Tractor spikes={this.props.spikes} className={this.props.tractorClass} />
|
<Tractor spikes={spikes} className={tractorClass} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class App extends React.Component {
|
const App = ({ screen, logout, createAccount, login, errors }) => {
|
||||||
render() {
|
|
||||||
let view;
|
let view;
|
||||||
switch (this.props.screen) {
|
switch (screen) {
|
||||||
case SCREENS.intro:
|
case SCREENS.intro:
|
||||||
view = (<Chrome spikes={true} tractorClass='intro'><Welcome /></Chrome>);
|
view = (<Chrome spikes={true} tractorClass='intro'><Welcome /></Chrome>);
|
||||||
break;
|
break;
|
||||||
case SCREENS.start:
|
case SCREENS.start:
|
||||||
view = (<Chrome><CreateOrJoin signOut={this.props.logout} /></Chrome>);
|
view = (<Chrome><CreateOrJoin signOut={logout} /></Chrome>);
|
||||||
break;
|
break;
|
||||||
case SCREENS.newGame:
|
case SCREENS.newGame:
|
||||||
view = (<Chrome>
|
view = (<Chrome>
|
||||||
@@ -60,9 +56,9 @@ class App extends React.Component {
|
|||||||
title={'New Game'}
|
title={'New Game'}
|
||||||
type={'new-game'}
|
type={'new-game'}
|
||||||
showGameName={true}
|
showGameName={true}
|
||||||
createAccount={this.props.createAccount}
|
createAccount={createAccount}
|
||||||
login={this.props.login}
|
login={login}
|
||||||
errors={this.props.errors}
|
errors={errors}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Chrome>);
|
</Chrome>);
|
||||||
@@ -71,9 +67,9 @@ class App extends React.Component {
|
|||||||
view = (
|
view = (
|
||||||
<Chrome>
|
<Chrome>
|
||||||
<div className='view-container'>
|
<div className='view-container'>
|
||||||
<JoinGame createAccount={this.props.createAccount}
|
<JoinGame createAccount={createAccount}
|
||||||
login={this.props.login}
|
login={login}
|
||||||
errors={this.props.errors}
|
errors={errors}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Chrome>);
|
</Chrome>);
|
||||||
@@ -88,7 +84,6 @@ class App extends React.Component {
|
|||||||
<div id={messagePanelId}><MessagePanel /></div>
|
<div id={messagePanelId}><MessagePanel /></div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|||||||
@@ -61,14 +61,6 @@ export default class CreateAccount extends React.Component {
|
|||||||
</label>
|
</label>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
|
||||||
<Col width="12">
|
|
||||||
<label>
|
|
||||||
Email (optional)
|
|
||||||
<input onChange={this.onChange} name="email" type="email" />
|
|
||||||
</label>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
<Row>
|
||||||
<Col width="12">
|
<Col width="12">
|
||||||
<label>
|
<label>
|
||||||
|
|||||||
@@ -24,32 +24,31 @@ import Cookies from 'cookies-js'
|
|||||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||||
import { showNewGame, showJoinGame } from '../app/actions.js'
|
import { showNewGame, showJoinGame } from '../app/actions.js'
|
||||||
|
|
||||||
class CreateOrJoin extends React.Component {
|
const CreateOrJoin = ({ signOut, showNewGame, start, showJoinGame }) => {
|
||||||
signOut = (e) => {
|
const handleSignOut = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.signOut();
|
signOut();
|
||||||
Cookies.expire('awful-cookie');
|
Cookies.expire('awful-cookie');
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Button size='large' className='shadow' onClick={this.props.showNewGame}>
|
<div className="font-preloader">text</div>
|
||||||
|
<Button size='large' className='shadow action-item' onClick={showNewGame}>
|
||||||
New Game
|
New Game
|
||||||
</Button>
|
</Button>
|
||||||
{(this.props.start.start.games.length > 0) || (this.props.start.start.openGames.length > 0) ? (
|
{(start.start.games.length > 0) || (start.start.openGames.length > 0) ? (
|
||||||
<Button size='large' className='shadow' onClick={this.props.showJoinGame}>
|
<Button size='large' className='shadow' onClick={showJoinGame}>
|
||||||
Join Game
|
Join Game
|
||||||
</Button>
|
</Button>
|
||||||
) : (<Fragment />)}
|
) : (<Fragment />)}
|
||||||
{this.props.start.start.user ? (
|
{start.start.user ? (
|
||||||
<Button size='large' className='shadow sign-out-button' onClick={this.signOut}>
|
<Button size='large' className='shadow sign-out-button' onClick={handleSignOut}>
|
||||||
Sign Out
|
Sign Out
|
||||||
</Button>
|
</Button>
|
||||||
) : (<></>)}
|
) : (<></>)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -21,13 +21,10 @@ import { connect } from 'react-redux'
|
|||||||
|
|
||||||
import SpaceNode from './SpaceNode.jsx'
|
import SpaceNode from './SpaceNode.jsx'
|
||||||
|
|
||||||
import { setMessagePanelSpace, mpMouse } from './actions.js'
|
const MessagePanel = (props) => {
|
||||||
|
if (props.space !== null) {
|
||||||
class MessagePanel extends React.Component {
|
|
||||||
render () {
|
|
||||||
if (this.props.space !== null) {
|
|
||||||
const panel = document.getElementById('message-panel'),
|
const panel = document.getElementById('message-panel'),
|
||||||
mpDims = this.props.mpDims;
|
mpDims = props.mpDims;
|
||||||
panel.style.top =
|
panel.style.top =
|
||||||
(Math.min(Math.max(mpDims.mouseY, mpDims.minHeight + mpDims.padding),
|
(Math.min(Math.max(mpDims.mouseY, mpDims.minHeight + mpDims.padding),
|
||||||
mpDims.maxHeight)) + 'px';
|
mpDims.maxHeight)) + 'px';
|
||||||
@@ -35,13 +32,12 @@ class MessagePanel extends React.Component {
|
|||||||
(Math.min(Math.max(mpDims.mouseX, mpDims.minWidth + mpDims.padding),
|
(Math.min(Math.max(mpDims.mouseX, mpDims.minWidth + mpDims.padding),
|
||||||
mpDims.maxWidth)) + 'px';
|
mpDims.maxWidth)) + 'px';
|
||||||
return (
|
return (
|
||||||
<SpaceNode space={this.props.space} height='210px'
|
<SpaceNode space={props.space} height='210px'
|
||||||
showtitle={true} orientation={''} />
|
showtitle={true} orientation={''} />
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ export default class PlayerIcon extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<center>
|
<center>
|
||||||
{this.props.colors
|
{this.props.colors.map(c => (
|
||||||
.map(c => (<div key={c} className={'player player-' + c}></div>))}
|
<div key={c} className={'player player-' + c + (c === this.props.current ? ' player-current' : '')} />
|
||||||
|
))}
|
||||||
</center>
|
</center>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class SpaceNode extends React.Component {
|
|||||||
{title}
|
{title}
|
||||||
</div>)
|
</div>)
|
||||||
: (null)}
|
: (null)}
|
||||||
{ this.props.space.players.length ? <PlayerIcon colors={this.props.space.players} /> : ''}
|
{ this.props.space.players.length ? <PlayerIcon colors={this.props.space.players} current={this.props.current} /> : ''}
|
||||||
<div className='space-description'>
|
<div className='space-description'>
|
||||||
{this.props.space.description}
|
{this.props.space.description}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -39,3 +39,5 @@ export const AUTO_SKIP = 'auto-skip'
|
|||||||
export const MESSAGE = 'message'
|
export const MESSAGE = 'message'
|
||||||
export const SET_HARVEST_TABLE = 'set-harvest-table'
|
export const SET_HARVEST_TABLE = 'set-harvest-table'
|
||||||
export const SET_MOVING_SKIP = 'set-moving-skip'
|
export const SET_MOVING_SKIP = 'set-moving-skip'
|
||||||
|
export const SERVER_ERROR = 'server-error'
|
||||||
|
export const REMOVE_PLAYER = 'remove-player'
|
||||||
|
|||||||
@@ -21,13 +21,14 @@ import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
|
|||||||
MP_MOUSE, SET_MP_DIMS, MARK_ACTION_CHANGE_HANDLED, SET_NEXT_ACTION,
|
MP_MOUSE, SET_MP_DIMS, MARK_ACTION_CHANGE_HANDLED, SET_NEXT_ACTION,
|
||||||
MOVE_PLAYER, NEXT_UI_ACTION, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED,
|
MOVE_PLAYER, NEXT_UI_ACTION, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED,
|
||||||
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR,
|
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR,
|
||||||
SET_MOVING_SKIP } from './actionTypes.js'
|
SET_MOVING_SKIP, SERVER_ERROR, REMOVE_PLAYER } from './actionTypes.js'
|
||||||
|
|
||||||
export { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
|
export { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
|
||||||
spacePushPlayer, spaceClearPlayers, setOldMessages, setMessagePanelSpace,
|
spacePushPlayer, spaceClearPlayers, setOldMessages, setMessagePanelSpace,
|
||||||
mpMouse, setMPDims, movePlayer, setNextAction, nextUIAction,
|
mpMouse, setMPDims, movePlayer, setNextAction, nextUIAction,
|
||||||
markActionChangeHandled, nextUIActionSilent, alert, alertHandled,
|
markActionChangeHandled, nextUIActionSilent, alert, alertHandled,
|
||||||
autoSkip, message, setHarvestTable, setCardError, setMovingSkip }
|
autoSkip, message, setHarvestTable, setCardError, setMovingSkip,
|
||||||
|
serverError, removePlayer }
|
||||||
|
|
||||||
function updateGame(update) {
|
function updateGame(update) {
|
||||||
return { type: UPDATE_GAME,
|
return { type: UPDATE_GAME,
|
||||||
@@ -95,6 +96,11 @@ function movePlayer(newSpace, oldSpace, player) {
|
|||||||
newSpace, oldSpace, player };
|
newSpace, oldSpace, player };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removePlayer(color) {
|
||||||
|
return { type: REMOVE_PLAYER,
|
||||||
|
color };
|
||||||
|
}
|
||||||
|
|
||||||
function nextUIAction() {
|
function nextUIAction() {
|
||||||
return { type: NEXT_UI_ACTION };
|
return { type: NEXT_UI_ACTION };
|
||||||
}
|
}
|
||||||
@@ -135,3 +141,7 @@ function setHarvestTable(table) {
|
|||||||
function setMovingSkip(skip) {
|
function setMovingSkip(skip) {
|
||||||
return { type: SET_MOVING_SKIP, skip };
|
return { type: SET_MOVING_SKIP, skip };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function serverError(exn) {
|
||||||
|
return { type: SERVER_ERROR, exn };
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,13 +25,14 @@ import { updateGame, updatePlayer, gameState, setSelectedCard, setCards,
|
|||||||
movePlayer, setOldMessages, markActionChangeHandled,
|
movePlayer, setOldMessages, markActionChangeHandled,
|
||||||
mpMouse, rolled, setNextAction, nextUIAction, nextUIActionSilent, alert,
|
mpMouse, rolled, setNextAction, nextUIAction, nextUIActionSilent, alert,
|
||||||
autoSkip, message, alertHandled, setHarvestTable,
|
autoSkip, message, alertHandled, setHarvestTable,
|
||||||
setCardError, setMovingSkip } from './actions.js'
|
setCardError, setMovingSkip, serverError, removePlayer } from './actions.js'
|
||||||
import { itemCard, fateCard } from 'game.js'
|
import { itemCard, fateCard } from 'game.js'
|
||||||
|
|
||||||
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
|
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||||
submitTradeDeny, submitTradeCancel, audit, handleMessage,
|
submitTradeDeny, submitTradeCancel, audit, handleMessage,
|
||||||
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
|
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
|
||||||
startGame }
|
startGame, readyToStart, leaveGame, kickPlayer, toggleRevealForTrade,
|
||||||
|
addAIPlayer, birthdayBonusPlayer }
|
||||||
|
|
||||||
let store;
|
let store;
|
||||||
let movingTimer = 0;
|
let movingTimer = 0;
|
||||||
@@ -42,9 +43,16 @@ function handleMessage(evt) {
|
|||||||
|
|
||||||
if (data.event === 'error') {
|
if (data.event === 'error') {
|
||||||
console.log('error:' + data.exn);
|
console.log('error:' + data.exn);
|
||||||
|
store.dispatch(serverError(data.exn));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
batch(() => {
|
batch(() => {
|
||||||
|
if (data.event === 'left-game') {
|
||||||
|
window.location.href = window.location.pathname;
|
||||||
|
}
|
||||||
|
if (data.event === 'player-left-game') {
|
||||||
|
store.dispatch(removePlayer(data.color));
|
||||||
|
}
|
||||||
if (data.game.state === GAME_STATES.preGame) {
|
if (data.game.state === GAME_STATES.preGame) {
|
||||||
store.dispatch(alert(ALERTS.preGame, '', 'pre-game'));
|
store.dispatch(alert(ALERTS.preGame, '', 'pre-game'));
|
||||||
}
|
}
|
||||||
@@ -79,7 +87,7 @@ function handleMessage(evt) {
|
|||||||
store.dispatch(movePlayer(data.player.space, -1, data.player.color));
|
store.dispatch(movePlayer(data.player.space, -1, data.player.color));
|
||||||
store.dispatch(setHarvestTable(data.harvestTable));
|
store.dispatch(setHarvestTable(data.harvestTable));
|
||||||
}
|
}
|
||||||
// new player(s) added to game, put them on the board
|
// player(s) added or removed from game, put them on the board
|
||||||
if (data.game.otherPlayers.length !== store.getState().farm.game.otherPlayers.length) {
|
if (data.game.otherPlayers.length !== store.getState().farm.game.otherPlayers.length) {
|
||||||
const otherPlayers = store.getState().farm.game.otherPlayers;
|
const otherPlayers = store.getState().farm.game.otherPlayers;
|
||||||
const newPlayers = data.game.otherPlayers.filter(
|
const newPlayers = data.game.otherPlayers.filter(
|
||||||
@@ -119,7 +127,7 @@ function handleMessage(evt) {
|
|||||||
store.dispatch(autoSkip(data.component));
|
store.dispatch(autoSkip(data.component));
|
||||||
}
|
}
|
||||||
if (data.event === 'end-of-game') {
|
if (data.event === 'end-of-game') {
|
||||||
store.dispatch(alert(ALERTS.endOfGame, data.results, 'endOfGame' + data.game.turn));
|
store.dispatch(alert(ALERTS.endOfGame, { results: data.results, stats: data.stats }, 'endOfGame' + data.game.turn));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -198,6 +206,30 @@ function startGame() {
|
|||||||
sendCommand({ type: 'start-game' });
|
sendCommand({ type: 'start-game' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readyToStart() {
|
||||||
|
sendCommand({ type: 'ready-to-start' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function leaveGame() {
|
||||||
|
sendCommand({ type: 'leave-game' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function kickPlayer(name) {
|
||||||
|
sendCommand({ type: 'kick-player', name });
|
||||||
|
}
|
||||||
|
|
||||||
|
function birthdayBonusPlayer(name) {
|
||||||
|
sendCommand({ type: 'birthday-bonus-player', name });
|
||||||
|
}
|
||||||
|
|
||||||
|
function addAIPlayer() {
|
||||||
|
sendCommand({ type: 'add-ai-player' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleRevealForTrade(id) {
|
||||||
|
sendCommand({ type: 'toggle-reveal-for-trading', id });
|
||||||
|
}
|
||||||
|
|
||||||
// TODO share with Board.jsx
|
// TODO share with Board.jsx
|
||||||
// http://stackoverflow.com/questions/149055
|
// http://stackoverflow.com/questions/149055
|
||||||
function formatMoney(n) {
|
function formatMoney(n) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { UPDATE_GAME, UPDATE_PLAYER, GAME_STATE, SET_SELECTED_CARD, SET_CARDS,
|
|||||||
SET_MP_DIMS, MOVE_PLAYER, SET_NEXT_ACTION, NEXT_UI_ACTION,
|
SET_MP_DIMS, MOVE_PLAYER, SET_NEXT_ACTION, NEXT_UI_ACTION,
|
||||||
MARK_ACTION_CHANGE_HANDLED, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED,
|
MARK_ACTION_CHANGE_HANDLED, NEXT_UI_ACTION_SILENT, ALERT, ALERT_HANDLED,
|
||||||
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR,
|
AUTO_SKIP, MESSAGE, SET_HARVEST_TABLE, SET_CARD_ERROR,
|
||||||
SET_MOVING_SKIP } from './actionTypes.js'
|
SET_MOVING_SKIP, SERVER_ERROR, REMOVE_PLAYER } from './actionTypes.js'
|
||||||
import { GAME_STATES } from '../../constants.js'
|
import { GAME_STATES } from '../../constants.js'
|
||||||
import { spaceContent, corners } from 'game.js'
|
import { spaceContent, corners } from 'game.js'
|
||||||
|
|
||||||
@@ -88,9 +88,11 @@ const initialState = {
|
|||||||
debt: 5000,
|
debt: 5000,
|
||||||
spaces,
|
spaces,
|
||||||
state: GAME_STATES.turnEnded,
|
state: GAME_STATES.turnEnded,
|
||||||
assets: { hay: 10, grain: 10, fruit: 0, cows: 0, harvester: 0, tractor: 0 },
|
assets: { hay: 10, grain: 10, fruit: 0, cows: 0, harvester: 0, tractor: 0, birthday: 0 },
|
||||||
color: '',
|
color: '',
|
||||||
name: '',
|
name: '',
|
||||||
|
cards: [],
|
||||||
|
revealedCards: [],
|
||||||
ridges: { ridge1: 0, ridge2: 0, ridge3: 0, ridge4: 0 },
|
ridges: { ridge1: 0, ridge2: 0, ridge3: 0, ridge4: 0 },
|
||||||
space: 0,
|
space: 0,
|
||||||
hayDoubled: false,
|
hayDoubled: false,
|
||||||
@@ -105,18 +107,26 @@ const initialState = {
|
|||||||
state: GAME_STATES.preTurn,
|
state: GAME_STATES.preTurn,
|
||||||
turn: 0,
|
turn: 0,
|
||||||
oldMessages: [],
|
oldMessages: [],
|
||||||
|
name: '',
|
||||||
|
host: '',
|
||||||
settings: { downPayment: 0.2,
|
settings: { downPayment: 0.2,
|
||||||
loanInterest: 0.2,
|
loanInterest: 0.2,
|
||||||
maxDebt: 50000,
|
maxDebt: 50000,
|
||||||
auditThreshold: 250000 }
|
auditThreshold: 250000,
|
||||||
|
startingOtbs: 2,
|
||||||
|
startingCash: 5000,
|
||||||
|
startingDebt: 5000 },
|
||||||
|
readyToStart: false
|
||||||
},
|
},
|
||||||
ui: { card: { type: 'no-card', contents: '', total: 0 },
|
ui: { card: { type: 'no-card', contents: '', total: 0 },
|
||||||
cards: [],
|
cards: [],
|
||||||
cardError: false,
|
cardError: false,
|
||||||
action: false,
|
action: false,
|
||||||
actionValue: null,
|
actionValue: null,
|
||||||
|
actionId: -1,
|
||||||
nextAction: false,
|
nextAction: false,
|
||||||
nextActionValue: null,
|
nextActionValue: null,
|
||||||
|
nextActionId: -1,
|
||||||
actionChangeHandled: true,
|
actionChangeHandled: true,
|
||||||
message: '',
|
message: '',
|
||||||
alerts: {},
|
alerts: {},
|
||||||
@@ -124,7 +134,8 @@ const initialState = {
|
|||||||
autoSkip: false,
|
autoSkip: false,
|
||||||
playerSpaces: {},
|
playerSpaces: {},
|
||||||
movingSkip: false,
|
movingSkip: false,
|
||||||
harvestTable: false },
|
harvestTable: false,
|
||||||
|
exn: false },
|
||||||
spaces: spaces,
|
spaces: spaces,
|
||||||
space: null,
|
space: null,
|
||||||
// message panel dimenions
|
// message panel dimenions
|
||||||
@@ -135,6 +146,8 @@ const initialState = {
|
|||||||
profileTurns: 500
|
profileTurns: 500
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lastActionId = -1;
|
||||||
|
|
||||||
export default function(state = initialState, action) {
|
export default function(state = initialState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case UPDATE_GAME:
|
case UPDATE_GAME:
|
||||||
@@ -170,6 +183,21 @@ export default function(state = initialState, action) {
|
|||||||
[action.player]: action.newSpace }}
|
[action.player]: action.newSpace }}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
case REMOVE_PLAYER:
|
||||||
|
const playerSpace = state.ui.playerSpaces[action.color];
|
||||||
|
return { ...state,
|
||||||
|
spaces: state.spaces.map((item, index) => {
|
||||||
|
if (index === playerSpace) {
|
||||||
|
return { ...item,
|
||||||
|
players: item.players
|
||||||
|
.filter(x => x !== action.color) };
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}),
|
||||||
|
ui: { ...state.ui,
|
||||||
|
playerSpaces: { ...state.ui.playerSpaces,
|
||||||
|
[action.player]: -1 }}
|
||||||
|
};
|
||||||
case SET_OLD_MESSAGES:
|
case SET_OLD_MESSAGES:
|
||||||
return { ...state, oldMessages: action.messages };
|
return { ...state, oldMessages: action.messages };
|
||||||
case MESSAGE_PANEL_SPACE:
|
case MESSAGE_PANEL_SPACE:
|
||||||
@@ -185,15 +213,18 @@ export default function(state = initialState, action) {
|
|||||||
maxHeight: action.maxHeight }};
|
maxHeight: action.maxHeight }};
|
||||||
case SET_NEXT_ACTION:
|
case SET_NEXT_ACTION:
|
||||||
return { ...state, ui: { ...state.ui, nextAction: action.action,
|
return { ...state, ui: { ...state.ui, nextAction: action.action,
|
||||||
nextActionValue: action.value }};
|
nextActionValue: action.value,
|
||||||
|
nextActionId: ++lastActionId }};
|
||||||
case NEXT_UI_ACTION:
|
case NEXT_UI_ACTION:
|
||||||
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
|
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
|
||||||
actionValue: state.ui.nextActionValue,
|
actionValue: state.ui.nextActionValue,
|
||||||
|
actionId: state.ui.nextActionId,
|
||||||
autoSkip: false,
|
autoSkip: false,
|
||||||
actionChangeHandled: !state.ui.nextAction }};
|
actionChangeHandled: !state.ui.nextAction }};
|
||||||
case NEXT_UI_ACTION_SILENT: // don't set actionChangeHandled
|
case NEXT_UI_ACTION_SILENT: // don't set actionChangeHandled
|
||||||
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
|
return { ...state, ui: { ...state.ui, action: state.ui.nextAction,
|
||||||
actionValue: state.ui.nextActionValue }};
|
actionValue: state.ui.nextActionValue,
|
||||||
|
actionId: state.ui.nextActionId }};
|
||||||
case MARK_ACTION_CHANGE_HANDLED:
|
case MARK_ACTION_CHANGE_HANDLED:
|
||||||
return { ...state, ui: { ...state.ui, actionChangeHandled: true }};
|
return { ...state, ui: { ...state.ui, actionChangeHandled: true }};
|
||||||
case ALERT:
|
case ALERT:
|
||||||
@@ -228,6 +259,8 @@ export default function(state = initialState, action) {
|
|||||||
return { ...state, ui: { ...state.ui, harvestTable: action.table }};
|
return { ...state, ui: { ...state.ui, harvestTable: action.table }};
|
||||||
case SET_MOVING_SKIP:
|
case SET_MOVING_SKIP:
|
||||||
return { ...state, ui: { ...state.ui, movingSkip: action.skip }};
|
return { ...state, ui: { ...state.ui, movingSkip: action.skip }};
|
||||||
|
case SERVER_ERROR:
|
||||||
|
return { ...state, ui: { ...state.ui, exn: action.exn }};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,19 +26,23 @@ import { start } from '../app/actions.js'
|
|||||||
import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccount.jsx';
|
import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccount.jsx';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faArrowCircleLeft } from '@fortawesome/free-solid-svg-icons'
|
import { faArrowCircleLeft, faCaretDown } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
import NewGame from '../new-game/NewGame.jsx'
|
import NewGame from '../new-game/NewGame.jsx'
|
||||||
|
|
||||||
const JoinGameScreens = { list: 'list', details: 'details' };
|
const JoinGameScreens = { list: 'list', details: 'details' };
|
||||||
|
|
||||||
|
const defaultMaxGames = 5;
|
||||||
|
|
||||||
class JoinGame extends React.Component {
|
class JoinGame extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
screen: JoinGameScreens.list,
|
screen: JoinGameScreens.list,
|
||||||
game: null,
|
game: null,
|
||||||
showSignIn: false
|
showSignIn: false,
|
||||||
|
maxGames: defaultMaxGames,
|
||||||
|
maxOpenGames: defaultMaxGames
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,11 +71,22 @@ class JoinGame extends React.Component {
|
|||||||
this.setState(state => { return { showSignIn: !state.showSignIn }; });
|
this.setState(state => { return { showSignIn: !state.showSignIn }; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showAllGames = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({ maxGames: Number.MAX_SAFE_INTEGER });
|
||||||
|
}
|
||||||
|
|
||||||
|
showAllOpenGames = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({ maxOpenGames: Number.MAX_SAFE_INTEGER });
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { games, openGames } = this.props;
|
||||||
return (
|
return (
|
||||||
<GroupBox title={(
|
<GroupBox title={(
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<a href="#" onClick={this.handleBack}>
|
<a onClick={this.handleBack}>
|
||||||
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
||||||
</a>
|
</a>
|
||||||
Join Game
|
Join Game
|
||||||
@@ -97,21 +112,39 @@ class JoinGame extends React.Component {
|
|||||||
</>
|
</>
|
||||||
) : (<></>)}
|
) : (<></>)}
|
||||||
<ul>
|
<ul>
|
||||||
{this.props.games
|
{games.slice(0, this.state.maxGames)
|
||||||
.map((g, i) =>
|
.map((g, i) =>
|
||||||
(<li key={i}>
|
(
|
||||||
|
<li key={i}>
|
||||||
<a onClick={(e) => this.handleJoinAsExisting(e, g.id)}>{g.name}</a>
|
<a onClick={(e) => this.handleJoinAsExisting(e, g.id)}>{g.name}</a>
|
||||||
</li>))}
|
</li>
|
||||||
|
))}
|
||||||
|
{games.length > this.state.maxGames ? (
|
||||||
|
<li>
|
||||||
|
<center>
|
||||||
|
<a onClick={this.showAllGames}><FontAwesomeIcon icon={faCaretDown} /> Show all</a>
|
||||||
|
</center>
|
||||||
|
</li>
|
||||||
|
) : (<></>)}
|
||||||
</ul>
|
</ul>
|
||||||
<h3>Open Games</h3>
|
<h3>Open Games</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{this.props.openGames
|
{openGames.slice(0, this.state.maxOpenGames)
|
||||||
.map((g, i) =>
|
.map((g, i) =>
|
||||||
(<li key={i}>
|
(
|
||||||
|
<li key={i}>
|
||||||
<a onClick={e => {
|
<a onClick={e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.handleClickGame(g); }}>{g.name}</a>
|
this.handleClickGame(g); }}>{g.name}</a>
|
||||||
</li>))}
|
</li>
|
||||||
|
))}
|
||||||
|
{openGames.length > this.state.maxOpenGames ? (
|
||||||
|
<li>
|
||||||
|
<center>
|
||||||
|
<a onClick={this.showAllOpenGames}><FontAwesomeIcon icon={faCaretDown} /> Show all</a>
|
||||||
|
</center>
|
||||||
|
</li>
|
||||||
|
) : (<></>)}
|
||||||
</ul>
|
</ul>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export default class LoginOrCreateAccount extends React.Component {
|
|||||||
createAccount={this.props.createAccount} />
|
createAccount={this.props.createAccount} />
|
||||||
)}
|
)}
|
||||||
<div className="center">
|
<div className="center">
|
||||||
<a onClick={this.toggleLogin}>{this.state.showLogin ? 'Create Account' : 'Login'}</a>
|
<a className="action-item" onClick={this.toggleLogin}>{this.state.showLogin ? 'Create Account' : 'Login'}</a>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccoun
|
|||||||
import { startOrJoinGame } from '../start/actions.js'
|
import { startOrJoinGame } from '../start/actions.js'
|
||||||
import { start } from '../app/actions.js'
|
import { start } from '../app/actions.js'
|
||||||
|
|
||||||
|
import { itemCardShort } from 'game.js'
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faArrowCircleLeft, faCog } from '@fortawesome/free-solid-svg-icons'
|
import { faArrowCircleLeft, faCog } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
@@ -63,6 +65,7 @@ class NewGame extends React.Component {
|
|||||||
auditThreshold: 250000,
|
auditThreshold: 250000,
|
||||||
startingCash: 5000,
|
startingCash: 5000,
|
||||||
startingDebt: 5000,
|
startingDebt: 5000,
|
||||||
|
startingOtbs: 2,
|
||||||
trade: true,
|
trade: true,
|
||||||
showLogin: false
|
showLogin: false
|
||||||
};
|
};
|
||||||
@@ -180,6 +183,13 @@ class NewGame extends React.Component {
|
|||||||
step={1000}
|
step={1000}
|
||||||
value={this.state.startingDebt}
|
value={this.state.startingDebt}
|
||||||
onChange={this.handleInputChange} />
|
onChange={this.handleInputChange} />
|
||||||
|
<InputRow label={'Number of Starting ' + itemCardShort}
|
||||||
|
name='startingOtbs'
|
||||||
|
min={0}
|
||||||
|
max={8}
|
||||||
|
step={1}
|
||||||
|
value={this.state.startingOtbs}
|
||||||
|
onChange={this.handleInputChange} />
|
||||||
<Row>
|
<Row>
|
||||||
<Col width='12'>
|
<Col width='12'>
|
||||||
<label>
|
<label>
|
||||||
|
|||||||
@@ -19,12 +19,11 @@
|
|||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
|
||||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
import { Button } from '../widgets.jsx'
|
||||||
import { start } from '../app/actions.js'
|
import { start } from '../app/actions.js'
|
||||||
|
|
||||||
|
|
||||||
class Welcome extends React.Component {
|
const Welcome = (props) => {
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className='intro-text'>
|
<div className='intro-text'>
|
||||||
@@ -32,12 +31,11 @@ class Welcome extends React.Component {
|
|||||||
Your ancestors were farmers on one of the first transports to Alpha Centuari{`'`}s Proxima b. The growing season is short and harsh but the colonists depend on you for their food. Are you up to the challenge?
|
Your ancestors were farmers on one of the first transports to Alpha Centuari{`'`}s Proxima b. The growing season is short and harsh but the colonists depend on you for their food. Are you up to the challenge?
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button size='large' className='shadow intro' onClick={this.props.start}>
|
<Button size='large' className='shadow intro action-item' onClick={props.start}>
|
||||||
Begin
|
Begin
|
||||||
</Button>
|
</Button>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|||||||
@@ -20,51 +20,43 @@ import React, { Fragment } from 'react'
|
|||||||
|
|
||||||
export { GroupBox, Row, Col, Button }
|
export { GroupBox, Row, Col, Button }
|
||||||
|
|
||||||
class GroupBox extends React.Component {
|
const GroupBox = (props) => {
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<div className='panel card'>
|
<div className='panel card'>
|
||||||
{this.props.title ?
|
{props.title ?
|
||||||
(<div className='card-divider'>
|
(<div className='card-divider'>
|
||||||
{this.props.title}
|
{props.title}
|
||||||
</div>) : (<Fragment />)}
|
</div>) : (<Fragment />)}
|
||||||
<div className={'card-section ' + this.props.className ? this.props.className : ''}>
|
<div className={'card-section ' + props.className ? props.className : ''}>
|
||||||
{this.props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Row extends React.Component {
|
const Row = (props) => {
|
||||||
render() {
|
|
||||||
return (<div className={'grid-x full-width ' +
|
return (<div className={'grid-x full-width ' +
|
||||||
(this.props.collapse ? 'collapse' : '') + ' ' +
|
(props.collapse ? 'collapse' : '') + ' ' +
|
||||||
(this.props.className ? this.props.className : '')} >
|
(props.className ? props.className : '')} >
|
||||||
{this.props.children}</div>);
|
{props.children}</div>);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Col extends React.Component {
|
const Col = (props) => {
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<div className={'cell small-' + this.props.width + ' ' + (this.props.className ? this.props.className : '')}>
|
<div className={'cell small-' + props.width + ' ' + (props.className ? props.className : '')}>
|
||||||
{this.props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Button extends React.Component {
|
const Button = (props) => {
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<button className={'button ' + (this.props.size ? this.props.size : '') +
|
<button className={'button ' + (props.size ? props.size : '') +
|
||||||
' ' + (this.props.className ? this.props.className : '')}
|
' ' + (props.className ? props.className : '')}
|
||||||
type={this.props.type || 'button'}
|
type={props.type || 'button'}
|
||||||
disabled={this.props.disabled}
|
disabled={props.disabled}
|
||||||
onClick={this.props.onClick} >
|
onClick={props.onClick} >
|
||||||
{this.props.children}
|
{props.children}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ const unsubscribeNewOrJoinGame = store.subscribe(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let autostart = new URL(window.location.href).searchParams.get('autostart');
|
let autostart = new URL(window.location.href).searchParams.get('autostart');
|
||||||
|
let rejoin = new URL(window.location.href).searchParams.get('reload-game');
|
||||||
|
|
||||||
function handleMessage(evt) {
|
function handleMessage(evt) {
|
||||||
const data = JSON.parse(evt.data),
|
const data = JSON.parse(evt.data),
|
||||||
@@ -86,6 +87,8 @@ function handleMessage(evt) {
|
|||||||
if (data.event === 'error') {
|
if (data.event === 'error') {
|
||||||
console.log('error:' + data.exn);
|
console.log('error:' + data.exn);
|
||||||
} else if (data.event === 'new-game-started') {
|
} else if (data.event === 'new-game-started') {
|
||||||
|
history.replaceState({}, document.title, '/');
|
||||||
|
console.log('clearing auto-reload');
|
||||||
initialize(store, Ws.sendCommand);
|
initialize(store, Ws.sendCommand);
|
||||||
Ws.setMainOnMessage(handleMessageFarm);
|
Ws.setMainOnMessage(handleMessageFarm);
|
||||||
Ws.openSecondary('push-web-socket');
|
Ws.openSecondary('push-web-socket');
|
||||||
@@ -111,6 +114,10 @@ function handleMessage(evt) {
|
|||||||
gameName: data.games.games[0].name }));
|
gameName: data.games.games[0].name }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rejoin) {
|
||||||
|
store.dispatch(startOrJoinGame({ type: 'join-as-existing',
|
||||||
|
gameId: false }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
(use sql-de-lite crypt)
|
(use sql-de-lite crypt)
|
||||||
|
|
||||||
(define *db* "/home/tjhintz/db")
|
;; (define *db* "/home/tjhintz/db")
|
||||||
|
(define *db* "/farmdb/db")
|
||||||
|
|
||||||
(define-syntax with-db
|
(define-syntax with-db
|
||||||
(syntax-rules ()
|
(syntax-rules ()
|
||||||
@@ -10,12 +11,17 @@
|
|||||||
body ...)))))
|
body ...)))))
|
||||||
|
|
||||||
(define (create-tables)
|
(define (create-tables)
|
||||||
|
(when (not (file-exists? *db*))
|
||||||
|
(call-with-output-file *db*
|
||||||
|
(lambda (output-port)
|
||||||
|
""
|
||||||
|
)))
|
||||||
(with-db (db)
|
(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 if not exists 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 if not exists 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 if not exists games(id INTEGER PRIMARY KEY, status TEXT, object TEXT, updated INTEGER);"))
|
||||||
(exec (sql db "create table players(id INTEGER PRIMARY KEY, object TEXT);"))
|
(exec (sql db "create table if not exists players(id INTEGER PRIMARY KEY, object TEXT);"))
|
||||||
(exec (sql db "create table user_games(user_id INTEGER, game_id INTEGER);"))))
|
(exec (sql db "create table if not exists user_games(user_id INTEGER, game_id INTEGER);"))))
|
||||||
|
|
||||||
(define (db-session-set! sid bindings)
|
(define (db-session-set! sid bindings)
|
||||||
(with-db (db)
|
(with-db (db)
|
||||||
@@ -62,6 +68,12 @@
|
|||||||
(string=? (crypt password (alist-ref 'salt user))
|
(string=? (crypt password (alist-ref 'salt user))
|
||||||
(alist-ref 'password user))))
|
(alist-ref 'password user))))
|
||||||
|
|
||||||
|
(define (unsecure-set-password username password)
|
||||||
|
(let ((salt (crypt-gensalt)))
|
||||||
|
(with-db (db)
|
||||||
|
(exec (sql db "update users set password=?, salt=? where username=?;")
|
||||||
|
(crypt password salt) salt username))))
|
||||||
|
|
||||||
(define (alist->string alist)
|
(define (alist->string alist)
|
||||||
(with-output-to-string (lambda () (write alist))))
|
(with-output-to-string (lambda () (write alist))))
|
||||||
|
|
||||||
@@ -70,14 +82,14 @@
|
|||||||
|
|
||||||
(define (db-add-game status object)
|
(define (db-add-game status object)
|
||||||
(with-db (db)
|
(with-db (db)
|
||||||
(exec (sql db "insert into games(status, object) values (?, ?);")
|
(exec (sql db "insert into games(status, object, updated) values (?, ?, ?);")
|
||||||
status (alist->string object))
|
status (alist->string object) (current-seconds))
|
||||||
(last-insert-rowid db)))
|
(last-insert-rowid db)))
|
||||||
|
|
||||||
(define (db-update-game id status object)
|
(define (db-update-game id status object)
|
||||||
(with-db (db)
|
(with-db (db)
|
||||||
(exec (sql db "replace into games(id, status, object) values (?, ?, ?);")
|
(exec (sql db "replace into games(id, status, object, updated) values (?, ?, ?, ?);")
|
||||||
id status (alist->string object))))
|
id status (alist->string object) (current-seconds))))
|
||||||
|
|
||||||
(define (db-fetch-game id)
|
(define (db-fetch-game id)
|
||||||
(string->alist
|
(string->alist
|
||||||
@@ -91,7 +103,7 @@
|
|||||||
string->alist
|
string->alist
|
||||||
(with-db (db)
|
(with-db (db)
|
||||||
(query fetch-column
|
(query fetch-column
|
||||||
(sql db "select object from games where status=?;")
|
(sql db "select object from games where status=? order by updated desc;")
|
||||||
"pre-game"))))
|
"pre-game"))))
|
||||||
|
|
||||||
(define (db-fetch-game-row id)
|
(define (db-fetch-game-row id)
|
||||||
@@ -127,8 +139,13 @@
|
|||||||
(exec (sql db "insert into user_games(user_id, game_id) values (?, ?);")
|
(exec (sql db "insert into user_games(user_id, game_id) values (?, ?);")
|
||||||
user-id game-id)))
|
user-id game-id)))
|
||||||
|
|
||||||
|
(define (db-remove-user-game user-id game-id)
|
||||||
|
(with-db (db)
|
||||||
|
(exec (sql db "delete from user_games where user_id=? and game_id=?;")
|
||||||
|
user-id game-id)))
|
||||||
|
|
||||||
(define (db-fetch-user-games user-id)
|
(define (db-fetch-user-games user-id)
|
||||||
(with-db (db)
|
(with-db (db)
|
||||||
(query fetch-column
|
(query fetch-column
|
||||||
(sql db "select game_id from user_games where user_id=?;")
|
(sql db "select game_id from user_games join games on user_games.game_id=games.id where user_games.user_id=? and not games.status=? order by updated desc;")
|
||||||
user-id)))
|
user-id "finished")))
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
214
src/style.scss
214
src/style.scss
@@ -16,6 +16,20 @@
|
|||||||
// along with the Alpha Centauri Farming project. If not, see
|
// along with the Alpha Centauri Farming project. If not, see
|
||||||
// <https://www.gnu.org/licenses/>.
|
// <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'IndieFlower-Regular';
|
||||||
|
src: url('../assets/font/IndieFlower-Regular.woff2') format('woff2'),
|
||||||
|
url('../assets/font/IndieFlower-Regular.woff') format('woff'),
|
||||||
|
url('../assets/font/IndieFlower-Regular.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'LibreBaskerville-Regular';
|
||||||
|
// src: url('../assets/font/LibreBaskerville-Regular.woff2') format('woff2'),
|
||||||
|
// url('../assets/font/LibreBaskerville-Regular.woff') format('woff'),
|
||||||
|
// url('../assets/font/LibreBaskerville-Regular.ttf') format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
@import './foundation/foundation';
|
@import './foundation/foundation';
|
||||||
|
|
||||||
// Global styles
|
// Global styles
|
||||||
@@ -159,6 +173,8 @@ $tab-margin: 0.3rem;
|
|||||||
width: 100%; }
|
width: 100%; }
|
||||||
|
|
||||||
.space {
|
.space {
|
||||||
|
font-family: 'IndieFlower-Regular';
|
||||||
|
// font-family: 'LibreBaskerville-Regular';
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
flex-basis: 0;
|
flex-basis: 0;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
@@ -169,6 +185,7 @@ $tab-margin: 0.3rem;
|
|||||||
font-size: 4px; }
|
font-size: 4px; }
|
||||||
@include breakpoint(large) {
|
@include breakpoint(large) {
|
||||||
font-size: 14px; }
|
font-size: 14px; }
|
||||||
|
text-shadow: 0px 0px 2px black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-description {
|
.space-description {
|
||||||
@@ -244,6 +261,23 @@ $tab-margin: 0.3rem;
|
|||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
margin-left: 5px; }
|
margin-left: 5px; }
|
||||||
|
|
||||||
|
.player-current {
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
|
||||||
|
transition: all 0.3s ease-in-out; }
|
||||||
|
|
||||||
|
.player-current::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 12px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
|
box-shadow: 0 0px 5px $primary-color;
|
||||||
|
animation: die-pulse 2s ease-in-out infinite; }
|
||||||
|
|
||||||
.player-selectable {
|
.player-selectable {
|
||||||
border: 4px solid #ff816e;
|
border: 4px solid #ff816e;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -271,7 +305,7 @@ $tab-margin: 0.3rem;
|
|||||||
.player-black {
|
.player-black {
|
||||||
background-color: black; }
|
background-color: black; }
|
||||||
.player-none {
|
.player-none {
|
||||||
background-color: #f2f2f2; }
|
background-color: #f2f2f2; } //
|
||||||
|
|
||||||
.tab .player {
|
.tab .player {
|
||||||
height: 27px;
|
height: 27px;
|
||||||
@@ -437,21 +471,107 @@ $trade-margin: 3rem;
|
|||||||
.space-type-hay {
|
.space-type-hay {
|
||||||
background-color: hsla(120, 100%, 25%, 0.19); }
|
background-color: hsla(120, 100%, 25%, 0.19); }
|
||||||
|
|
||||||
|
.space-type-hay::after {
|
||||||
|
background: url('../assets/img/hay.svg') repeat;
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0.2;
|
||||||
|
z-index: -1;
|
||||||
|
position: absolute;
|
||||||
|
filter: invert(42%) sepia(93%) saturate(1352%) hue-rotate(87deg) brightness(119%) contrast(119%);
|
||||||
|
background-size: auto 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0; }
|
||||||
|
|
||||||
.space-type-cherry {
|
.space-type-cherry {
|
||||||
background-color: hsla(0, 100%, 40%, 0.28); }
|
background-color: hsla(0, 100%, 40%, 0.28); }
|
||||||
|
|
||||||
|
.space-type-cherry::after {
|
||||||
|
background: url('../assets/img/fruit.svg') repeat;
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0.1;
|
||||||
|
z-index: -1;
|
||||||
|
position: absolute;
|
||||||
|
filter: invert(13%) sepia(54%) saturate(6280%) hue-rotate(358deg) brightness(98%) contrast(123%);
|
||||||
|
background-size: auto 50%;
|
||||||
|
background-position: right;
|
||||||
|
top: 0;
|
||||||
|
left: 0; }
|
||||||
|
|
||||||
.space-type-apple {
|
.space-type-apple {
|
||||||
background-color: hsla(0, 100%, 40%, 0.28); }
|
background-color: hsla(0, 100%, 40%, 0.28); }
|
||||||
|
|
||||||
|
.space-type-apple::after {
|
||||||
|
background: url('../assets/img/fruit.svg') repeat;
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0.1;
|
||||||
|
z-index: -1;
|
||||||
|
position: absolute;
|
||||||
|
filter: invert(13%) sepia(54%) saturate(6280%) hue-rotate(358deg) brightness(98%) contrast(123%);
|
||||||
|
background-size: auto 50%;
|
||||||
|
background-position: right;
|
||||||
|
top: 0;
|
||||||
|
left: 0; }
|
||||||
|
|
||||||
.space-type-wheat {
|
.space-type-wheat {
|
||||||
background-color: hsla(50, 97%, 48%, 0.22); }
|
background-color: hsla(50, 97%, 48%, 0.22); }
|
||||||
|
|
||||||
|
.space-type-wheat::after {
|
||||||
|
background: url('../assets/img/wheat.svg') repeat;
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0.2;
|
||||||
|
z-index: -1;
|
||||||
|
position: absolute;
|
||||||
|
filter: invert(68%) sepia(58%) saturate(747%) hue-rotate(8deg) brightness(102%) contrast(106%);
|
||||||
|
background-size: auto 110%;
|
||||||
|
background-position: right;
|
||||||
|
top: 0;
|
||||||
|
left: 0; }
|
||||||
|
|
||||||
.space-type-corn {
|
.space-type-corn {
|
||||||
background-color: hsla(50, 97%, 48%, 0.22); }
|
background-color: hsla(50, 97%, 48%, 0.22); }
|
||||||
|
|
||||||
|
.space-type-corn::after {
|
||||||
|
background: url('../assets/img/wheat.svg') repeat;
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0.2;
|
||||||
|
z-index: -1;
|
||||||
|
position: absolute;
|
||||||
|
filter: invert(68%) sepia(58%) saturate(747%) hue-rotate(8deg) brightness(102%) contrast(106%);
|
||||||
|
background-size: auto 110%;
|
||||||
|
background-position: right;
|
||||||
|
top: 0;
|
||||||
|
left: 0; }
|
||||||
|
|
||||||
.space-type-cows {
|
.space-type-cows {
|
||||||
background-color: hsla(0, 25%, 43%, 0.49); }
|
background-color: hsla(0, 25%, 43%, 0.49); }
|
||||||
|
|
||||||
|
.space-type-cows::after {
|
||||||
|
background: url('../assets/img/cow.svg') repeat;
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0.2;
|
||||||
|
z-index: -1;
|
||||||
|
position: absolute;
|
||||||
|
filter: invert(43%) sepia(5%) saturate(4943%) hue-rotate(314deg) brightness(76%) contrast(75%);
|
||||||
|
background-size: auto 35%;
|
||||||
|
background-position: right;
|
||||||
|
top: 0;
|
||||||
|
left: 0; }
|
||||||
|
|
||||||
|
.space-type-buy {
|
||||||
|
background-color: hsla(240, 100%, 85%, 0.15); }
|
||||||
|
|
||||||
.space-title {
|
.space-title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-style: italic; }
|
font-style: italic; }
|
||||||
@@ -686,6 +806,14 @@ $trade-margin: 3rem;
|
|||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
display: none; }
|
display: none; }
|
||||||
|
|
||||||
|
.tab.border-top {
|
||||||
|
$tab-border: 0.3rem solid $primary-color;
|
||||||
|
border-top: $tab-border;
|
||||||
|
border-bottom: none;
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
.tab.show {
|
.tab.show {
|
||||||
display: block; }
|
display: block; }
|
||||||
|
|
||||||
@@ -752,6 +880,7 @@ $trade-margin: 3rem;
|
|||||||
margin-top: 1rem; }
|
margin-top: 1rem; }
|
||||||
|
|
||||||
.clear-background {
|
.clear-background {
|
||||||
|
position: relative;
|
||||||
background: white; }
|
background: white; }
|
||||||
|
|
||||||
.harvest-card {
|
.harvest-card {
|
||||||
@@ -805,6 +934,10 @@ $trade-margin: 3rem;
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center; }
|
align-items: center; }
|
||||||
|
|
||||||
|
.alert-container {
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow: auto; }
|
||||||
|
|
||||||
.moving {
|
.moving {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -926,70 +1059,27 @@ $intro-time: 6s;
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 1rem; }
|
bottom: 1rem; }
|
||||||
|
|
||||||
/* -------- MENU ------- */
|
.lobby-icon {
|
||||||
/* Position and sizing of burger button */
|
cursor: pointer;
|
||||||
.bm-burger-button {
|
margin-left: 0.2rem; }
|
||||||
position: fixed;
|
|
||||||
width: 36px;
|
|
||||||
height: 30px;
|
|
||||||
left: 36px;
|
|
||||||
top: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Color/shape of burger icon bars */
|
.kick-player {
|
||||||
.bm-burger-bars {
|
color: red; }
|
||||||
background: #373a47;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Color/shape of burger icon bars on hover*/
|
.birthday-selected {
|
||||||
.bm-burger-bars-hover {
|
color: blue; }
|
||||||
background: #a90000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Position and sizing of clickable cross button */
|
ul {
|
||||||
.bm-cross-button {
|
margin-left: 0;
|
||||||
height: 24px;
|
list-style-type: none; }
|
||||||
width: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Color/shape of close button cross */
|
.font-preloader {
|
||||||
.bm-cross {
|
font-family: 'IndieFlower-Regular';
|
||||||
background: #bdc3c7;
|
width: 0;
|
||||||
}
|
height: 0; }
|
||||||
|
|
||||||
/*
|
.game-over p {
|
||||||
Sidebar wrapper styles
|
margin-bottom: 0.2rem;
|
||||||
Note: Beware of modifying this element as it can break the animations - you should not need to touch it in most cases
|
text-align: left;
|
||||||
*/
|
width: 100%;
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,31 +19,39 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
|
// const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
const autoprefixer = require("autoprefixer");
|
const autoprefixer = require("autoprefixer");
|
||||||
|
const CssUrlRelativePlugin = require('css-url-relative-plugin')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
app: './src/main.jsx',
|
app: './src/index.jsx',
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].bundle.js',
|
filename: './assets/[name].[hash].js',
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
},
|
},
|
||||||
|
optimization: {
|
||||||
|
runtimeChunk: 'single',
|
||||||
|
splitChunks: {
|
||||||
|
cacheGroups: {
|
||||||
|
vendor: {
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
name: 'vendors',
|
||||||
|
chunks: 'all',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CleanWebpackPlugin(),
|
new CleanWebpackPlugin(),
|
||||||
new HtmlWebpackPlugin({
|
// new FaviconsWebpackPlugin('./assets/img/tractor.svg'),
|
||||||
title: 'Alpha Centauri Farming',
|
|
||||||
filename: 'main.html',
|
|
||||||
meta: {viewport: 'width=device-width, initial-scale=1'},
|
|
||||||
}),
|
|
||||||
new FaviconsWebpackPlugin('./assets/img/tractor.svg'),
|
|
||||||
new MiniCssExtractPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: '[name].css',
|
filename: './assets/[name].[hash].css',
|
||||||
chunkFilename: '[id].css',
|
chunkFilename: './assets/[id].[hash].css',
|
||||||
}),
|
}),
|
||||||
new CopyPlugin([
|
new CopyPlugin([
|
||||||
{ from: './src/server/farm.scm', to: './[name].[ext]' },
|
{ from: './src/server/farm.scm', to: './[name].[ext]' },
|
||||||
@@ -57,6 +65,7 @@ module.exports = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
new CssUrlRelativePlugin()
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
@@ -71,11 +80,26 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// test: /mars-texture.png$/,
|
||||||
|
// loader: 'file-loader',
|
||||||
|
// options: {
|
||||||
|
// name: './assets/img/[name].[contenthash].[ext]',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
test: /\.(woff|woff2|eot|ttf|otf|svg|png|gif)$/,
|
test: /\.(svg|png|gif)$/,
|
||||||
use: [
|
loader: 'file-loader',
|
||||||
'file-loader',
|
options: {
|
||||||
],
|
name: './assets/img/[name].[hash].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: './assets/font/[name].[hash].[ext]',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.s[ac]ss$/i,
|
test: /\.s[ac]ss$/i,
|
||||||
|
|||||||
@@ -19,15 +19,54 @@
|
|||||||
const merge = require('webpack-merge');
|
const merge = require('webpack-merge');
|
||||||
const common = require('./webpack.common.js');
|
const common = require('./webpack.common.js');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
module.exports = function(env) {
|
module.exports = function(env) {
|
||||||
return merge(common, {
|
return merge(common, {
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
devtool: 'inline-source-map',
|
devtool: 'inline-source-map',
|
||||||
|
devServer: {
|
||||||
|
port: 9000,
|
||||||
|
contentBase: './dist',
|
||||||
|
hot: true,
|
||||||
|
proxy: {
|
||||||
|
'/websocket': {
|
||||||
|
target: 'ws://localhost:8080',
|
||||||
|
ws: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: [path.resolve(__dirname, 'src'),
|
modules: [path.resolve(__dirname, 'src'),
|
||||||
path.resolve(__dirname, env.assets),
|
path.resolve(__dirname, env.assets),
|
||||||
'node_modules']
|
'node_modules']
|
||||||
},
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
|
new ReactRefreshWebpackPlugin(),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
title: 'Alpha Centauri Farming',
|
||||||
|
filename: 'index.html',
|
||||||
|
meta: {viewport: 'width=device-width, initial-scale=1'},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
options: {
|
||||||
|
plugins: [require.resolve('react-refresh/babel')],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ const common = require('./webpack.common.js');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||||
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
|
||||||
module.exports = function(env) {
|
module.exports = function(env) {
|
||||||
return merge(common, {
|
return merge(common, {
|
||||||
@@ -31,8 +33,16 @@ module.exports = function(env) {
|
|||||||
path.resolve(__dirname, env.assets),
|
path.resolve(__dirname, env.assets),
|
||||||
'node_modules']
|
'node_modules']
|
||||||
},
|
},
|
||||||
|
plugins: [
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
title: 'Alpha Centauri Farming',
|
||||||
|
filename: 'main.html',
|
||||||
|
meta: {viewport: 'width=device-width, initial-scale=1'},
|
||||||
|
}),
|
||||||
|
],
|
||||||
optimization: {
|
optimization: {
|
||||||
minimizer: [new OptimizeCssAssetsPlugin({})],
|
minimize: true,
|
||||||
|
minimizer: [new OptimizeCssAssetsPlugin({}), new TerserPlugin()],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user