Compare commits
259 Commits
in-develop
...
TimerSongD
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da27399dda | ||
|
|
c98edc37a6 | ||
|
|
c21f254234 | ||
|
|
fd85a73608 | ||
|
|
ea7a5e11ba | ||
|
|
164708dcf5 | ||
|
|
eb5e69a59c | ||
|
|
b3c9f89f99 | ||
|
|
6b619604ec | ||
|
|
1ec1c0d13d | ||
|
|
0ab071693f | ||
|
|
1a11827ba3 | ||
|
|
a2d651cd7d | ||
| 0cb025edb9 | |||
| 6ea94fe658 | |||
|
|
ef5c1ce6e3 | ||
|
|
8c01c7fa7a | ||
|
|
72dd78137b | ||
| 71c918e9ee | |||
|
|
81f4d307a2 | ||
|
|
710438ec1b | ||
|
|
c14b66e892 | ||
|
|
8c69453506 | ||
|
|
a6b835bddf | ||
|
|
ca11151381 | ||
|
|
fa4e1ad5e3 | ||
|
|
295c61c7eb | ||
|
|
1c9af58264 | ||
| 6dc05e7123 | |||
| d1a9f94ee0 | |||
| edfb4ffe51 | |||
| be31de4660 | |||
| ea30e20585 | |||
| d7e370536e | |||
| 6811890531 | |||
| 5da0a02cc8 | |||
| 50713c5021 | |||
| d17edf7c4a | |||
| 84e257c17c | |||
| 925c848fda | |||
| 13bac113b7 | |||
| 068337e01b | |||
| 44d8ffbef2 | |||
|
|
ff611724e7 | ||
|
|
7f36d7f244 | ||
| eda85ea888 | |||
| f026a4fec6 | |||
|
|
b84255e00e | ||
|
|
84c17d185b | ||
|
|
3776167299 | ||
|
|
48ed6df6b4 | ||
|
|
2428048bd5 | ||
|
|
1440190ac3 | ||
|
|
3a51434f91 | ||
|
|
5b20909f80 | ||
|
|
00b5f9dced | ||
|
|
188a5e8a45 | ||
|
|
0638a38fc1 | ||
|
|
75fb865dad | ||
|
|
2cda94e4db | ||
|
|
d6f3bb2185 | ||
|
|
95d7ea5e1d | ||
|
|
6fb248bec4 | ||
|
|
7b5c188280 | ||
|
|
1c2736ac75 | ||
|
|
caa812217f | ||
|
|
c115fb91af | ||
|
|
b506afdade | ||
|
|
59cc64ada7 | ||
|
|
bd096df2c2 | ||
|
|
dfd3934b96 | ||
|
|
2f7f2955c1 | ||
|
|
fb8acbe228 | ||
|
|
be40ee0187 | ||
|
|
0c536b0f9b | ||
|
|
c85ab38142 | ||
|
|
c3f764f33d | ||
|
|
df493a5eba | ||
|
|
0447f7b0fe | ||
|
|
b1589032be | ||
|
|
55989ab8ce | ||
|
|
443f2da97d | ||
|
|
8f047cd7b5 | ||
|
|
bb2630f3d5 | ||
|
|
f44bf6bd02 | ||
|
|
3a120803e3 | ||
|
|
6e35067c18 | ||
|
|
30f797022c | ||
|
|
abc173a1ee | ||
|
|
3784cd790e | ||
|
|
f44c3932dc | ||
|
|
975207a6de | ||
|
|
545e830b3c | ||
|
|
977e9bb102 | ||
|
|
69bc55dc26 | ||
|
|
62e2b71ece | ||
|
|
cf9dbef882 | ||
|
|
09f3dc4e3e | ||
|
|
6ae5f1c2d2 | ||
|
|
b30420616a | ||
|
|
1134649197 | ||
|
|
5beebf9663 | ||
|
|
798005de2c | ||
|
|
e71369f7ff | ||
|
|
56ebe1347c | ||
|
|
7f8ed029b9 | ||
|
|
bc6182e29a | ||
|
|
dc81d9c3ca | ||
|
|
2c8db95ba7 | ||
|
|
1f64a2dfd0 | ||
|
|
0a6c2487bd | ||
|
|
e382cf95f2 | ||
|
|
14e6785c6f | ||
|
|
444a81abc3 | ||
|
|
d0676d9363 | ||
|
|
8f7e78efb5 | ||
|
|
cb7e3298fd | ||
|
|
c09f0eb1f9 | ||
|
|
a3203dd78e | ||
|
|
efbab12b10 | ||
|
|
8e823b4108 | ||
| 3165ff33b3 | |||
|
|
81abeef843 | ||
|
|
be26db953e | ||
|
|
76c7e44447 | ||
|
|
d9f6c7ee74 | ||
|
|
0e3165ed98 | ||
|
|
4bcf70d4dc | ||
|
|
fcc0b9d0dd | ||
|
|
cdc34b432e | ||
|
|
00daf37244 | ||
|
|
bab11b64a5 | ||
|
|
4b60fa88ee | ||
|
|
f3316145e7 | ||
|
|
53a72cc340 | ||
|
|
081fbda7b1 | ||
|
|
d051e3e603 | ||
|
|
5317c42c81 | ||
|
|
6085f6ebe2 | ||
|
|
ea6264e519 | ||
|
|
e3bce3889e | ||
|
|
b050e06ceb | ||
|
|
7631a10838 | ||
|
|
ca25338971 | ||
|
|
42e03e0878 | ||
|
|
9b81ee1e65 | ||
|
|
a4b0f890da | ||
|
|
a766b85a75 | ||
|
|
34ccddaea5 | ||
|
|
73a2fe3da2 | ||
|
|
d958b9730a | ||
|
|
9749d3eee8 | ||
|
|
1ecdb9a555 | ||
|
|
b101734fd7 | ||
|
|
123ecc7d3a | ||
|
|
c1f7a093ef | ||
|
|
5dda85248e | ||
|
|
5a3490af2e | ||
|
|
7f3d858320 | ||
|
|
e9dfbbd150 | ||
|
|
72e322675e | ||
|
|
ed3cb902e4 | ||
|
|
3c385e27b0 | ||
|
|
783cfd22e1 | ||
|
|
16a5b1ce2f | ||
|
|
6bfa8868bf | ||
|
|
748f72352f | ||
|
|
e12e48b4fb | ||
|
|
a302f0d24d | ||
|
|
3d9914c927 | ||
|
|
3af182b986 | ||
|
|
58269e917a | ||
|
|
172b26ed51 | ||
|
|
78aef47bc0 | ||
|
|
ea8de7881f | ||
|
|
e6fa522f39 | ||
|
|
6d7a8e4c50 | ||
|
|
c6c1c110f7 | ||
|
|
046a59e915 | ||
|
|
501b411e34 | ||
|
|
95c4a2fc8e | ||
|
|
ce02fc2b88 | ||
|
|
f525fc7ffc | ||
|
|
1bf3f00322 | ||
|
|
525adfdd04 | ||
|
|
fcdd4a8fc1 | ||
|
|
acc9972c80 | ||
|
|
5097e371f3 | ||
|
|
98755b6bed | ||
|
|
0d771088e1 | ||
|
|
43c577ef17 | ||
|
|
017673452b | ||
|
|
b8488c7289 | ||
|
|
cfde1f8d7f | ||
|
|
9144cb453e | ||
|
|
20a7fd7a3e | ||
|
|
33255d5ee6 | ||
|
|
ada778fe71 | ||
|
|
ab7494616b | ||
|
|
08bfb97399 | ||
|
|
062fe2e8bc | ||
|
|
b903e9b3c4 | ||
|
|
a40d30fec7 | ||
|
|
98bff669e9 | ||
|
|
c2d320ea97 | ||
|
|
9ee6bf3067 | ||
|
|
2198b8a8d9 | ||
|
|
7e3f13491d | ||
|
|
d28fd90b84 | ||
|
|
b8336ce3d2 | ||
|
|
b5ac747f77 | ||
|
|
369df7a0d1 | ||
|
|
06464945bd | ||
|
|
1bab3e12a5 | ||
|
|
a50c1a8d0d | ||
|
|
f780309572 | ||
|
|
2362333d46 | ||
|
|
0ab0cd75ba | ||
|
|
043b789da1 | ||
|
|
d7d6a49b98 | ||
|
|
39fa2edb3a | ||
|
|
e7d606f08e | ||
|
|
db6231c6d0 | ||
|
|
cd2f3c312e | ||
|
|
2eeca4e418 | ||
|
|
4daa379011 | ||
|
|
ba4173f029 | ||
|
|
af0db24b0a | ||
|
|
732abedba5 | ||
|
|
fe6b050702 | ||
|
|
b3feab7cb3 | ||
|
|
87a5b301c7 | ||
|
|
8fc7f606f9 | ||
|
|
fae5b8bcda | ||
|
|
ac6de04e68 | ||
|
|
d9a93f24fb | ||
|
|
754c8fea2e | ||
|
|
82f8d00625 | ||
|
|
56a1afe1cd | ||
|
|
796c3a2bc6 | ||
|
|
dd192692bd | ||
|
|
5a200a8a70 | ||
|
|
83130806a8 | ||
|
|
a5513bf87b | ||
|
|
547ea55300 | ||
|
|
3471ae54a5 | ||
|
|
c020269f6e | ||
|
|
f037412e9a | ||
|
|
5e1d53e96b | ||
|
|
8ac76dd17f | ||
|
|
efca808e1c | ||
|
|
dd230ad515 | ||
|
|
1dd345a290 | ||
|
|
e48df5df15 | ||
|
|
ef550f353d | ||
|
|
a6bd2495ab | ||
|
|
477afa142b | ||
|
|
d5735be2db | ||
|
|
f37928307c |
10
.gitignore
vendored
@@ -47,6 +47,9 @@ shelf/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
misc.xml
|
||||
uiDesigner.xml
|
||||
|
||||
|
||||
##############################
|
||||
## Eclipse
|
||||
@@ -75,6 +78,8 @@ dist/
|
||||
nbdist/
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
misc.xml
|
||||
compiler.xml
|
||||
|
||||
##############################
|
||||
## Visual Studio Code
|
||||
@@ -102,3 +107,8 @@ newgamesver-release-V1.jar
|
||||
server.properties
|
||||
gameserver.log.*
|
||||
gameserver.log
|
||||
|
||||
##############################
|
||||
## JPackage
|
||||
##############################
|
||||
jpackage-input
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
22
.idea/compiler.xml
generated
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="pism_framework" />
|
||||
<module name="pism_game" />
|
||||
<module name="pism_app" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||
<module name="pism_app" options="" />
|
||||
<module name="pism_framework" options="" />
|
||||
<module name="pism_game" options="" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
3
.idea/dictionaries/project.xml
generated
@@ -5,14 +5,17 @@
|
||||
<w>clid</w>
|
||||
<w>dcompile</w>
|
||||
<w>errorprone</w>
|
||||
<w>español</w>
|
||||
<w>flushnl</w>
|
||||
<w>gaaf</w>
|
||||
<w>gamelist</w>
|
||||
<w>pism</w>
|
||||
<w>playerlist</w>
|
||||
<w>tictactoe</w>
|
||||
<w>toop</w>
|
||||
<w>vmoptions</w>
|
||||
<w>xplugin</w>
|
||||
<w>yourturn</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
4
.idea/encodings.xml
generated
@@ -1,12 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$APPLICATION_HOME_DIR$/bin/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$APPLICATION_HOME_DIR$/bin/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/framework/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/framework/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/game/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/game/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/processors/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/processors/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
|
||||
3
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -2,7 +2,8 @@
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,java.lang.foreign.Arena,ofAuto,java.lang.foreign.Arena,global,org.toop.framework.audio.AudioPlayer,play" />
|
||||
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,java.lang.foreign.Arena,ofAuto,java.lang.foreign.Arena,global,org.toop.framework.audio.AudioPlayer,play,java.util.Map,remove,java.util.concurrent.Executors,newSingleThreadScheduledExecutor" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="WriteOnlyObject" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
19
.idea/misc.xml
generated
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="com.google.common.eventbus.Subscribe" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
15
.idea/resourceBundles.xml
generated
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ResourceBundleManager">
|
||||
<custom-resource-bundle>
|
||||
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization.properties" />
|
||||
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_de.properties" />
|
||||
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_es.properties" />
|
||||
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_fr.properties" />
|
||||
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_it.properties" />
|
||||
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_nl.properties" />
|
||||
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_zh.properties" />
|
||||
<base-name>localization</base-name>
|
||||
</custom-resource-bundle>
|
||||
</component>
|
||||
</project>
|
||||
98
app/pom.xml
@@ -1,15 +1,20 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.toop</groupId>
|
||||
<artifactId>pism_app</artifactId>
|
||||
<artifactId>pism</artifactId>
|
||||
<version>0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>app</artifactId>
|
||||
<version>0.1</version>
|
||||
|
||||
<properties>
|
||||
<main-class>org.toop.Main</main-class>
|
||||
<maven.compiler.source>25</maven.compiler.source>
|
||||
<maven.compiler.target>25</maven.compiler.target>
|
||||
|
||||
<maven.compiler.release>25</maven.compiler.release>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
@@ -19,18 +24,10 @@
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
<version>2.46.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.toop</groupId>
|
||||
<artifactId>pism_framework</artifactId>
|
||||
<version>0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.toop</groupId>
|
||||
<artifactId>pism_game</artifactId>
|
||||
<version>0.1</version>
|
||||
<scope>compile</scope>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -38,6 +35,30 @@
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>25</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>2.42.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
<version>2.42.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.toop</groupId>
|
||||
<artifactId>framework</artifactId>
|
||||
<version>0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.toop</groupId>
|
||||
<artifactId>game</artifactId>
|
||||
<version>0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@@ -68,6 +89,7 @@
|
||||
<mainClass>org.toop.Main</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
<finalName>pism</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
@@ -107,6 +129,56 @@
|
||||
</java>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.14.1</version>
|
||||
<configuration>
|
||||
<showWarnings>true</showWarnings>
|
||||
<fork>true</fork>
|
||||
<executable>${java.home}/bin/javac</executable>
|
||||
<source>25</source>
|
||||
<target>25</target>
|
||||
<release>25</release>
|
||||
<encoding>UTF-8</encoding>
|
||||
<compilerArgs>
|
||||
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
|
||||
<arg>
|
||||
-Xplugin:ErrorProne \
|
||||
</arg>
|
||||
<!-- TODO-->
|
||||
<!-- -Xep:RestrictedApi:ERROR \-->
|
||||
<!-- -XepOpt:RestrictedApi:annotation=org.toop.annotations.TestsOnly \-->
|
||||
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
|
||||
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
|
||||
<arg>-XDcompilePolicy=simple</arg>
|
||||
<arg>--should-stop=ifError=FLOW</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>2.42.0</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>2.42.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,21 +1,40 @@
|
||||
package org.toop;
|
||||
|
||||
import org.toop.app.App;
|
||||
import org.toop.framework.asset.ResourceLoader;
|
||||
import org.toop.framework.asset.ResourceManager;
|
||||
import org.toop.framework.audio.SoundManager;
|
||||
import org.toop.framework.audio.*;
|
||||
import org.toop.framework.networking.NetworkingClientEventListener;
|
||||
import org.toop.framework.networking.NetworkingClientManager;
|
||||
import org.toop.framework.networking.NetworkingInitializationException;
|
||||
import org.toop.framework.resource.ResourceLoader;
|
||||
import org.toop.framework.resource.ResourceManager;
|
||||
import org.toop.framework.resource.resources.MusicAsset;
|
||||
import org.toop.framework.resource.resources.SoundEffectAsset;
|
||||
|
||||
public final class Main {
|
||||
public static void main(String[] args) {
|
||||
static void main(String[] args) {
|
||||
initSystems();
|
||||
App.run(args);
|
||||
}
|
||||
|
||||
private static void initSystems() throws NetworkingInitializationException {
|
||||
private static void initSystems() {
|
||||
ResourceManager.loadAssets(new ResourceLoader("app/src/main/resources/assets"));
|
||||
new Thread(NetworkingClientManager::new).start();
|
||||
new Thread(SoundManager::new).start();
|
||||
new Thread(() -> new NetworkingClientEventListener(new NetworkingClientManager())).start();
|
||||
|
||||
new Thread(() -> {
|
||||
MusicManager<MusicAsset> musicManager = new MusicManager<>(ResourceManager.getAllOfTypeAndRemoveWrapper(MusicAsset.class), true);
|
||||
SoundEffectManager<SoundEffectAsset> soundEffectManager = new SoundEffectManager<>(ResourceManager.getAllOfType(SoundEffectAsset.class));
|
||||
AudioVolumeManager audioVolumeManager = new AudioVolumeManager()
|
||||
.registerManager(VolumeControl.MASTERVOLUME, musicManager)
|
||||
.registerManager(VolumeControl.MASTERVOLUME, soundEffectManager)
|
||||
.registerManager(VolumeControl.FX, soundEffectManager)
|
||||
.registerManager(VolumeControl.MUSIC, musicManager);
|
||||
|
||||
new AudioEventListener<>(
|
||||
musicManager,
|
||||
soundEffectManager,
|
||||
audioVolumeManager
|
||||
).initListeners("medium-button-click.wav");
|
||||
|
||||
}).start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,114 +1,113 @@
|
||||
package org.toop.app;
|
||||
|
||||
import org.toop.app.menu.MainMenu;
|
||||
import org.toop.app.menu.Menu;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.app.widget.display.SongDisplay;
|
||||
import org.toop.app.widget.popup.QuitPopup;
|
||||
import org.toop.app.widget.view.MainView;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.resource.ResourceManager;
|
||||
import org.toop.framework.resource.resources.CssAsset;
|
||||
import org.toop.local.AppContext;
|
||||
import org.toop.local.AppSettings;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.stage.Stage;
|
||||
import org.toop.framework.asset.ResourceManager;
|
||||
import org.toop.framework.asset.resources.CssAsset;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
|
||||
public final class App extends Application {
|
||||
private static Stage stage;
|
||||
private static StackPane root;
|
||||
private static Scene scene;
|
||||
|
||||
private static int width;
|
||||
private static int height;
|
||||
private static int width;
|
||||
|
||||
private static boolean isQuitting;
|
||||
|
||||
private static class QuitMenu extends Menu {
|
||||
public QuitMenu() {
|
||||
final Region background = createBackground("quit_background");
|
||||
|
||||
final Text sure = createText("Are you sure?");
|
||||
|
||||
final Button yes = createButton("Yes", () -> { stage.close(); });
|
||||
final Button no = createButton("No", () -> { pop(); isQuitting = false; });
|
||||
|
||||
final HBox buttons = new HBox(50, yes, no);
|
||||
buttons.setAlignment(Pos.CENTER);
|
||||
|
||||
final VBox box = new VBox(35, sure, buttons);
|
||||
box.getStyleClass().add("quit_box");
|
||||
box.setAlignment(Pos.CENTER);
|
||||
box.setMaxWidth(350);
|
||||
box.setMaxHeight(200);
|
||||
|
||||
pane = new StackPane(background, box);
|
||||
pane.getStylesheets().add(ResourceManager.get(CssAsset.class, "quit.css").getUrl());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void run(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) throws Exception {
|
||||
final StackPane root = new StackPane(new MainMenu().getPane());
|
||||
|
||||
final StackPane root = WidgetContainer.setup();
|
||||
final Scene scene = new Scene(root);
|
||||
scene.getStylesheets().add(((CssAsset) ResourceManager.get("app.css")).getUrl());
|
||||
|
||||
stage.setTitle("pism");
|
||||
stage.setTitle(AppContext.getString("app-title"));
|
||||
stage.titleProperty().bind(AppContext.bindToKey("app-title"));
|
||||
|
||||
stage.setWidth(1080);
|
||||
stage.setHeight(720);
|
||||
|
||||
scene.getRoot();
|
||||
|
||||
stage.setMinWidth(1080);
|
||||
stage.setMinHeight(720);
|
||||
|
||||
stage.setOnCloseRequest(event -> {
|
||||
event.consume();
|
||||
|
||||
if (!isQuitting) {
|
||||
quitPopup();
|
||||
}
|
||||
startQuit();
|
||||
});
|
||||
|
||||
stage.setScene(scene);
|
||||
stage.setResizable(false);
|
||||
stage.setResizable(true);
|
||||
|
||||
stage.show();
|
||||
|
||||
App.stage = stage;
|
||||
App.root = root;
|
||||
App.scene = scene;
|
||||
|
||||
App.width = (int)stage.getWidth();
|
||||
App.height = (int)stage.getHeight();
|
||||
|
||||
new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
|
||||
new EventFlow().addPostEvent(new AudioEvents.ChangeVolume(0.1)).asyncPostEvent();
|
||||
|
||||
App.isQuitting = false;
|
||||
|
||||
AppSettings.applySettings();
|
||||
new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
|
||||
|
||||
WidgetContainer.add(Pos.CENTER, new MainView());
|
||||
WidgetContainer.add(Pos.BOTTOM_RIGHT, new SongDisplay());
|
||||
}
|
||||
|
||||
public static void quitPopup() {
|
||||
public static void startQuit() {
|
||||
if (isQuitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
WidgetContainer.add(Pos.CENTER, new QuitPopup());
|
||||
isQuitting = true;
|
||||
push(new QuitMenu());
|
||||
}
|
||||
|
||||
public static void activate(Menu menu) {
|
||||
pop();
|
||||
push(menu);
|
||||
public static void stopQuit() {
|
||||
isQuitting = false;
|
||||
}
|
||||
|
||||
public static void push(Menu menu) {
|
||||
root.getChildren().addLast(menu.getPane());
|
||||
public static void quit() {
|
||||
stage.close();
|
||||
System.exit(0); // TODO: This is like dropping a nuke
|
||||
}
|
||||
|
||||
public static void pop() {
|
||||
root.getChildren().removeLast();
|
||||
public static void setFullscreen(boolean fullscreen) {
|
||||
stage.setFullScreen(fullscreen);
|
||||
|
||||
width = (int)stage.getWidth();
|
||||
height = (int)stage.getHeight();
|
||||
}
|
||||
|
||||
public static int getWidth() { return width; }
|
||||
public static int getHeight() { return height; }
|
||||
public static void setStyle(String theme, String layoutSize) {
|
||||
scene.getStylesheets().clear();
|
||||
|
||||
scene.getStylesheets().add(ResourceManager.<CssAsset>get("general.css").getUrl());
|
||||
scene.getStylesheets().add(ResourceManager.<CssAsset>get(theme + ".css").getUrl());
|
||||
scene.getStylesheets().add(ResourceManager.<CssAsset>get(layoutSize + ".css").getUrl());
|
||||
}
|
||||
|
||||
public static int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public static int getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
56
app/src/main/java/org/toop/app/GameInformation.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package org.toop.app;
|
||||
|
||||
public class GameInformation {
|
||||
public enum Type {
|
||||
TICTACTOE(2, 5),
|
||||
REVERSI(2, 10),
|
||||
CONNECT4(2, 7),
|
||||
BATTLESHIP(2, 5);
|
||||
|
||||
private final int playerCount;
|
||||
private final int maxDepth;
|
||||
|
||||
Type(int playerCount, int maxDepth) {
|
||||
this.playerCount = playerCount;
|
||||
this.maxDepth = maxDepth;
|
||||
}
|
||||
|
||||
public int getPlayerCount() {
|
||||
return playerCount;
|
||||
}
|
||||
|
||||
public int getMaxDepth() {
|
||||
return maxDepth;
|
||||
}
|
||||
|
||||
public String getTypeToString() {
|
||||
String name = this.name();
|
||||
return switch (name) {
|
||||
case "TICTACTOE" -> "TicTacToe";
|
||||
case "REVERSI" -> "Reversi";
|
||||
case "CONNECT4" -> "Connect4";
|
||||
case "BATTLESHIP" -> "Battleship";
|
||||
default -> name;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class Player {
|
||||
public String name = "";
|
||||
public boolean isHuman = true;
|
||||
public int computerDifficulty = 1;
|
||||
public int computerThinkTime = 1;
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
public final Player[] players;
|
||||
|
||||
public GameInformation(Type type) {
|
||||
this.type = type;
|
||||
players = new Player[type.getPlayerCount()];
|
||||
|
||||
for (int i = 0; i < players.length; i++) {
|
||||
players[i] = new Player();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package org.toop.app;
|
||||
|
||||
public enum GameType {
|
||||
TICTACTOE, REVERSI;
|
||||
|
||||
public static String toName(GameType type) {
|
||||
return switch (type) {
|
||||
case TICTACTOE -> "Tic Tac Toe";
|
||||
case REVERSI -> "Reversi";
|
||||
};
|
||||
}
|
||||
|
||||
public static GameType toType(String name) {
|
||||
return switch (name) {
|
||||
case "Tic Tac Toe" -> TICTACTOE;
|
||||
case "Reversi" -> REVERSI;
|
||||
|
||||
default -> TICTACTOE;
|
||||
};
|
||||
}
|
||||
}
|
||||
235
app/src/main/java/org/toop/app/Server.java
Normal file
@@ -0,0 +1,235 @@
|
||||
package org.toop.app;
|
||||
|
||||
import org.toop.app.game.Connect4Game;
|
||||
import org.toop.app.game.ReversiGame;
|
||||
import org.toop.app.game.TicTacToeGame;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.app.widget.popup.ChallengePopup;
|
||||
import org.toop.app.widget.popup.ErrorPopup;
|
||||
import org.toop.app.widget.popup.SendChallengePopup;
|
||||
import org.toop.app.widget.view.ServerView;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.clients.TournamentNetworkingClient;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
import org.toop.framework.networking.types.NetworkingConnector;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public final class Server {
|
||||
private String user = "";
|
||||
private long clientId = -1;
|
||||
|
||||
private final List<String> onlinePlayers = new CopyOnWriteArrayList<>();
|
||||
private final List<String> gameList = new CopyOnWriteArrayList<>();
|
||||
|
||||
private ServerView primary;
|
||||
private boolean isPolling = true;
|
||||
|
||||
private final AtomicBoolean isSingleGame = new AtomicBoolean(false);
|
||||
|
||||
private ScheduledExecutorService scheduler;
|
||||
|
||||
public static GameInformation.Type gameToType(String game) {
|
||||
if (game.equalsIgnoreCase("tic-tac-toe")) {
|
||||
return GameInformation.Type.TICTACTOE;
|
||||
} else if (game.equalsIgnoreCase("reversi")) {
|
||||
return GameInformation.Type.REVERSI;
|
||||
} else if (game.equalsIgnoreCase("connect4")) {
|
||||
return GameInformation.Type.CONNECT4;
|
||||
// } else if (game.equalsIgnoreCase("battleship")) {
|
||||
// return GameInformation.Type.BATTLESHIP;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Server(String ip, String port, String user) {
|
||||
if (ip.split("\\.").length < 4) {
|
||||
new ErrorPopup("\"" + ip + "\" " + AppContext.getString("is-not-a-valid-ip-address"));
|
||||
return;
|
||||
}
|
||||
|
||||
int parsedPort;
|
||||
|
||||
try {
|
||||
parsedPort = Integer.parseInt(port);
|
||||
} catch (NumberFormatException _) {
|
||||
new ErrorPopup("\"" + port + "\" " + AppContext.getString("is-not-a-valid-port"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.isEmpty() || user.matches("^[0-9].*")) {
|
||||
new ErrorPopup(AppContext.getString("invalid-username"));
|
||||
return;
|
||||
}
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(NetworkEvents.StartClient.class,
|
||||
new TournamentNetworkingClient(),
|
||||
new NetworkingConnector(ip, parsedPort, 10, 1, TimeUnit.SECONDS)
|
||||
)
|
||||
.onResponse(NetworkEvents.StartClientResponse.class, e -> {
|
||||
this.user = user;
|
||||
clientId = e.clientId();
|
||||
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendLogin(clientId, user)).postEvent();
|
||||
|
||||
primary = new ServerView(user, this::sendChallenge, this::disconnect);
|
||||
WidgetContainer.getCurrentView().transitionNext(primary);
|
||||
|
||||
startPopulateScheduler();
|
||||
populateGameList();
|
||||
|
||||
}).postEvent();
|
||||
|
||||
new EventFlow().listen(this::handleReceivedChallenge)
|
||||
.listen(this::handleMatchResponse);
|
||||
}
|
||||
|
||||
private void sendChallenge(String opponent) {
|
||||
if (!isPolling) return;
|
||||
|
||||
new SendChallengePopup(this, opponent, (playerInformation, gameType) -> {
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendChallenge(clientId, opponent, gameType)).postEvent();
|
||||
isSingleGame.set(true);
|
||||
});
|
||||
}
|
||||
|
||||
private void handleMatchResponse(NetworkEvents.GameMatchResponse response) {
|
||||
if (!isPolling) return;
|
||||
|
||||
String gameType = extractQuotedValue(response.gameType());
|
||||
|
||||
if (response.clientId() == clientId) {
|
||||
isPolling = false;
|
||||
onlinePlayers.clear();
|
||||
|
||||
final GameInformation.Type type = gameToType(gameType);
|
||||
if (type == null) {
|
||||
new ErrorPopup("Unsupported game type: " + gameType);
|
||||
return;
|
||||
}
|
||||
|
||||
final int myTurn = response.playerToMove().equalsIgnoreCase(response.opponent()) ? 1 : 0;
|
||||
|
||||
final GameInformation information = new GameInformation(type);
|
||||
//information.players[0] = playerInformation;
|
||||
information.players[0].name = user;
|
||||
information.players[0].isHuman = false;
|
||||
information.players[0].computerDifficulty = 5;
|
||||
information.players[0].computerThinkTime = 1;
|
||||
information.players[1].name = response.opponent();
|
||||
|
||||
Runnable onGameOverRunnable = isSingleGame.get()? null: this::gameOver;
|
||||
|
||||
|
||||
switch (type) {
|
||||
case TICTACTOE ->
|
||||
new TicTacToeGame(information, myTurn, this::forfeitGame, this::exitGame, this::sendMessage, onGameOverRunnable);
|
||||
case REVERSI ->
|
||||
new ReversiGame(information, myTurn, this::forfeitGame, this::exitGame, this::sendMessage, onGameOverRunnable);
|
||||
case CONNECT4 ->
|
||||
new Connect4Game(information, myTurn, this::forfeitGame, this::exitGame, this::sendMessage, onGameOverRunnable);
|
||||
default -> new ErrorPopup("Unsupported game type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReceivedChallenge(NetworkEvents.ChallengeResponse response) {
|
||||
if (!isPolling) return;
|
||||
|
||||
String challengerName = extractQuotedValue(response.challengerName());
|
||||
String gameType = extractQuotedValue(response.gameType());
|
||||
final String finalGameType = gameType;
|
||||
new ChallengePopup(challengerName, gameType, (playerInformation) -> {
|
||||
final int challengeId = Integer.parseInt(response.challengeId().replaceAll("\\D", ""));
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendAcceptChallenge(clientId, challengeId)).postEvent();
|
||||
isSingleGame.set(true);
|
||||
});
|
||||
}
|
||||
|
||||
private void sendMessage(String message) {
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendMessage(clientId, message)).postEvent();
|
||||
}
|
||||
|
||||
private void disconnect() {
|
||||
new EventFlow().addPostEvent(new NetworkEvents.CloseClient(clientId)).postEvent();
|
||||
isPolling = false;
|
||||
stopScheduler();
|
||||
primary.transitionPrevious();
|
||||
}
|
||||
|
||||
private void forfeitGame() {
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendForfeit(clientId)).postEvent();
|
||||
}
|
||||
|
||||
private void exitGame() {
|
||||
forfeitGame();
|
||||
startPopulateScheduler();
|
||||
}
|
||||
|
||||
private void gameOver(){
|
||||
startPopulateScheduler();
|
||||
}
|
||||
|
||||
private void startPopulateScheduler() {
|
||||
isPolling = true;
|
||||
isSingleGame.set(false);
|
||||
stopScheduler();
|
||||
|
||||
new EventFlow()
|
||||
.listen(NetworkEvents.PlayerlistResponse.class, e -> {
|
||||
if (e.clientId() == clientId) {
|
||||
onlinePlayers.clear();
|
||||
onlinePlayers.addAll(List.of(e.playerlist()));
|
||||
onlinePlayers.removeIf(name -> name.equalsIgnoreCase(user));
|
||||
primary.update(onlinePlayers);
|
||||
}
|
||||
}, false);
|
||||
|
||||
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
scheduler.scheduleAtFixedRate(() -> {
|
||||
if (isPolling) {
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendGetPlayerlist(clientId)).postEvent();
|
||||
} else {
|
||||
stopScheduler();
|
||||
}
|
||||
}, 0, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void stopScheduler() {
|
||||
if (scheduler != null && !scheduler.isShutdown()) {
|
||||
scheduler.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
private void gamesListFromServerHandler(NetworkEvents.GamelistResponse event) {
|
||||
gameList.clear();
|
||||
gameList.addAll(List.of(event.gamelist()));
|
||||
}
|
||||
|
||||
public void populateGameList() {
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendGetGamelist(clientId))
|
||||
.listen(NetworkEvents.GamelistResponse.class, this::gamesListFromServerHandler, true)
|
||||
.postEvent();
|
||||
}
|
||||
|
||||
public List<String> getGameList() {
|
||||
return gameList;
|
||||
}
|
||||
|
||||
private String extractQuotedValue(String s) {
|
||||
int first = s.indexOf('"');
|
||||
int last = s.lastIndexOf('"');
|
||||
if (first >= 0 && last > first) {
|
||||
return s.substring(first + 1, last);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
11
app/src/main/java/org/toop/app/canvas/Connect4Canvas.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package org.toop.app.canvas;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Connect4Canvas extends GameCanvas {
|
||||
public Connect4Canvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
|
||||
super(color, Color.TRANSPARENT, width, height, 7, 6, 10, true, onCellClicked,null);
|
||||
}
|
||||
}
|
||||
215
app/src/main/java/org/toop/app/canvas/GameCanvas.java
Normal file
@@ -0,0 +1,215 @@
|
||||
package org.toop.app.canvas;
|
||||
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.util.Duration;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public abstract class GameCanvas {
|
||||
protected record Cell(float x, float y, float width, float height) {
|
||||
public boolean isInside(double x, double y) {
|
||||
return x >= this.x && x <= this.x + width &&
|
||||
y >= this.y && y <= this.y + height;
|
||||
}
|
||||
}
|
||||
|
||||
protected final Canvas canvas;
|
||||
protected final GraphicsContext graphics;
|
||||
|
||||
protected final Color color;
|
||||
protected final Color backgroundColor;
|
||||
|
||||
protected final int width;
|
||||
protected final int height;
|
||||
|
||||
protected final int rowSize;
|
||||
protected final int columnSize;
|
||||
|
||||
protected final int gapSize;
|
||||
protected final boolean edges;
|
||||
|
||||
protected final Cell[] cells;
|
||||
|
||||
protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer<Integer> onCellClicked, Consumer<Integer> newCellEntered) {
|
||||
canvas = new Canvas(width, height);
|
||||
graphics = canvas.getGraphicsContext2D();
|
||||
|
||||
this.color = color;
|
||||
this.backgroundColor = backgroundColor;
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
this.rowSize = rowSize;
|
||||
this.columnSize = columnSize;
|
||||
|
||||
this.gapSize = gapSize;
|
||||
this.edges = edges;
|
||||
|
||||
cells = new Cell[rowSize * columnSize];
|
||||
|
||||
final float cellWidth = ((float) width - gapSize * rowSize - gapSize) / rowSize;
|
||||
final float cellHeight = ((float) height - gapSize * columnSize - gapSize) / columnSize;
|
||||
|
||||
for (int y = 0; y < columnSize; y++) {
|
||||
final float startY = y * cellHeight + y * gapSize + gapSize;
|
||||
|
||||
for (int x = 0; x < rowSize; x++) {
|
||||
final float startX = x * cellWidth + x * gapSize + gapSize;
|
||||
cells[x + y * rowSize] = new Cell(startX, startY, cellWidth, cellHeight);
|
||||
}
|
||||
}
|
||||
|
||||
canvas.setOnMouseClicked(event -> {
|
||||
if (event.getButton() != MouseButton.PRIMARY) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int column = (int) ((event.getX() / this.width) * rowSize);
|
||||
final int row = (int) ((event.getY() / this.height) * columnSize);
|
||||
|
||||
final Cell cell = cells[column + row * rowSize];
|
||||
|
||||
if (cell.isInside(event.getX(), event.getY())) {
|
||||
event.consume();
|
||||
onCellClicked.accept(column + row * rowSize);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
private void render() {
|
||||
graphics.setFill(backgroundColor);
|
||||
graphics.fillRect(0, 0, width, height);
|
||||
|
||||
graphics.setFill(color);
|
||||
|
||||
for (int x = 0; x < rowSize - 1; x++) {
|
||||
final float start = cells[x].x + cells[x].width;
|
||||
graphics.fillRect(start, gapSize, gapSize, height - gapSize * 2);
|
||||
}
|
||||
|
||||
for (int y = 0; y < columnSize - 1; y++) {
|
||||
final float start = cells[y * rowSize].y + cells[y * rowSize].height;
|
||||
graphics.fillRect(gapSize, start, width - gapSize * 2, gapSize);
|
||||
}
|
||||
|
||||
if (edges) {
|
||||
graphics.fillRect(0, 0, width, gapSize);
|
||||
graphics.fillRect(0, 0, gapSize, height);
|
||||
|
||||
graphics.fillRect(width - gapSize, 0, gapSize, height);
|
||||
graphics.fillRect(0, height - gapSize, width, gapSize);
|
||||
}
|
||||
}
|
||||
|
||||
public void fill(Color color, int cell) {
|
||||
final float x = cells[cell].x();
|
||||
final float y = cells[cell].y();
|
||||
|
||||
final float width = cells[cell].width();
|
||||
final float height = cells[cell].height();
|
||||
|
||||
graphics.setFill(color);
|
||||
graphics.fillRect(x, y, width, height);
|
||||
}
|
||||
|
||||
public void clear(int cell) {
|
||||
final float x = cells[cell].x();
|
||||
final float y = cells[cell].y();
|
||||
|
||||
final float width = cells[cell].width();
|
||||
final float height = cells[cell].height();
|
||||
|
||||
graphics.clearRect(x, y, width, height);
|
||||
|
||||
graphics.setFill(backgroundColor);
|
||||
graphics.fillRect(x, y, width, height);
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
for (int i = 0; i < cells.length; i++) {
|
||||
clear(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawDot(Color color, int cell) {
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
|
||||
graphics.setFill(color);
|
||||
graphics.fillOval(x, y, width, height);
|
||||
}
|
||||
|
||||
public void drawInnerDot(Color color, int cell, boolean slightlyBigger) {
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
float multiplier = slightlyBigger?1.4f:1.5f;
|
||||
|
||||
final float width = (cells[cell].width() - gapSize * 2)/multiplier;
|
||||
final float height = (cells[cell].height() - gapSize * 2)/multiplier;
|
||||
|
||||
float offset = slightlyBigger?5f:4f;
|
||||
|
||||
graphics.setFill(color);
|
||||
graphics.fillOval(x + width/offset, y + height/offset, width, height);
|
||||
}
|
||||
|
||||
private void drawDotScaled(Color color, int cell, double scale) {
|
||||
final float cx = cells[cell].x() + gapSize;
|
||||
final float cy = cells[cell].y() + gapSize;
|
||||
|
||||
final float fullWidth = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
|
||||
final float scaledWidth = (float)(fullWidth * scale);
|
||||
final float offsetX = (fullWidth - scaledWidth) / 2;
|
||||
|
||||
graphics.setFill(color);
|
||||
graphics.fillOval(cx + offsetX, cy, scaledWidth, height);
|
||||
}
|
||||
|
||||
public Timeline flipDot(Color fromColor, Color toColor, int cell) {
|
||||
final int steps = 60;
|
||||
final long duration = 250;
|
||||
final double interval = duration / (double) steps;
|
||||
|
||||
final Timeline timeline = new Timeline();
|
||||
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
final double t = i / (double) steps;
|
||||
final KeyFrame keyFrame = new KeyFrame(Duration.millis(i * interval),
|
||||
_ -> {
|
||||
clear(cell);
|
||||
|
||||
final double scale = t <= 0.5 ? 1 - 2 * t : 2 * t - 1;
|
||||
final Color currentColor = t < 0.5 ? fromColor : toColor;
|
||||
|
||||
drawDotScaled(currentColor, cell, scale);
|
||||
}
|
||||
);
|
||||
|
||||
timeline.getKeyFrames().add(keyFrame);
|
||||
}
|
||||
|
||||
return timeline;
|
||||
}
|
||||
|
||||
public Canvas getCanvas() {
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
84
app/src/main/java/org/toop/app/canvas/ReversiCanvas.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package org.toop.app.canvas;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import org.toop.game.records.Move;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class ReversiCanvas extends GameCanvas {
|
||||
private Move[] currentlyHighlightedMoves = null;
|
||||
public ReversiCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked, Consumer<Integer> newCellEntered) {
|
||||
super(color, new Color(0f,0.4f,0.2f,1f), width, height, 8, 8, 5, true, onCellClicked, newCellEntered);
|
||||
drawStartingDots();
|
||||
|
||||
final AtomicReference<Cell> lastHoveredCell = new AtomicReference<>(null);
|
||||
|
||||
canvas.setOnMouseMoved(event -> {
|
||||
double mouseX = event.getX();
|
||||
double mouseY = event.getY();
|
||||
int cellId = -1;
|
||||
|
||||
Cell hovered = null;
|
||||
for (Cell cell : cells) {
|
||||
if (cell.isInside(mouseX, mouseY)) {
|
||||
hovered = cell;
|
||||
cellId = turnCoordsIntoCellId(mouseX, mouseY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Cell previous = lastHoveredCell.get();
|
||||
|
||||
if (hovered != previous) {
|
||||
lastHoveredCell.set(hovered);
|
||||
newCellEntered.accept(cellId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setCurrentlyHighlightedMovesNull() {
|
||||
currentlyHighlightedMoves = null;
|
||||
}
|
||||
|
||||
public void drawHighlightDots(Move[] moves){
|
||||
if (currentlyHighlightedMoves != null){
|
||||
for (final Move move : currentlyHighlightedMoves){
|
||||
Color color = move.value() == 'W'? Color.BLACK: Color.WHITE;
|
||||
drawInnerDot(color, move.position(), true);
|
||||
}
|
||||
}
|
||||
currentlyHighlightedMoves = moves;
|
||||
if (moves != null) {
|
||||
for (Move move : moves) {
|
||||
Color color = move.value() == 'B' ? Color.BLACK : Color.WHITE;
|
||||
drawInnerDot(color, move.position(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int turnCoordsIntoCellId(double x, double y) {
|
||||
final int column = (int) ((x / this.width) * rowSize);
|
||||
final int row = (int) ((y / this.height) * columnSize);
|
||||
return column + row * rowSize;
|
||||
}
|
||||
|
||||
public void drawStartingDots() {
|
||||
drawDot(Color.BLACK, 28);
|
||||
drawDot(Color.WHITE, 36);
|
||||
drawDot(Color.BLACK, 35);
|
||||
drawDot(Color.WHITE, 27);
|
||||
}
|
||||
|
||||
public void drawLegalPosition(int cell, char player) {
|
||||
|
||||
Color innerColor;
|
||||
if (player == 'B') {
|
||||
innerColor = new Color(0.0f, 0.0f, 0.0f, 0.6f);
|
||||
}
|
||||
else {
|
||||
innerColor = new Color(1.0f, 1.0f, 1.0f, 0.75f);
|
||||
}
|
||||
drawInnerDot(innerColor, cell,false);
|
||||
}
|
||||
}
|
||||
38
app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package org.toop.app.canvas;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class TicTacToeCanvas extends GameCanvas {
|
||||
public TicTacToeCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
|
||||
super(color, Color.TRANSPARENT, width, height, 3, 3, 30, false, onCellClicked,null);
|
||||
}
|
||||
|
||||
public void drawX(Color color, int cell) {
|
||||
graphics.setStroke(color);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
|
||||
graphics.strokeLine(x, y, x + width, y + height);
|
||||
graphics.strokeLine(x + width, y, x, y + height);
|
||||
}
|
||||
|
||||
public void drawO(Color color, int cell) {
|
||||
graphics.setStroke(color);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
|
||||
graphics.strokeOval(x, y, width, height);
|
||||
}
|
||||
}
|
||||
122
app/src/main/java/org/toop/app/game/BaseGameThread.java
Normal file
@@ -0,0 +1,122 @@
|
||||
package org.toop.app.game;
|
||||
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.app.widget.view.GameView;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
import org.toop.game.Game;
|
||||
import org.toop.game.records.Move;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class BaseGameThread<TGame extends Game, TAI, TCanvas> {
|
||||
protected final GameInformation information;
|
||||
protected final int myTurn;
|
||||
protected final Runnable onGameOver;
|
||||
protected final BlockingQueue<Move> moveQueue;
|
||||
|
||||
protected final TGame game;
|
||||
protected final TAI ai;
|
||||
|
||||
protected final GameView primary;
|
||||
protected final TCanvas canvas;
|
||||
|
||||
protected final AtomicBoolean isRunning = new AtomicBoolean(true);
|
||||
|
||||
protected BaseGameThread(
|
||||
GameInformation information,
|
||||
int myTurn,
|
||||
Runnable onForfeit,
|
||||
Runnable onExit,
|
||||
Consumer<String> onMessage,
|
||||
Runnable onGameOver,
|
||||
Supplier<TGame> gameSupplier,
|
||||
Supplier<TAI> aiSupplier,
|
||||
Function<Consumer<Integer>, TCanvas> canvasFactory) {
|
||||
|
||||
this.information = information;
|
||||
this.myTurn = myTurn;
|
||||
this.onGameOver = onGameOver;
|
||||
this.moveQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
this.game = gameSupplier.get();
|
||||
this.ai = aiSupplier.get();
|
||||
|
||||
String type = information.type.getTypeToString();
|
||||
if (onForfeit == null || onExit == null) {
|
||||
primary = new GameView(null, () -> {
|
||||
isRunning.set(false);
|
||||
WidgetContainer.getCurrentView().transitionPrevious();
|
||||
}, null, type);
|
||||
} else {
|
||||
primary = new GameView(onForfeit, () -> {
|
||||
isRunning.set(false);
|
||||
onExit.run();
|
||||
}, onMessage, type);
|
||||
}
|
||||
|
||||
this.canvas = canvasFactory.apply(this::onCellClicked);
|
||||
|
||||
addCanvasToPrimary();
|
||||
|
||||
WidgetContainer.getCurrentView().transitionNext(primary);
|
||||
|
||||
if (onForfeit == null || onExit == null)
|
||||
new Thread(this::localGameThread).start();
|
||||
else
|
||||
new EventFlow()
|
||||
.listen(NetworkEvents.GameMoveResponse.class, this::onMoveResponse)
|
||||
.listen(NetworkEvents.YourTurnResponse.class, this::onYourTurnResponse);
|
||||
|
||||
setGameLabels(myTurn == 0);
|
||||
}
|
||||
|
||||
private void onCellClicked(int cell) {
|
||||
if (!isRunning.get()) return;
|
||||
|
||||
final int currentTurn = getCurrentTurn();
|
||||
if (!information.players[currentTurn].isHuman) return;
|
||||
|
||||
final char value = getSymbolForTurn(currentTurn);
|
||||
|
||||
try {
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
|
||||
protected void gameOver() {
|
||||
if (onGameOver != null) {
|
||||
isRunning.set(false);
|
||||
onGameOver.run();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setGameLabels(boolean isMe) {
|
||||
final int currentTurn = getCurrentTurn();
|
||||
final String turnName = getNameForTurn(currentTurn);
|
||||
|
||||
primary.nextPlayer(
|
||||
isMe,
|
||||
information.players[isMe ? 0 : 1].name,
|
||||
turnName,
|
||||
information.players[isMe ? 1 : 0].name
|
||||
);
|
||||
}
|
||||
|
||||
protected abstract void addCanvasToPrimary();
|
||||
|
||||
protected abstract int getCurrentTurn();
|
||||
protected abstract char getSymbolForTurn(int turn);
|
||||
protected abstract String getNameForTurn(int turn);
|
||||
|
||||
protected abstract void onMoveResponse(NetworkEvents.GameMoveResponse response);
|
||||
protected abstract void onYourTurnResponse(NetworkEvents.YourTurnResponse response);
|
||||
|
||||
protected abstract void localGameThread();
|
||||
}
|
||||
265
app/src/main/java/org/toop/app/game/Connect4Game.java
Normal file
@@ -0,0 +1,265 @@
|
||||
package org.toop.app.game;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.paint.Color;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.canvas.Connect4Canvas;
|
||||
import org.toop.app.widget.view.GameView;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
import org.toop.game.Connect4.Connect4;
|
||||
import org.toop.game.Connect4.Connect4AI;
|
||||
import org.toop.game.enumerators.GameState;
|
||||
import org.toop.game.records.Move;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Connect4Game {
|
||||
private final GameInformation information;
|
||||
|
||||
private final int myTurn;
|
||||
private Runnable onGameOver;
|
||||
private final BlockingQueue<Move> moveQueue;
|
||||
|
||||
private final Connect4 game;
|
||||
private final Connect4AI ai;
|
||||
private final int columnSize = 7;
|
||||
private final int rowSize = 6;
|
||||
|
||||
private final GameView primary;
|
||||
private final Connect4Canvas canvas;
|
||||
|
||||
private final AtomicBoolean isRunning;
|
||||
|
||||
public Connect4Game(GameInformation information, int myTurn, Runnable onForfeit, Runnable onExit, Consumer<String> onMessage, Runnable onGameOver) {
|
||||
this.information = information;
|
||||
this.myTurn = myTurn;
|
||||
this.onGameOver = onGameOver;
|
||||
moveQueue = new LinkedBlockingQueue<Move>();
|
||||
|
||||
|
||||
game = new Connect4();
|
||||
ai = new Connect4AI();
|
||||
|
||||
isRunning = new AtomicBoolean(true);
|
||||
|
||||
if (onForfeit == null || onExit == null) {
|
||||
primary = new GameView(null, () -> {
|
||||
isRunning.set(false);
|
||||
WidgetContainer.getCurrentView().transitionPrevious();
|
||||
}, null, "Connect4");
|
||||
} else {
|
||||
primary = new GameView(onForfeit, () -> {
|
||||
isRunning.set(false);
|
||||
onExit.run();
|
||||
}, onMessage, "Connect4");
|
||||
}
|
||||
|
||||
canvas = new Connect4Canvas(Color.GRAY,
|
||||
(App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3,
|
||||
(cell) -> {
|
||||
if (onForfeit == null || onExit == null) {
|
||||
if (information.players[game.getCurrentTurn()].isHuman) {
|
||||
final char value = game.getCurrentTurn() == 0? 'X' : 'O';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Move(cell%columnSize, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
} else {
|
||||
if (information.players[0].isHuman) {
|
||||
final char value = myTurn == 0? 'X' : 'O';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Move(cell%columnSize, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
primary.add(Pos.CENTER, canvas.getCanvas());
|
||||
WidgetContainer.getCurrentView().transitionNext(primary);
|
||||
|
||||
if (onForfeit == null || onExit == null) {
|
||||
new Thread(this::localGameThread).start();
|
||||
setGameLabels(information.players[0].isHuman);
|
||||
} else {
|
||||
new EventFlow()
|
||||
.listen(NetworkEvents.GameMoveResponse.class, this::onMoveResponse)
|
||||
.listen(NetworkEvents.YourTurnResponse.class, this::onYourTurnResponse);
|
||||
|
||||
setGameLabels(myTurn == 0);
|
||||
}
|
||||
updateCanvas();
|
||||
}
|
||||
|
||||
public Connect4Game(GameInformation information) {
|
||||
this(information, 0, null, null, null, null);
|
||||
}
|
||||
private void localGameThread() {
|
||||
while (isRunning.get()) {
|
||||
final int currentTurn = game.getCurrentTurn();
|
||||
final String currentValue = currentTurn == 0? "RED" : "BLUE";
|
||||
final int nextTurn = (currentTurn + 1) % information.type.getPlayerCount();
|
||||
|
||||
primary.nextPlayer(information.players[currentTurn].isHuman,
|
||||
information.players[currentTurn].name,
|
||||
currentValue,
|
||||
information.players[nextTurn].name);
|
||||
|
||||
Move move = null;
|
||||
|
||||
if (information.players[currentTurn].isHuman) {
|
||||
try {
|
||||
final Move wants = moveQueue.take();
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == wants.position() &&
|
||||
legalMove.value() == wants.value()) {
|
||||
move = wants;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
move = ai.findBestMove(game, information.players[currentTurn].computerDifficulty);
|
||||
|
||||
if (information.players[currentTurn].computerThinkTime > 0) {
|
||||
final long elapsedTime = System.currentTimeMillis() - start;
|
||||
final long sleepTime = Math.abs(information.players[currentTurn].computerThinkTime * 1000L - elapsedTime);
|
||||
|
||||
try {
|
||||
Thread.sleep((long)(sleepTime * Math.random()));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (move == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final GameState state = game.play(move);
|
||||
updateCanvas();
|
||||
/*
|
||||
if (move.value() == 'X') {
|
||||
canvas.drawX(Color.INDIANRED, move.position());
|
||||
} else if (move.value() == 'O') {
|
||||
canvas.drawO(Color.ROYALBLUE, move.position());
|
||||
}
|
||||
*/
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
primary.gameOver(true, information.players[currentTurn].name);
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
}
|
||||
|
||||
isRunning.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onMoveResponse(NetworkEvents.GameMoveResponse response) {
|
||||
if (!isRunning.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
char playerChar;
|
||||
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
playerChar = myTurn == 0? 'X' : 'O';
|
||||
} else {
|
||||
playerChar = myTurn == 0? 'O' : 'X';
|
||||
}
|
||||
|
||||
final Move move = new Move(Integer.parseInt(response.move()), playerChar);
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
primary.gameOver(true, information.players[0].name);
|
||||
gameOver();
|
||||
} else {
|
||||
primary.gameOver(false, information.players[1].name);
|
||||
gameOver();
|
||||
}
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
gameOver();
|
||||
}
|
||||
}
|
||||
|
||||
if (move.value() == 'X') {
|
||||
canvas.drawDot(Color.INDIANRED, move.position());
|
||||
} else if (move.value() == 'O') {
|
||||
canvas.drawDot(Color.ROYALBLUE, move.position());
|
||||
}
|
||||
|
||||
updateCanvas();
|
||||
setGameLabels(game.getCurrentTurn() == myTurn);
|
||||
}
|
||||
|
||||
private void gameOver() {
|
||||
if (onGameOver == null){
|
||||
return;
|
||||
}
|
||||
isRunning.set(false);
|
||||
onGameOver.run();
|
||||
}
|
||||
|
||||
private void onYourTurnResponse(NetworkEvents.YourTurnResponse response) {
|
||||
|
||||
if (!isRunning.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
moveQueue.clear();
|
||||
|
||||
int position = -1;
|
||||
|
||||
if (information.players[0].isHuman) {
|
||||
try {
|
||||
position = moveQueue.take().position();
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final Move move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
|
||||
assert move != null;
|
||||
position = move.position();
|
||||
}
|
||||
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short)position))
|
||||
.postEvent();
|
||||
}
|
||||
|
||||
private void updateCanvas() {
|
||||
canvas.clearAll();
|
||||
|
||||
for (int i = 0; i < game.getBoard().length; i++) {
|
||||
if (game.getBoard()[i] == 'X') {
|
||||
canvas.drawDot(Color.RED, i);
|
||||
} else if (game.getBoard()[i] == 'O') {
|
||||
canvas.drawDot(Color.BLUE, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setGameLabels(boolean isMe) {
|
||||
final int currentTurn = game.getCurrentTurn();
|
||||
final String currentValue = currentTurn == 0? "RED" : "BLUE";
|
||||
|
||||
primary.nextPlayer(isMe,
|
||||
information.players[isMe? 0 : 1].name,
|
||||
currentValue,
|
||||
information.players[isMe? 1 : 0].name);
|
||||
}
|
||||
}
|
||||
333
app/src/main/java/org/toop/app/game/ReversiGame.java
Normal file
@@ -0,0 +1,333 @@
|
||||
package org.toop.app.game;
|
||||
|
||||
import javafx.animation.SequentialTransition;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.canvas.ReversiCanvas;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.app.widget.view.GameView;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
import org.toop.game.enumerators.GameState;
|
||||
import org.toop.game.records.Move;
|
||||
import org.toop.game.reversi.Reversi;
|
||||
import org.toop.game.reversi.ReversiAI;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class ReversiGame {
|
||||
private final GameInformation information;
|
||||
|
||||
private final int myTurn;
|
||||
private final Runnable onGameOver;
|
||||
private final BlockingQueue<Move> moveQueue;
|
||||
|
||||
private final Reversi game;
|
||||
private final ReversiAI ai;
|
||||
|
||||
private final GameView primary;
|
||||
private final ReversiCanvas canvas;
|
||||
|
||||
private final AtomicBoolean isRunning;
|
||||
private final AtomicBoolean isPaused;
|
||||
|
||||
public ReversiGame(GameInformation information, int myTurn, Runnable onForfeit, Runnable onExit, Consumer<String> onMessage, Runnable onGameOver) {
|
||||
this.information = information;
|
||||
|
||||
this.myTurn = myTurn;
|
||||
this.onGameOver = onGameOver;
|
||||
moveQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
game = new Reversi();
|
||||
ai = new ReversiAI();
|
||||
|
||||
isRunning = new AtomicBoolean(true);
|
||||
isPaused = new AtomicBoolean(false);
|
||||
|
||||
if (onForfeit == null || onExit == null) {
|
||||
primary = new GameView(null, () -> {
|
||||
isRunning.set(false);
|
||||
WidgetContainer.getCurrentView().transitionPrevious();
|
||||
}, null, "Reversi");
|
||||
} else {
|
||||
primary = new GameView(onForfeit, () -> {
|
||||
isRunning.set(false);
|
||||
onExit.run();
|
||||
}, onMessage, "Reversi");
|
||||
}
|
||||
|
||||
canvas = new ReversiCanvas(Color.BLACK,
|
||||
(App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3,
|
||||
(cell) -> {
|
||||
if (onForfeit == null || onExit == null) {
|
||||
if (information.players[game.getCurrentTurn()].isHuman) {
|
||||
final char value = game.getCurrentTurn() == 0? 'B' : 'W';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
} else {
|
||||
if (information.players[0].isHuman) {
|
||||
final char value = myTurn == 0? 'B' : 'W';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
},this::highlightCells);
|
||||
|
||||
|
||||
|
||||
primary.add(Pos.CENTER, canvas.getCanvas());
|
||||
WidgetContainer.getCurrentView().transitionNext(primary);
|
||||
|
||||
if (onForfeit == null || onExit == null) {
|
||||
new Thread(this::localGameThread).start();
|
||||
setGameLabels(information.players[0].isHuman);
|
||||
} else {
|
||||
new EventFlow()
|
||||
.listen(NetworkEvents.GameMoveResponse.class, this::onMoveResponse)
|
||||
.listen(NetworkEvents.YourTurnResponse.class, this::onYourTurnResponse);
|
||||
|
||||
setGameLabels(myTurn == 0);
|
||||
}
|
||||
|
||||
updateCanvas(false);
|
||||
}
|
||||
|
||||
public ReversiGame(GameInformation information) {
|
||||
this(information, 0, null, null, null,null);
|
||||
}
|
||||
|
||||
private void localGameThread() {
|
||||
while (isRunning.get()) {
|
||||
if (isPaused.get()) {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException _) {}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
final int currentTurn = game.getCurrentTurn();
|
||||
final String currentValue = currentTurn == 0? "BLACK" : "WHITE";
|
||||
final int nextTurn = (currentTurn + 1) % information.type.getPlayerCount();
|
||||
|
||||
primary.nextPlayer(information.players[currentTurn].isHuman,
|
||||
information.players[currentTurn].name,
|
||||
currentValue,
|
||||
information.players[nextTurn].name);
|
||||
|
||||
Move move = null;
|
||||
|
||||
if (information.players[currentTurn].isHuman) {
|
||||
try {
|
||||
final Move wants = moveQueue.take();
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == wants.position() &&
|
||||
legalMove.value() == wants.value()) {
|
||||
move = wants;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
move = ai.findBestMove(game, information.players[currentTurn].computerDifficulty);
|
||||
|
||||
if (information.players[currentTurn].computerThinkTime > 0) {
|
||||
final long elapsedTime = System.currentTimeMillis() - start;
|
||||
final long sleepTime = information.players[currentTurn].computerThinkTime * 1000L - elapsedTime;
|
||||
|
||||
try {
|
||||
Thread.sleep((long) (sleepTime * Math.random()));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (move == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
canvas.setCurrentlyHighlightedMovesNull();
|
||||
final GameState state = game.play(move);
|
||||
updateCanvas(true);
|
||||
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.TURN_SKIPPED){
|
||||
continue;
|
||||
}
|
||||
int winningPLayerNumber = getPlayerNumberWithHighestScore();
|
||||
if (state == GameState.WIN && winningPLayerNumber > -1) {
|
||||
primary.gameOver(true, information.players[winningPLayerNumber].name);
|
||||
} else if (state == GameState.DRAW || winningPLayerNumber == -1) {
|
||||
primary.gameOver(false, "");
|
||||
}
|
||||
|
||||
isRunning.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getPlayerNumberWithHighestScore(){
|
||||
Reversi.Score score = game.getScore();
|
||||
if (score.player1Score() > score.player2Score()) return 0;
|
||||
if (score.player1Score() < score.player2Score()) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void onMoveResponse(NetworkEvents.GameMoveResponse response) {
|
||||
if (!isRunning.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
char playerChar;
|
||||
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
playerChar = myTurn == 0? 'B' : 'W';
|
||||
} else {
|
||||
playerChar = myTurn == 0? 'W' : 'B';
|
||||
}
|
||||
|
||||
final Move move = new Move(Integer.parseInt(response.move()), playerChar);
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
primary.gameOver(true, information.players[0].name);
|
||||
gameOver();
|
||||
} else {
|
||||
primary.gameOver(false, information.players[1].name);
|
||||
gameOver();
|
||||
}
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
game.play(move);
|
||||
}
|
||||
}
|
||||
|
||||
updateCanvas(false);
|
||||
setGameLabels(game.getCurrentTurn() == myTurn);
|
||||
}
|
||||
|
||||
private void gameOver() {
|
||||
if (onGameOver == null){
|
||||
return;
|
||||
}
|
||||
isRunning.set(false);
|
||||
onGameOver.run();
|
||||
}
|
||||
|
||||
private void onYourTurnResponse(NetworkEvents.YourTurnResponse response) {
|
||||
if (!isRunning.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
moveQueue.clear();
|
||||
|
||||
int position = -1;
|
||||
|
||||
if (information.players[0].isHuman) {
|
||||
try {
|
||||
position = moveQueue.take().position();
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final Move move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
|
||||
assert move != null;
|
||||
position = move.position();
|
||||
}
|
||||
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short) position))
|
||||
.postEvent();
|
||||
}
|
||||
|
||||
private void updateCanvas(boolean animate) {
|
||||
// Todo: this is very inefficient. still very fast but if the grid is bigger it might cause issues. improve.
|
||||
canvas.clearAll();
|
||||
|
||||
for (int i = 0; i < game.getBoard().length; i++) {
|
||||
if (game.getBoard()[i] == 'B') {
|
||||
canvas.drawDot(Color.BLACK, i);
|
||||
} else if (game.getBoard()[i] == 'W') {
|
||||
canvas.drawDot(Color.WHITE, i);
|
||||
}
|
||||
}
|
||||
|
||||
final Move[] flipped = game.getMostRecentlyFlippedPieces();
|
||||
|
||||
final SequentialTransition animation = new SequentialTransition();
|
||||
isPaused.set(true);
|
||||
|
||||
final Color fromColor = game.getCurrentPlayer() == 'W'? Color.WHITE : Color.BLACK;
|
||||
final Color toColor = game.getCurrentPlayer() == 'W'? Color.BLACK : Color.WHITE;
|
||||
|
||||
if (animate && flipped != null) {
|
||||
for (final Move flip : flipped) {
|
||||
canvas.clear(flip.position());
|
||||
canvas.drawDot(fromColor, flip.position());
|
||||
animation.getChildren().addFirst(canvas.flipDot(fromColor, toColor, flip.position()));
|
||||
}
|
||||
}
|
||||
|
||||
animation.setOnFinished(_ -> {
|
||||
isPaused.set(false);
|
||||
|
||||
if (information.players[game.getCurrentTurn()].isHuman) {
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Move legalMove : legalMoves) {
|
||||
canvas.drawLegalPosition(legalMove.position(), game.getCurrentPlayer());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
animation.play();
|
||||
}
|
||||
|
||||
private void setGameLabels(boolean isMe) {
|
||||
final int currentTurn = game.getCurrentTurn();
|
||||
final String currentValue = currentTurn == 0? "BLACK" : "WHITE";
|
||||
|
||||
primary.nextPlayer(isMe,
|
||||
information.players[isMe? 0 : 1].name,
|
||||
currentValue,
|
||||
information.players[isMe? 1 : 0].name);
|
||||
}
|
||||
|
||||
private void highlightCells(int cellEntered) {
|
||||
if (information.players[game.getCurrentTurn()].isHuman) {
|
||||
Move[] legalMoves = game.getLegalMoves();
|
||||
boolean isLegalMove = false;
|
||||
for (Move move : legalMoves) {
|
||||
if (move.position() == cellEntered){
|
||||
isLegalMove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cellEntered >= 0){
|
||||
Move[] moves = null;
|
||||
if (isLegalMove) {
|
||||
moves = game.getFlipsForPotentialMove(
|
||||
new Point(cellEntered%game.getColumnSize(),cellEntered/game.getRowSize()),
|
||||
game.getCurrentPlayer());
|
||||
}
|
||||
canvas.drawHighlightDots(moves);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
250
app/src/main/java/org/toop/app/game/TicTacToeGame.java
Normal file
@@ -0,0 +1,250 @@
|
||||
package org.toop.app.game;
|
||||
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.canvas.TicTacToeCanvas;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.app.widget.view.GameView;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
import org.toop.game.enumerators.GameState;
|
||||
import org.toop.game.records.Move;
|
||||
import org.toop.game.tictactoe.TicTacToe;
|
||||
import org.toop.game.tictactoe.TicTacToeAI;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class TicTacToeGame {
|
||||
private final GameInformation information;
|
||||
|
||||
private final int myTurn;
|
||||
private final Runnable onGameOver;
|
||||
private final BlockingQueue<Move> moveQueue;
|
||||
|
||||
private final TicTacToe game;
|
||||
private final TicTacToeAI ai;
|
||||
|
||||
private final GameView primary;
|
||||
private final TicTacToeCanvas canvas;
|
||||
|
||||
private final AtomicBoolean isRunning;
|
||||
|
||||
public TicTacToeGame(GameInformation information, int myTurn, Runnable onForfeit, Runnable onExit, Consumer<String> onMessage, Runnable onGameOver) {
|
||||
this.information = information;
|
||||
|
||||
this.myTurn = myTurn;
|
||||
this.onGameOver = onGameOver;
|
||||
moveQueue = new LinkedBlockingQueue<Move>();
|
||||
|
||||
game = new TicTacToe();
|
||||
ai = new TicTacToeAI();
|
||||
|
||||
isRunning = new AtomicBoolean(true);
|
||||
|
||||
if (onForfeit == null || onExit == null) {
|
||||
primary = new GameView(null, () -> {
|
||||
isRunning.set(false);
|
||||
WidgetContainer.getCurrentView().transitionPrevious();
|
||||
}, null, "TicTacToe");
|
||||
} else {
|
||||
primary = new GameView(onForfeit, () -> {
|
||||
isRunning.set(false);
|
||||
onExit.run();
|
||||
}, onMessage, "TicTacToe");
|
||||
}
|
||||
|
||||
canvas = new TicTacToeCanvas(Color.GRAY,
|
||||
(App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3,
|
||||
(cell) -> {
|
||||
if (onForfeit == null || onExit == null) {
|
||||
if (information.players[game.getCurrentTurn()].isHuman) {
|
||||
final char value = game.getCurrentTurn() == 0? 'X' : 'O';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
} else {
|
||||
if (information.players[0].isHuman) {
|
||||
final char value = myTurn == 0? 'X' : 'O';
|
||||
|
||||
try {
|
||||
moveQueue.put(new Move(cell, value));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
primary.add(Pos.CENTER, canvas.getCanvas());
|
||||
WidgetContainer.getCurrentView().transitionNext(primary);
|
||||
|
||||
if (onForfeit == null || onExit == null) {
|
||||
new Thread(this::localGameThread).start();
|
||||
} else {
|
||||
new EventFlow()
|
||||
.listen(NetworkEvents.GameMoveResponse.class, this::onMoveResponse)
|
||||
.listen(NetworkEvents.YourTurnResponse.class, this::onYourTurnResponse);
|
||||
|
||||
setGameLabels(myTurn == 0);
|
||||
}
|
||||
}
|
||||
|
||||
public TicTacToeGame(GameInformation information) {
|
||||
this(information, 0, null, null, null, null);
|
||||
}
|
||||
|
||||
private void localGameThread() {
|
||||
while (isRunning.get()) {
|
||||
final int currentTurn = game.getCurrentTurn();
|
||||
final String currentValue = currentTurn == 0? "X" : "O";
|
||||
final int nextTurn = (currentTurn + 1) % information.type.getPlayerCount();
|
||||
|
||||
primary.nextPlayer(information.players[currentTurn].isHuman,
|
||||
information.players[currentTurn].name,
|
||||
currentValue,
|
||||
information.players[nextTurn].name);
|
||||
|
||||
Move move = null;
|
||||
|
||||
if (information.players[currentTurn].isHuman) {
|
||||
try {
|
||||
final Move wants = moveQueue.take();
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == wants.position() &&
|
||||
legalMove.value() == wants.value()) {
|
||||
move = wants;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
move = ai.findBestMove(game, information.players[currentTurn].computerDifficulty);
|
||||
|
||||
if (information.players[currentTurn].computerThinkTime > 0) {
|
||||
final long elapsedTime = System.currentTimeMillis() - start;
|
||||
final long sleepTime = information.players[currentTurn].computerThinkTime * 1000L - elapsedTime;
|
||||
|
||||
try {
|
||||
Thread.sleep((long)(sleepTime * Math.random()));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (move == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (move.value() == 'X') {
|
||||
canvas.drawX(Color.INDIANRED, move.position());
|
||||
} else if (move.value() == 'O') {
|
||||
canvas.drawO(Color.ROYALBLUE, move.position());
|
||||
}
|
||||
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
primary.gameOver(true, information.players[currentTurn].name);
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
}
|
||||
|
||||
isRunning.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onMoveResponse(NetworkEvents.GameMoveResponse response) {
|
||||
if (!isRunning.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
char playerChar;
|
||||
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
playerChar = myTurn == 0? 'X' : 'O';
|
||||
} else {
|
||||
playerChar = myTurn == 0? 'O' : 'X';
|
||||
}
|
||||
|
||||
final Move move = new Move(Integer.parseInt(response.move()), playerChar);
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
primary.gameOver(true, information.players[0].name);
|
||||
gameOver();
|
||||
} else {
|
||||
primary.gameOver(false, information.players[1].name);
|
||||
gameOver();
|
||||
}
|
||||
} else if (state == GameState.DRAW) {
|
||||
if(game.getLegalMoves().length == 0) { //only return draw in online multiplayer if the game is actually over.
|
||||
primary.gameOver(false, "");
|
||||
gameOver();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (move.value() == 'X') {
|
||||
canvas.drawX(Color.RED, move.position());
|
||||
} else if (move.value() == 'O') {
|
||||
canvas.drawO(Color.BLUE, move.position());
|
||||
}
|
||||
|
||||
setGameLabels(game.getCurrentTurn() == myTurn);
|
||||
}
|
||||
|
||||
private void gameOver() {
|
||||
if (onGameOver == null){
|
||||
return;
|
||||
}
|
||||
isRunning.set(false);
|
||||
onGameOver.run();
|
||||
}
|
||||
|
||||
private void onYourTurnResponse(NetworkEvents.YourTurnResponse response) {
|
||||
if (!isRunning.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
moveQueue.clear();
|
||||
|
||||
int position = -1;
|
||||
|
||||
if (information.players[0].isHuman) {
|
||||
try {
|
||||
position = moveQueue.take().position();
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final Move move;
|
||||
move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
assert move != null;
|
||||
position = move.position();
|
||||
}
|
||||
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short)position))
|
||||
.postEvent();
|
||||
}
|
||||
|
||||
private void setGameLabels(boolean isMe) {
|
||||
final int currentTurn = game.getCurrentTurn();
|
||||
final String currentValue = currentTurn == 0? "X" : "O";
|
||||
|
||||
primary.nextPlayer(isMe,
|
||||
information.players[isMe? 0 : 1].name,
|
||||
currentValue,
|
||||
information.players[isMe? 1 : 0].name);
|
||||
}
|
||||
}
|
||||
176
app/src/main/java/org/toop/app/game/TicTacToeGameThread.java
Normal file
@@ -0,0 +1,176 @@
|
||||
package org.toop.app.game;
|
||||
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.canvas.TicTacToeCanvas;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
import org.toop.game.enumerators.GameState;
|
||||
import org.toop.game.records.Move;
|
||||
import org.toop.game.tictactoe.TicTacToe;
|
||||
import org.toop.game.tictactoe.TicTacToeAI;
|
||||
import java.util.function.Consumer;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
public final class TicTacToeGameThread extends BaseGameThread<TicTacToe, TicTacToeAI, TicTacToeCanvas> {
|
||||
public TicTacToeGameThread(GameInformation info, int myTurn, Runnable onForfeit, Runnable onExit, Consumer<String> onMessage, Runnable onGameOver) {
|
||||
super(info, myTurn, onForfeit, onExit, onMessage, onGameOver,
|
||||
TicTacToe::new,
|
||||
TicTacToeAI::new,
|
||||
clickHandler -> new TicTacToeCanvas(Color.GRAY, (App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3, clickHandler)
|
||||
);
|
||||
}
|
||||
|
||||
public TicTacToeGameThread(GameInformation info) {
|
||||
this(info, 0, null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addCanvasToPrimary() {
|
||||
primary.add(Pos.CENTER, canvas.getCanvas());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getCurrentTurn() {
|
||||
return game.getCurrentTurn();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected char getSymbolForTurn(int turn) {
|
||||
return turn == 0 ? 'X' : 'O';
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getNameForTurn(int turn) {
|
||||
return turn == 0 ? "X" : "O";
|
||||
}
|
||||
|
||||
private void drawMove(Move move) {
|
||||
if (move.value() == 'X') canvas.drawX(Color.RED, move.position());
|
||||
else canvas.drawO(Color.BLUE, move.position());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMoveResponse(NetworkEvents.GameMoveResponse response) {
|
||||
if (!isRunning.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
char playerChar;
|
||||
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
playerChar = myTurn == 0? 'X' : 'O';
|
||||
} else {
|
||||
playerChar = myTurn == 0? 'O' : 'X';
|
||||
}
|
||||
|
||||
final Move move = new Move(Integer.parseInt(response.move()), playerChar);
|
||||
final GameState state = game.play(move);
|
||||
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
if (response.player().equalsIgnoreCase(information.players[0].name)) {
|
||||
primary.gameOver(true, information.players[0].name);
|
||||
gameOver();
|
||||
} else {
|
||||
primary.gameOver(false, information.players[1].name);
|
||||
gameOver();
|
||||
}
|
||||
} else if (state == GameState.DRAW) {
|
||||
if (game.getLegalMoves().length == 0) {
|
||||
primary.gameOver(false, "");
|
||||
gameOver();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawMove(move);
|
||||
setGameLabels(game.getCurrentTurn() == myTurn);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onYourTurnResponse(NetworkEvents.YourTurnResponse response) {
|
||||
if (!isRunning.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
moveQueue.clear();
|
||||
|
||||
int position = -1;
|
||||
|
||||
if (information.players[0].isHuman) {
|
||||
try {
|
||||
position = moveQueue.take().position();
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final Move move;
|
||||
if (information.players[1].name.equalsIgnoreCase("pism")) {
|
||||
move = ai.findWorstMove(game,9);
|
||||
}else{
|
||||
move = ai.findBestMove(game, information.players[0].computerDifficulty);
|
||||
}
|
||||
|
||||
assert move != null;
|
||||
position = move.position();
|
||||
}
|
||||
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short)position))
|
||||
.postEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void localGameThread() {
|
||||
while (isRunning.get()) {
|
||||
final int currentTurn = game.getCurrentTurn();
|
||||
setGameLabels(currentTurn == myTurn);
|
||||
|
||||
Move move = null;
|
||||
|
||||
if (information.players[currentTurn].isHuman) {
|
||||
try {
|
||||
final Move wants = moveQueue.take();
|
||||
final Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
for (final Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == wants.position() &&
|
||||
legalMove.value() == wants.value()) {
|
||||
move = wants;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException _) {}
|
||||
} else {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
move = ai.findBestMove(game, information.players[currentTurn].computerDifficulty);
|
||||
|
||||
if (information.players[currentTurn].computerThinkTime > 0) {
|
||||
final long elapsedTime = System.currentTimeMillis() - start;
|
||||
final long sleepTime = information.players[currentTurn].computerThinkTime * 1000L - elapsedTime;
|
||||
|
||||
try {
|
||||
Thread.sleep((long)(sleepTime * Math.random()));
|
||||
} catch (InterruptedException _) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (move == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final GameState state = game.play(move);
|
||||
drawMove(move);
|
||||
|
||||
if (state != GameState.NORMAL) {
|
||||
if (state == GameState.WIN) {
|
||||
primary.gameOver(information.players[currentTurn].isHuman, information.players[currentTurn].name);
|
||||
} else if (state == GameState.DRAW) {
|
||||
primary.gameOver(false, "");
|
||||
}
|
||||
|
||||
isRunning.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package org.toop.app.menu;
|
||||
|
||||
import org.toop.framework.asset.ResourceManager;
|
||||
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public final class CreditsMenu extends Menu {
|
||||
private Locale currentLocale = AppContext.getLocale();
|
||||
private LocalizationAsset loc = ResourceManager.get("localization.properties");
|
||||
public CreditsMenu() {
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.toop.app.menu;
|
||||
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.toop.app.GameType;
|
||||
|
||||
public class GameSelectMenu extends Menu {
|
||||
public GameSelectMenu(GameType type) {
|
||||
final Region background = createBackground();
|
||||
|
||||
final ComboBox<String> selectedGame = new ComboBox<>();
|
||||
selectedGame.getItems().add(GameType.toName(GameType.TICTACTOE));
|
||||
selectedGame.getItems().add(GameType.toName(GameType.REVERSI));
|
||||
selectedGame.setValue(GameType.toName(type));
|
||||
|
||||
final ComboBox<String> selectedMode = new ComboBox<>();
|
||||
selectedMode.getItems().add("Local");
|
||||
selectedMode.getItems().add("Online");
|
||||
selectedMode.setValue("Local");
|
||||
|
||||
final HBox selectedContainer = new HBox(10, selectedGame, selectedMode);
|
||||
|
||||
final TextField serverIpField = new TextField();
|
||||
serverIpField.setPromptText("Enter here your server ip address");
|
||||
|
||||
VBox box = new VBox(selectedContainer, serverIpField);
|
||||
pane = new StackPane(background, box);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.toop.app.menu;
|
||||
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.GameType;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.*;
|
||||
import org.toop.app.menu.game.TicTacToeMenu;
|
||||
import org.toop.game.tictactoe.TicTacToe;
|
||||
|
||||
public final class MainMenu extends Menu {
|
||||
public MainMenu() {
|
||||
final Region background = createBackground();
|
||||
|
||||
final Button tictactoe = createButton("Tic Tac Toe", () -> { App.activate(new TicTacToeMenu(new TicTacToe("player 1", true, "player 2", true))); });
|
||||
final Button reversi = createButton("Reversi", () -> { App.activate(new GameSelectMenu(GameType.REVERSI)); });
|
||||
|
||||
final VBox gamesBox = new VBox(10, tictactoe, reversi);
|
||||
gamesBox.setAlignment(Pos.TOP_LEFT);
|
||||
gamesBox.setPickOnBounds(false);
|
||||
gamesBox.setTranslateY(50);
|
||||
gamesBox.setTranslateX(25);
|
||||
|
||||
final Button credits = createButton("Credits", () -> { App.push(new CreditsMenu()); });
|
||||
final Button options = createButton("Options", () -> { App.push(new OptionsMenu()); });
|
||||
final Button quit = createButton("Quit", () -> { App.quitPopup(); });
|
||||
|
||||
final VBox controlBox = new VBox(10, credits, options, quit);
|
||||
controlBox.setAlignment(Pos.BOTTOM_LEFT);
|
||||
controlBox.setPickOnBounds(false);
|
||||
controlBox.setTranslateY(-50);
|
||||
controlBox.setTranslateX(25);
|
||||
|
||||
pane = new StackPane(background, gamesBox, controlBox);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package org.toop.app.menu;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.text.Text;
|
||||
|
||||
public abstract class Menu {
|
||||
protected Pane pane;
|
||||
public Pane getPane() { return pane; }
|
||||
|
||||
public Region createBackground(String css) {
|
||||
final Region background = new Region();
|
||||
background.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
||||
background.getStyleClass().add(css);
|
||||
|
||||
return background;
|
||||
}
|
||||
|
||||
public Region createBackground() {
|
||||
return createBackground("background");
|
||||
}
|
||||
|
||||
public Text createText(String css, String x) {
|
||||
final Text text = new Text(x);
|
||||
text.getStyleClass().add(css);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public Text createText(String x) {
|
||||
return createText("text", x);
|
||||
}
|
||||
|
||||
public Button createButton(String css, String x, Runnable runnable) {
|
||||
final Button button = new Button(x);
|
||||
button.setOnAction(_ -> runnable.run());
|
||||
button.getStyleClass().add(css);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
public Button createButton(String x, Runnable runnable) {
|
||||
return createButton("button", x, runnable);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package org.toop.app.menu;
|
||||
|
||||
import org.toop.framework.asset.ResourceManager;
|
||||
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public final class OptionsMenu extends Menu {
|
||||
private Locale currentLocale = AppContext.getLocale();
|
||||
private LocalizationAsset loc = ResourceManager.get("localization.properties");
|
||||
public OptionsMenu() {
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package org.toop.app.menu.game;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Text;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.menu.MainMenu;
|
||||
import org.toop.app.menu.Menu;
|
||||
|
||||
public abstract class GameMenu extends Menu {
|
||||
protected final class Cell {
|
||||
public float x;
|
||||
public float y;
|
||||
|
||||
public float width;
|
||||
public float height;
|
||||
|
||||
public Cell(float x, float y, float width, float height) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public boolean check(float x, float y) {
|
||||
return x >= this.x && y >= this.y && x <= this.x + width && y <= this.y + height;
|
||||
}
|
||||
}
|
||||
|
||||
protected final int size;
|
||||
|
||||
protected final Canvas canvas;
|
||||
protected final GraphicsContext graphics;
|
||||
|
||||
protected final int rows;
|
||||
protected final int columns;
|
||||
|
||||
protected final int gapSize;
|
||||
|
||||
protected final Cell[] cells;
|
||||
|
||||
protected GameMenu(int rows, int columns, int gapSize) {
|
||||
final int size = Math.min(App.getWidth(), App.getHeight()) / 5 * 4;
|
||||
|
||||
final Canvas canvas = new Canvas(size, size);
|
||||
|
||||
final GraphicsContext graphics = canvas.getGraphicsContext2D();
|
||||
|
||||
this.size = size;
|
||||
|
||||
this.canvas = canvas;
|
||||
this.graphics = graphics;
|
||||
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
|
||||
this.gapSize = gapSize;
|
||||
|
||||
cells = new Cell[rows * columns];
|
||||
|
||||
final float cellWidth = ((float)size - (rows - 1) * gapSize) / rows;
|
||||
final float cellHeight = ((float)size - (columns - 1) * gapSize) / rows;
|
||||
|
||||
for (int y = 0; y < columns; y++) {
|
||||
final float startY = y * cellHeight + y * gapSize;
|
||||
|
||||
for (int x = 0; x < rows; x++) {
|
||||
final float startX = x * cellWidth + x * gapSize;
|
||||
cells[y * rows + x] = new Cell(startX, startY, cellWidth, cellHeight);
|
||||
}
|
||||
}
|
||||
|
||||
final Region background = createBackground();
|
||||
|
||||
final Text player1 = createText("player_1", "Player 1");
|
||||
final Text player2 = createText("player_2", "Player 2");
|
||||
|
||||
final HBox playersContainer = new HBox(100, player1, player2);
|
||||
playersContainer.setAlignment(Pos.TOP_CENTER);
|
||||
playersContainer.setPickOnBounds(false);
|
||||
playersContainer.setTranslateY(50);
|
||||
|
||||
final Button hint = createButton("Hint", () -> {});
|
||||
final Button back = createButton("Back", () -> { App.activate(new MainMenu()); });
|
||||
|
||||
final VBox controlContainer = new VBox(hint, back);
|
||||
StackPane.setAlignment(controlContainer, Pos.BOTTOM_LEFT);
|
||||
controlContainer.setPickOnBounds(false);
|
||||
|
||||
pane = new StackPane(background, canvas, playersContainer, controlContainer);
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package org.toop.app.menu.game;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import org.toop.game.Game;
|
||||
import org.toop.game.Player;
|
||||
import org.toop.game.tictactoe.TicTacToe;
|
||||
import org.toop.game.tictactoe.TicTacToeAI;
|
||||
|
||||
import javax.management.RuntimeErrorException;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public final class TicTacToeMenu extends GameMenu {
|
||||
private final TicTacToe game;
|
||||
private final TicTacToeAI ai;
|
||||
|
||||
// private final ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||
private final BlockingQueue<Game.Move> moveQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
public TicTacToeMenu(TicTacToe game) {
|
||||
super(3, 3, 10);
|
||||
|
||||
graphics.setFill(Color.CYAN);
|
||||
|
||||
for (int x = 1; x < rows; x++) {
|
||||
graphics.fillRect(cells[x].x - gapSize, 0, gapSize, size);
|
||||
}
|
||||
|
||||
for (int y = 1; y < columns; y++) {
|
||||
graphics.fillRect(0, cells[y * rows].y - gapSize, size, gapSize);
|
||||
}
|
||||
|
||||
this.game = game;
|
||||
ai = new TicTacToeAI();
|
||||
|
||||
canvas.setOnMouseClicked(event -> {
|
||||
for (int i = 0; i < cells.length; i++) {
|
||||
if (cells[i].check((float) event.getX(), (float) event.getY())) {
|
||||
final Game.Move move = new Game.Move(i, game.getCurrentPlayer().values()[0]);
|
||||
play(move);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new Thread(this::gameThread).start();
|
||||
}
|
||||
|
||||
private void play(Game.Move move) {
|
||||
final Game.Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
boolean isLegal = false;
|
||||
|
||||
for (final Game.Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == move.position() && legalMove.value() == move.value()) {
|
||||
isLegal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isLegal) {
|
||||
return;
|
||||
}
|
||||
|
||||
try { moveQueue.put(move); }
|
||||
catch (InterruptedException _) {}
|
||||
}
|
||||
|
||||
private void placeX(int cell) {
|
||||
graphics.setStroke(Color.ORANGERED);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x + gapSize;
|
||||
final float y = cells[cell].y + gapSize;
|
||||
|
||||
final float width = cells[cell].width - gapSize * 2;
|
||||
final float height = cells[cell].height - gapSize * 2;
|
||||
|
||||
graphics.strokeLine(x, y, x + width, y + height);
|
||||
graphics.strokeLine(x + width, y, x, y + height);
|
||||
}
|
||||
|
||||
private void placeO(int cell) {
|
||||
graphics.setStroke(Color.DEEPSKYBLUE);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x + gapSize;
|
||||
final float y = cells[cell].y + gapSize;
|
||||
|
||||
final float width = cells[cell].width - gapSize * 2;
|
||||
final float height = cells[cell].height - gapSize * 2;
|
||||
|
||||
graphics.strokeOval(x, y, width, height);
|
||||
}
|
||||
|
||||
private void gameThread() {
|
||||
boolean running = true;
|
||||
|
||||
while(running) {
|
||||
final Player currentPlayer = game.getCurrentPlayer();
|
||||
|
||||
try {
|
||||
Game.Move move;
|
||||
|
||||
if (!currentPlayer.isAI()) {
|
||||
try { move = moveQueue.take(); }
|
||||
catch (InterruptedException _) { return; }
|
||||
} else {
|
||||
move = ai.findBestMove(game, 9);
|
||||
}
|
||||
|
||||
assert move != null;
|
||||
final Game.State state = game.play(move);
|
||||
|
||||
if (move.value() == 'X') {
|
||||
placeX(move.position());
|
||||
} else {
|
||||
placeO(move.position());
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case NORMAL: break;
|
||||
|
||||
case DRAW:
|
||||
case LOSE:
|
||||
case WIN:
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
179
app/src/main/java/org/toop/app/widget/Primitive.java
Normal file
@@ -0,0 +1,179 @@
|
||||
package org.toop.app.widget;
|
||||
|
||||
import javafx.scene.image.ImageView;
|
||||
import org.toop.framework.resource.resources.ImageAsset;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.Separator;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
public final class Primitive {
|
||||
public static Text header(String key) {
|
||||
var header = new Text();
|
||||
header.getStyleClass().add("header");
|
||||
|
||||
if (!key.isEmpty()) {
|
||||
header.setText(AppContext.getString(key));
|
||||
header.textProperty().bind(AppContext.bindToKey(key));
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
public static Text text(String key) {
|
||||
var text = new Text();
|
||||
text.getStyleClass().add("text");
|
||||
|
||||
if (!key.isEmpty()) {
|
||||
text.setText(AppContext.getString(key));
|
||||
text.textProperty().bind(AppContext.bindToKey(key));
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public static ImageView image(ImageAsset imageAsset) {
|
||||
ImageView imageView = new ImageView(imageAsset.getImage());
|
||||
imageView.getStyleClass().add("image");
|
||||
imageView.setPreserveRatio(true);
|
||||
imageView.setFitWidth(400);
|
||||
imageView.setFitHeight(400);
|
||||
return imageView;
|
||||
}
|
||||
|
||||
public static Button button(String key, Runnable onAction) {
|
||||
var button = new Button();
|
||||
button.getStyleClass().add("button");
|
||||
|
||||
if (!key.isEmpty()) {
|
||||
button.setText(AppContext.getString(key));
|
||||
button.textProperty().bind(AppContext.bindToKey(key));
|
||||
}
|
||||
|
||||
if (onAction != null) {
|
||||
button.setOnAction(_ ->
|
||||
onAction.run());
|
||||
}
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
public static TextField input(String promptKey, String text, Consumer<String> onValueChanged) {
|
||||
var input = new TextField();
|
||||
input.getStyleClass().add("input");
|
||||
|
||||
if (!promptKey.isEmpty()) {
|
||||
input.setPromptText(AppContext.getString(promptKey));
|
||||
input.promptTextProperty().bind(AppContext.bindToKey(promptKey));
|
||||
}
|
||||
|
||||
input.setText(text);
|
||||
|
||||
if (onValueChanged != null) {
|
||||
input.textProperty().addListener((_, _, newValue) ->
|
||||
onValueChanged.accept(newValue));
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public static Slider slider(int min, int max, int value, Consumer<Integer> onValueChanged) {
|
||||
var slider = new Slider();
|
||||
slider.getStyleClass().add("slider");
|
||||
|
||||
slider.setMin(min);
|
||||
slider.setMax(max);
|
||||
slider.setValue(value);
|
||||
|
||||
if (onValueChanged != null) {
|
||||
slider.valueProperty().addListener((_, _, newValue) ->
|
||||
onValueChanged.accept(newValue.intValue()));
|
||||
}
|
||||
|
||||
return slider;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> ComboBox<T> choice(StringConverter<T> converter, T value, Consumer<T> onValueChanged, T... items) {
|
||||
var choice = new ComboBox<T>();
|
||||
choice.getStyleClass().add("choice");
|
||||
|
||||
if (converter != null) {
|
||||
choice.setConverter(converter);
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
choice.setValue(value);
|
||||
}
|
||||
|
||||
if (onValueChanged != null) {
|
||||
choice.valueProperty().addListener((_, _, newValue) ->
|
||||
onValueChanged.accept(newValue));
|
||||
}
|
||||
|
||||
choice.setItems(FXCollections.observableArrayList(items));
|
||||
|
||||
return choice;
|
||||
}
|
||||
|
||||
public static ScrollPane scroll(Node content) {
|
||||
var scroll = new ScrollPane();
|
||||
scroll.getStyleClass().add("scroll");
|
||||
scroll.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
|
||||
scroll.setFitToWidth(true);
|
||||
|
||||
scroll.setContent(content);
|
||||
|
||||
return scroll;
|
||||
}
|
||||
|
||||
public static Separator separator() {
|
||||
var separator = new Separator();
|
||||
separator.getStyleClass().add("separator");
|
||||
|
||||
return separator;
|
||||
}
|
||||
|
||||
public static HBox hbox(Node... nodes) {
|
||||
var hbox = new HBox();
|
||||
hbox.getStyleClass().add("container");
|
||||
hbox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
|
||||
|
||||
for (var node : nodes) {
|
||||
if (node != null) {
|
||||
hbox.getChildren().add(node);
|
||||
}
|
||||
}
|
||||
|
||||
return hbox;
|
||||
}
|
||||
|
||||
public static VBox vbox(Node... nodes) {
|
||||
var vbox = new VBox();
|
||||
vbox.getStyleClass().add("container");
|
||||
vbox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
|
||||
|
||||
for (var node : nodes) {
|
||||
if (node != null) {
|
||||
vbox.getChildren().add(node);
|
||||
}
|
||||
}
|
||||
|
||||
return vbox;
|
||||
}
|
||||
}
|
||||
5
app/src/main/java/org/toop/app/widget/Updatable.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package org.toop.app.widget;
|
||||
|
||||
public interface Updatable {
|
||||
void update();
|
||||
}
|
||||
21
app/src/main/java/org/toop/app/widget/Widget.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package org.toop.app.widget;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
|
||||
public interface Widget {
|
||||
Node getNode();
|
||||
|
||||
default void show(Pos position) {
|
||||
WidgetContainer.add(position, this);
|
||||
}
|
||||
|
||||
default void hide() {
|
||||
WidgetContainer.remove(this);
|
||||
}
|
||||
|
||||
default void replace(Pos position, Widget widget) {
|
||||
widget.show(position);
|
||||
hide();
|
||||
}
|
||||
}
|
||||
77
app/src/main/java/org/toop/app/widget/WidgetContainer.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package org.toop.app.widget;
|
||||
|
||||
import org.toop.app.widget.complex.PopupWidget;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
public final class WidgetContainer {
|
||||
private static StackPane root;
|
||||
private static ViewWidget currentView;
|
||||
|
||||
public static synchronized StackPane setup() {
|
||||
if (root != null) {
|
||||
return root;
|
||||
}
|
||||
|
||||
root = new StackPane();
|
||||
root.getStyleClass().add("bg-view");
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public static void add(Pos position, Widget widget) {
|
||||
if (root == null || widget == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
if (root.getChildren().contains(widget.getNode())) {
|
||||
return;
|
||||
}
|
||||
|
||||
StackPane.setAlignment(widget.getNode(), position);
|
||||
|
||||
if (widget instanceof ViewWidget view) {
|
||||
root.getChildren().addFirst(view.getNode());
|
||||
currentView = view;
|
||||
} else if (widget instanceof PopupWidget popup) {
|
||||
currentView.add(Pos.CENTER, popup);
|
||||
} else {
|
||||
root.getChildren().add(widget.getNode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void remove(Widget widget) {
|
||||
if (root == null || widget == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
if (widget instanceof PopupWidget popup) {
|
||||
currentView.remove(popup);
|
||||
} else {
|
||||
root.getChildren().remove(widget.getNode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static ViewWidget getCurrentView() {
|
||||
return currentView;
|
||||
}
|
||||
|
||||
public static void setCurrentView(ViewWidget view) {
|
||||
if (root == null || view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
root.getChildren().clear();
|
||||
root.getChildren().add(view.getNode());
|
||||
currentView = view;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.toop.app.widget.complex;
|
||||
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.Widget;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Text;
|
||||
|
||||
public class ConfirmWidget implements Widget {
|
||||
private final HBox buttonsContainer;
|
||||
private final Text messageText;
|
||||
private final VBox container;
|
||||
|
||||
public ConfirmWidget(String confirm) {
|
||||
buttonsContainer = Primitive.hbox();
|
||||
messageText = Primitive.text("");
|
||||
container = Primitive.vbox(Primitive.header(confirm), messageText, Primitive.separator(), buttonsContainer);
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
messageText.setText(message);
|
||||
}
|
||||
|
||||
public void addButton(String key, Runnable onClick) {
|
||||
Platform.runLater(() -> {
|
||||
var button = Primitive.button(key, onClick);
|
||||
buttonsContainer.getChildren().add(button);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.toop.app.widget.complex;
|
||||
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.Widget;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
public class LabeledChoiceWidget<T> implements Widget {
|
||||
private final ComboBox<T> comboBox;
|
||||
private final VBox container;
|
||||
|
||||
@SafeVarargs
|
||||
public LabeledChoiceWidget(
|
||||
String key,
|
||||
StringConverter<T> converter,
|
||||
T initialValue,
|
||||
Consumer<T> onValueChanged,
|
||||
T... items
|
||||
) {
|
||||
var label = Primitive.text(key);
|
||||
comboBox = Primitive.choice(converter, initialValue, onValueChanged, items);
|
||||
container = Primitive.vbox(label, comboBox);
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return comboBox.getValue();
|
||||
}
|
||||
|
||||
public void setValue(T value) {
|
||||
comboBox.setValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.toop.app.widget.complex;
|
||||
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.Widget;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
public class LabeledInputWidget implements Widget {
|
||||
private final TextField input;
|
||||
private final VBox container;
|
||||
|
||||
public LabeledInputWidget(String key, String promptKey, String initialText, Consumer<String> onValueChanged) {
|
||||
var label = Primitive.text(key);
|
||||
input = Primitive.input(promptKey, initialText, onValueChanged);
|
||||
container = Primitive.vbox(label, input);
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return input.getText();
|
||||
}
|
||||
|
||||
public void setValue(String text) {
|
||||
input.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.toop.app.widget.complex;
|
||||
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.Widget;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Text;
|
||||
|
||||
public class LabeledSliderWidget implements Widget {
|
||||
private final Slider slider;
|
||||
private final Text labelValue;
|
||||
private final VBox container;
|
||||
|
||||
public LabeledSliderWidget(String key, int min, int max, int value, Consumer<Integer> onValueChanged) {
|
||||
var label = Primitive.text(key);
|
||||
|
||||
labelValue = new Text(String.valueOf(value));
|
||||
labelValue.getStyleClass().add("text");
|
||||
|
||||
slider = Primitive.slider(min, max, value, newValue -> {
|
||||
labelValue.setText(String.valueOf(newValue));
|
||||
|
||||
if (onValueChanged != null) {
|
||||
onValueChanged.accept(newValue);
|
||||
}
|
||||
});
|
||||
|
||||
var sliderRow = Primitive.hbox(slider, labelValue);
|
||||
container = Primitive.vbox(label, sliderRow);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return (int)slider.getValue();
|
||||
}
|
||||
|
||||
public void setValue(int newValue) {
|
||||
slider.setValue(newValue);
|
||||
labelValue.setText(String.valueOf(newValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.toop.app.widget.complex;
|
||||
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.widget.Primitive;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
public class PlayerInfoWidget {
|
||||
private final GameInformation.Player information;
|
||||
private final VBox container;
|
||||
|
||||
public PlayerInfoWidget(GameInformation.Player information) {
|
||||
this.information = information;
|
||||
container = Primitive.vbox(
|
||||
buildToggle().getNode(),
|
||||
buildContent()
|
||||
);
|
||||
}
|
||||
|
||||
private ToggleWidget buildToggle() {
|
||||
return new ToggleWidget(
|
||||
"computer", "player",
|
||||
information.isHuman,
|
||||
isHuman -> {
|
||||
information.isHuman = isHuman;
|
||||
container.getChildren().setAll(
|
||||
buildToggle().getNode(),
|
||||
buildContent()
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private Node buildContent() {
|
||||
if (information.isHuman) {
|
||||
var nameInput = new LabeledInputWidget(
|
||||
"name",
|
||||
"enter-your-name",
|
||||
information.name,
|
||||
newName -> information.name = newName
|
||||
);
|
||||
|
||||
return nameInput.getNode();
|
||||
} else {
|
||||
if (information.name == null || information.name.isEmpty()) {
|
||||
information.name = "Pism Bot";
|
||||
}
|
||||
|
||||
var playerName = Primitive.text("");
|
||||
playerName.setText(information.name);
|
||||
|
||||
var nameDisplay = Primitive.vbox(
|
||||
Primitive.text("name"),
|
||||
playerName
|
||||
);
|
||||
|
||||
var difficultySlider = new LabeledSliderWidget(
|
||||
"computer-difficulty",
|
||||
0, 5,
|
||||
information.computerDifficulty,
|
||||
newVal -> information.computerDifficulty = newVal
|
||||
);
|
||||
|
||||
var thinkTimeSlider = new LabeledSliderWidget(
|
||||
"computer-think-time",
|
||||
0, 5,
|
||||
information.computerThinkTime,
|
||||
newVal -> information.computerThinkTime = newVal
|
||||
);
|
||||
|
||||
return Primitive.vbox(
|
||||
nameDisplay,
|
||||
difficultySlider.getNode(),
|
||||
thinkTimeSlider.getNode()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public Node getNode() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.toop.app.widget.complex;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
|
||||
public abstract class PopupWidget extends StackWidget {
|
||||
private final Button popButton;
|
||||
|
||||
public PopupWidget() {
|
||||
super("bg-popup");
|
||||
|
||||
popButton = new Button("X");
|
||||
popButton.setOnAction(_ -> hide());
|
||||
|
||||
add(Pos.TOP_RIGHT, popButton);
|
||||
}
|
||||
|
||||
protected void setOnPop(Runnable onPop) {
|
||||
popButton.setOnAction(_ -> onPop.run());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.toop.app.widget.complex;
|
||||
|
||||
import org.toop.app.widget.Widget;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
public abstract class StackWidget implements Widget {
|
||||
private final StackPane container;
|
||||
|
||||
public StackWidget(String cssClass) {
|
||||
container = new StackPane();
|
||||
container.getStyleClass().add(cssClass);
|
||||
}
|
||||
|
||||
public void add(Pos position, Node node) {
|
||||
Platform.runLater(() -> {
|
||||
if (container.getChildren().contains(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
StackPane.setAlignment(node, position);
|
||||
container.getChildren().add(node);
|
||||
});
|
||||
}
|
||||
|
||||
public void add(Pos position, Widget widget) {
|
||||
add(position, widget.getNode());
|
||||
}
|
||||
|
||||
public void remove(Node node) {
|
||||
Platform.runLater(() -> {
|
||||
container.getChildren().remove(node);
|
||||
});
|
||||
}
|
||||
|
||||
public void remove(Widget widget) {
|
||||
remove(widget.getNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package org.toop.app.widget.complex;
|
||||
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.Widget;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
public class ToggleWidget implements Widget {
|
||||
private final Button button;
|
||||
private final VBox container;
|
||||
|
||||
private final String onKey;
|
||||
private final String offKey;
|
||||
|
||||
private boolean state;
|
||||
|
||||
public ToggleWidget(String onKey, String offKey, boolean initialState, Consumer<Boolean> onToggle) {
|
||||
this.onKey = onKey;
|
||||
this.offKey = offKey;
|
||||
this.state = initialState;
|
||||
|
||||
button = new Button(AppContext.getString(getCurrentKey()));
|
||||
button.setOnAction(_ -> {
|
||||
state = !state;
|
||||
updateText();
|
||||
if (onToggle != null) {
|
||||
onToggle.accept(state);
|
||||
}
|
||||
});
|
||||
|
||||
container = Primitive.vbox(button);
|
||||
}
|
||||
|
||||
private String getCurrentKey() {
|
||||
return state? offKey : onKey;
|
||||
}
|
||||
|
||||
private void updateText() {
|
||||
button.setText(AppContext.getString(getCurrentKey()));
|
||||
}
|
||||
|
||||
public boolean getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(boolean newState) {
|
||||
if (state != newState) {
|
||||
state = newState;
|
||||
updateText();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.toop.app.widget.complex;
|
||||
|
||||
import org.toop.app.widget.Primitive;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
public abstract class ViewWidget extends StackWidget {
|
||||
private ViewWidget previous = null;
|
||||
|
||||
public ViewWidget() {
|
||||
super("bg-primary");
|
||||
}
|
||||
|
||||
public void transition(ViewWidget view) {
|
||||
view.previous = this;
|
||||
replace(Pos.CENTER, view);
|
||||
}
|
||||
|
||||
public void transitionNext(ViewWidget view) {
|
||||
view.previous = this;
|
||||
replace(Pos.CENTER, view);
|
||||
|
||||
var backButton = Primitive.button("back", () -> {
|
||||
view.transitionPrevious();
|
||||
});
|
||||
|
||||
view.add(Pos.BOTTOM_LEFT, Primitive.vbox(backButton));
|
||||
}
|
||||
|
||||
public void transitionPrevious() {
|
||||
if (previous == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
replace(Pos.CENTER, previous);
|
||||
previous = null;
|
||||
}
|
||||
|
||||
public void reload(ViewWidget view) {
|
||||
view.previous = previous;
|
||||
replace(Pos.CENTER, view);
|
||||
|
||||
var backButton = Primitive.button("back", () -> {
|
||||
view.transitionPrevious();
|
||||
});
|
||||
|
||||
view.add(Pos.BOTTOM_LEFT, Primitive.vbox(backButton));
|
||||
}
|
||||
}
|
||||
139
app/src/main/java/org/toop/app/widget/display/SongDisplay.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package org.toop.app.widget.display;
|
||||
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.util.Duration;
|
||||
import org.toop.app.widget.Widget;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.eventbus.GlobalEventBus;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Text;
|
||||
|
||||
import java.util.Timer;
|
||||
|
||||
public class SongDisplay extends VBox implements Widget {
|
||||
private final Text songTitle;
|
||||
private final ProgressBar progressBar;
|
||||
private final Text progressText;
|
||||
private boolean canClick = true;
|
||||
|
||||
public SongDisplay() {
|
||||
new EventFlow()
|
||||
.listen(this::updateTheSong);
|
||||
|
||||
setAlignment(Pos.CENTER);
|
||||
setMaxHeight(Region.USE_PREF_SIZE);
|
||||
getStyleClass().add("song-display");
|
||||
|
||||
// TODO ADD GOOD SONG TITLES WITH ARTISTS DISPLAYED
|
||||
songTitle = new Text("song playing");
|
||||
songTitle.getStyleClass().add("song-title");
|
||||
|
||||
progressBar = new ProgressBar(0);
|
||||
progressBar.getStyleClass().add("progress-bar");
|
||||
|
||||
progressText = new Text("0:00/0:00");
|
||||
progressText.getStyleClass().add("progress-text");
|
||||
|
||||
// TODO ADD BETTER CSS FOR THE SKIPBUTTON WHERE ITS AT A NICER POSITION
|
||||
|
||||
Button skipButton = new Button(">>");
|
||||
Button pauseButton = new Button("⏸");
|
||||
Button previousButton = new Button("<<");
|
||||
|
||||
skipButton.getStyleClass().setAll("skip-button");
|
||||
pauseButton.getStyleClass().setAll("pause-button");
|
||||
previousButton.getStyleClass().setAll("previous-button");
|
||||
|
||||
skipButton.setOnAction( event -> {
|
||||
if (!canClick) { return; }
|
||||
GlobalEventBus.post(new AudioEvents.SkipMusic());
|
||||
doCooldown();
|
||||
});
|
||||
|
||||
pauseButton.setOnAction(event -> {
|
||||
if (!canClick) { return; }
|
||||
GlobalEventBus.post(new AudioEvents.PauseMusic());
|
||||
if (pauseButton.getText().equals("⏸")) {
|
||||
pauseButton.setText("▶");
|
||||
}
|
||||
else if (pauseButton.getText().equals("▶")) {
|
||||
pauseButton.setText("⏸");
|
||||
}
|
||||
doCooldown();
|
||||
});
|
||||
|
||||
previousButton.setOnAction( event -> {
|
||||
if (!canClick) { return; }
|
||||
GlobalEventBus.post(new AudioEvents.PreviousMusic());
|
||||
doCooldown();
|
||||
});
|
||||
|
||||
HBox control = new HBox(10, previousButton, pauseButton, skipButton);
|
||||
control.setAlignment(Pos.CENTER);
|
||||
control.getStyleClass().add("controls");
|
||||
|
||||
getChildren().addAll(songTitle, progressBar, progressText, control);
|
||||
}
|
||||
|
||||
private void updateTheSong(AudioEvents.PlayingMusic event) {
|
||||
Platform.runLater(() -> {
|
||||
String text = event.name();
|
||||
text = text.substring(0, text.length() - 4);
|
||||
songTitle.setText(text);
|
||||
double currentPos = event.currentPosition();
|
||||
double duration = event.duration();
|
||||
if (currentPos / duration > 0.05) {
|
||||
double progress = currentPos / duration;
|
||||
progressBar.setProgress(progress);
|
||||
}
|
||||
else if (currentPos / duration < 0.05) {
|
||||
progressBar.setProgress(0.05);
|
||||
}
|
||||
progressText.setText(getTimeString(event.currentPosition(), event.duration()));
|
||||
});
|
||||
}
|
||||
|
||||
private String getTimeString(long position, long duration) {
|
||||
long positionMinutes = position / 60;
|
||||
long durationMinutes = duration / 60;
|
||||
long positionSeconds = position % 60;
|
||||
long durationSeconds = duration % 60;
|
||||
String positionSecondsStr = String.valueOf(positionSeconds);
|
||||
String durationSecondsStr = String.valueOf(durationSeconds);
|
||||
|
||||
if (positionSeconds < 10) {
|
||||
positionSecondsStr = "0" + positionSeconds;
|
||||
}
|
||||
if (durationSeconds < 10) {
|
||||
durationSecondsStr = "0" + durationSeconds;
|
||||
}
|
||||
|
||||
String time = positionMinutes + ":" + positionSecondsStr + " / " + durationMinutes + ":" + durationSecondsStr;
|
||||
return time;
|
||||
}
|
||||
|
||||
private void doCooldown() {
|
||||
canClick = false;
|
||||
Timeline cooldown = new Timeline(
|
||||
new KeyFrame(Duration.millis(300), event -> canClick = true)
|
||||
);
|
||||
cooldown.setCycleCount(1);
|
||||
cooldown.play();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Node getNode() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.toop.app.widget.popup;
|
||||
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.PlayerInfoWidget;
|
||||
import org.toop.app.widget.complex.PopupWidget;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
public final class ChallengePopup extends PopupWidget {
|
||||
private final GameInformation.Player playerInformation;
|
||||
private final String challenger;
|
||||
private final String game;
|
||||
private final Consumer<GameInformation.Player> onAccept;
|
||||
|
||||
public ChallengePopup(String challenger, String game, Consumer<GameInformation.Player> onAccept) {
|
||||
this.challenger = challenger;
|
||||
this.game = game;
|
||||
this.onAccept = onAccept;
|
||||
|
||||
this.playerInformation = new GameInformation.Player();
|
||||
|
||||
setupLayout();
|
||||
}
|
||||
|
||||
private void setupLayout() {
|
||||
var challengeText = Primitive.text("you-were-challenged-by");
|
||||
|
||||
var challengerHeader = Primitive.header("");
|
||||
challengerHeader.setText(challenger);
|
||||
|
||||
var gameText = Primitive.text("to-a-game-of");
|
||||
gameText.setText(gameText.getText() + " " + game);
|
||||
|
||||
var acceptButton = Primitive.button("accept", () -> onAccept.accept(playerInformation));
|
||||
var denyButton = Primitive.button("deny", () -> hide());
|
||||
|
||||
var leftSection = Primitive.vbox(
|
||||
challengeText,
|
||||
challengerHeader,
|
||||
gameText,
|
||||
Primitive.separator(),
|
||||
Primitive.hbox(
|
||||
acceptButton,
|
||||
denyButton
|
||||
)
|
||||
);
|
||||
|
||||
var playerInfoWidget = new PlayerInfoWidget(playerInformation);
|
||||
|
||||
add(Pos.CENTER,
|
||||
Primitive.hbox(
|
||||
leftSection,
|
||||
playerInfoWidget.getNode()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
16
app/src/main/java/org/toop/app/widget/popup/ErrorPopup.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package org.toop.app.widget.popup;
|
||||
|
||||
import org.toop.app.widget.complex.ConfirmWidget;
|
||||
import org.toop.app.widget.complex.PopupWidget;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
public class ErrorPopup extends PopupWidget {
|
||||
public ErrorPopup(String error) {
|
||||
var confirmWidget = new ConfirmWidget("error");
|
||||
confirmWidget.setMessage(error);
|
||||
confirmWidget.addButton("ok", this::hide);
|
||||
|
||||
add(Pos.CENTER, confirmWidget);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.toop.app.widget.popup;
|
||||
|
||||
import org.toop.app.widget.complex.ConfirmWidget;
|
||||
import org.toop.app.widget.complex.PopupWidget;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
public final class GameOverPopup extends PopupWidget {
|
||||
public GameOverPopup(boolean iWon, String winner) {
|
||||
var confirmWidget = new ConfirmWidget("game-over");
|
||||
|
||||
if (winner.isEmpty()) {
|
||||
confirmWidget.setMessage(AppContext.getString("the-game-ended-in-a-draw"));
|
||||
} else if (iWon) {
|
||||
confirmWidget.setMessage(AppContext.getString("you-win"));
|
||||
} else {
|
||||
confirmWidget.setMessage(AppContext.getString("you-lost-against") + ": " + winner);
|
||||
}
|
||||
|
||||
confirmWidget.addButton("ok", () -> hide());
|
||||
|
||||
add(Pos.CENTER, confirmWidget);
|
||||
}
|
||||
}
|
||||
29
app/src/main/java/org/toop/app/widget/popup/QuitPopup.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package org.toop.app.widget.popup;
|
||||
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.widget.complex.ConfirmWidget;
|
||||
import org.toop.app.widget.complex.PopupWidget;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
public class QuitPopup extends PopupWidget {
|
||||
public QuitPopup() {
|
||||
var confirmWidget = new ConfirmWidget("are-you-sure");
|
||||
|
||||
confirmWidget.addButton("yes", () -> {
|
||||
App.quit();
|
||||
});
|
||||
|
||||
confirmWidget.addButton("no", () -> {
|
||||
App.stopQuit();
|
||||
hide();
|
||||
});
|
||||
|
||||
add(Pos.CENTER, confirmWidget);
|
||||
|
||||
setOnPop(() -> {
|
||||
App.stopQuit();
|
||||
hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.toop.app.widget.popup;
|
||||
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.Server;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.LabeledChoiceWidget;
|
||||
import org.toop.app.widget.complex.PlayerInfoWidget;
|
||||
import org.toop.app.widget.complex.PopupWidget;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
public final class SendChallengePopup extends PopupWidget {
|
||||
private final Server server;
|
||||
private final String opponent;
|
||||
private final BiConsumer<GameInformation.Player, String> onSend;
|
||||
|
||||
private final GameInformation.Player playerInformation;
|
||||
|
||||
public SendChallengePopup(Server server, String opponent, BiConsumer<GameInformation.Player, String> onSend) {
|
||||
this.server = server;
|
||||
this.opponent = opponent;
|
||||
this.onSend = onSend;
|
||||
|
||||
this.playerInformation = new GameInformation.Player();
|
||||
|
||||
setupLayout();
|
||||
}
|
||||
|
||||
private void setupLayout() {
|
||||
// --- Left side: challenge text and buttons ---
|
||||
var challengeText = Primitive.text("challenge");
|
||||
|
||||
var opponentHeader = Primitive.header(opponent);
|
||||
|
||||
var gameText = Primitive.text("to-a-game-of");
|
||||
|
||||
var games = server.getGameList();
|
||||
var gameChoice = new LabeledChoiceWidget<>(
|
||||
"game",
|
||||
new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(String game) {
|
||||
return AppContext.getString(game);
|
||||
}
|
||||
@Override
|
||||
public String fromString(String s) { return null; }
|
||||
},
|
||||
games.getFirst(),
|
||||
newGame -> {
|
||||
playerInformation.computerDifficulty = Math.min(
|
||||
playerInformation.computerDifficulty,
|
||||
Server.gameToType(newGame).getMaxDepth()
|
||||
);
|
||||
},
|
||||
games.toArray(new String[0])
|
||||
);
|
||||
|
||||
var sendButton = Primitive.button(
|
||||
"send",
|
||||
() -> onSend.accept(playerInformation, gameChoice.getValue())
|
||||
);
|
||||
|
||||
var cancelButton = Primitive.button("cancel", () -> hide());
|
||||
|
||||
var leftSection = Primitive.vbox(
|
||||
challengeText,
|
||||
opponentHeader,
|
||||
gameText,
|
||||
gameChoice.getNode(),
|
||||
Primitive.separator(),
|
||||
Primitive.hbox(
|
||||
sendButton,
|
||||
cancelButton
|
||||
)
|
||||
);
|
||||
|
||||
var playerInfoWidget = new PlayerInfoWidget(playerInformation);
|
||||
|
||||
add(Pos.CENTER,
|
||||
Primitive.hbox(
|
||||
leftSection,
|
||||
playerInfoWidget.getNode()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package org.toop.app.widget.tutorial;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.text.Text;
|
||||
import org.apache.maven.surefire.shared.lang3.tuple.ImmutablePair;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.Updatable;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.app.widget.complex.PopupWidget;
|
||||
|
||||
import org.toop.framework.resource.resources.ImageAsset;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A widget base for all the tutorial widgets.
|
||||
*
|
||||
* <p>Usage example:
|
||||
*
|
||||
* <pre>{@code
|
||||
* public class Connect4TutorialWidget extends BaseTutorialWidget {
|
||||
* public Connect4TutorialWidget(Runnable nextScreen) {
|
||||
* super(List.of(
|
||||
* new ImmutablePair<>("connect4.1", ResourceManager.get("connect41.png")),
|
||||
* new ImmutablePair<>("connect4.2", ResourceManager.get("connect42.png"))
|
||||
* ), nextScreen);
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
public class BaseTutorialWidget extends PopupWidget implements Updatable {
|
||||
|
||||
private final Text tutorialText;
|
||||
private final ImageView imagery;
|
||||
private final Button previousButton;
|
||||
private final Button nextButton;
|
||||
private final List<ImmutablePair<String, ImageAsset>> pages;
|
||||
private final Runnable nextScreen;
|
||||
|
||||
private int pageIndex = 0;
|
||||
|
||||
public BaseTutorialWidget(List<ImmutablePair<String, ImageAsset>> pages, Runnable nextScreen) {
|
||||
this.tutorialText = Primitive.text(pages.getFirst().getKey());
|
||||
this.imagery = Primitive.image(pages.getFirst().getValue());
|
||||
|
||||
this.pages = pages;
|
||||
this.nextScreen = nextScreen;
|
||||
|
||||
previousButton = Primitive.button("goback", () -> { update(false); this.hide(); });
|
||||
nextButton = Primitive.button(">", () -> update(true));
|
||||
|
||||
var w = Primitive.hbox(
|
||||
previousButton,
|
||||
nextButton
|
||||
);
|
||||
|
||||
var x = Primitive.vbox(imagery, tutorialText);
|
||||
|
||||
add(Pos.CENTER, Primitive.vbox(x, w));
|
||||
|
||||
WidgetContainer.add(Pos.CENTER, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
update(true);
|
||||
}
|
||||
|
||||
// TODO Refactor if statements to make code easier to read.
|
||||
public void update(boolean next) {
|
||||
pageIndex = next ? pageIndex + 1 : pageIndex - 1;
|
||||
|
||||
if (pageIndex >= pages.size()) {
|
||||
pageIndex--;
|
||||
return;
|
||||
} else if (pageIndex < 0) {
|
||||
pageIndex++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pageIndex == pages.size()-1) {
|
||||
nextButton.textProperty().unbind();
|
||||
nextButton.setText(AppContext.getString("startgame"));
|
||||
nextButton.setOnAction((_) -> {
|
||||
this.hide();
|
||||
nextScreen.run();
|
||||
});
|
||||
|
||||
} else {
|
||||
nextButton.textProperty().unbind();
|
||||
nextButton.setText(AppContext.getString(">"));
|
||||
nextButton.setOnAction((_) -> this.update(true));
|
||||
}
|
||||
|
||||
if (pageIndex == 0) {
|
||||
previousButton.textProperty().unbind();
|
||||
previousButton.setText(AppContext.getString("goback"));
|
||||
previousButton.setOnAction((_) -> this.hide());
|
||||
} else {
|
||||
previousButton.textProperty().unbind();
|
||||
previousButton.setText(AppContext.getString("<"));
|
||||
previousButton.setOnAction((_) -> this.update(false));
|
||||
}
|
||||
|
||||
var currentPage = pages.get(pageIndex);
|
||||
|
||||
var text = currentPage.getKey();
|
||||
var image = currentPage.getValue();
|
||||
|
||||
tutorialText.textProperty().unbind();
|
||||
tutorialText.setText(AppContext.getString(text));
|
||||
imagery.setImage(Primitive.image(image).getImage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.toop.app.widget.tutorial;
|
||||
|
||||
import org.apache.maven.surefire.shared.lang3.tuple.ImmutablePair;
|
||||
import org.toop.framework.resource.ResourceManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Connect4TutorialWidget extends BaseTutorialWidget {
|
||||
public Connect4TutorialWidget(Runnable nextScreen) {
|
||||
super(List.of(
|
||||
new ImmutablePair<>("connect4.1", ResourceManager.get("connect41.png")),
|
||||
new ImmutablePair<>("connect4.2", ResourceManager.get("connect42.png"))
|
||||
), nextScreen);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.toop.app.widget.tutorial;
|
||||
|
||||
import org.apache.maven.surefire.shared.lang3.tuple.ImmutablePair;
|
||||
import org.toop.framework.resource.ResourceManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ReversiTutorialWidget extends BaseTutorialWidget {
|
||||
public ReversiTutorialWidget(Runnable nextScreen) {
|
||||
super(List.of(
|
||||
new ImmutablePair<>("reversi1", ResourceManager.get("reversi1.png")),
|
||||
new ImmutablePair<>("reversi2", ResourceManager.get("reversi2.png")),
|
||||
new ImmutablePair<>("reversi3", ResourceManager.get("cat.jpg")),
|
||||
new ImmutablePair<>("reversi4", ResourceManager.get("cat.jpg"))
|
||||
), nextScreen);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.toop.app.widget.tutorial;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.app.widget.complex.PopupWidget;
|
||||
import org.toop.local.AppSettings;
|
||||
|
||||
public class ShowEnableTutorialWidget extends PopupWidget {
|
||||
|
||||
public ShowEnableTutorialWidget(Runnable tutorial, Runnable nextScreen, Runnable appSettingsSetter) {
|
||||
var a = Primitive.hbox(
|
||||
Primitive.button("ok", () -> { appSettingsSetter.run(); tutorial.run(); this.hide(); }),
|
||||
Primitive.button("no", () -> { appSettingsSetter.run(); nextScreen.run(); this.hide(); }),
|
||||
Primitive.button("never", () -> { AppSettings.getSettings().setTutorialFlag(false); nextScreen.run(); this.hide(); })
|
||||
);
|
||||
|
||||
var txt = Primitive.text("tutorial");
|
||||
add(Pos.CENTER, Primitive.vbox(txt, a));
|
||||
WidgetContainer.add(Pos.CENTER, this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.toop.app.widget.tutorial;
|
||||
|
||||
import org.apache.maven.surefire.shared.lang3.tuple.ImmutablePair;
|
||||
import org.toop.framework.resource.ResourceManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TicTacToeTutorialWidget extends BaseTutorialWidget {
|
||||
public TicTacToeTutorialWidget(Runnable nextScreen) {
|
||||
super(List.of(
|
||||
new ImmutablePair<>("tictactoe1", ResourceManager.get("tictactoe1.png")),
|
||||
new ImmutablePair<>("tictactoe2", ResourceManager.get("tictactoe2.png"))
|
||||
), nextScreen);
|
||||
}
|
||||
|
||||
}
|
||||
81
app/src/main/java/org/toop/app/widget/view/CreditsView.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package org.toop.app.widget.view;
|
||||
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.util.Duration;
|
||||
|
||||
public class CreditsView extends ViewWidget {
|
||||
public CreditsView() {
|
||||
var scrumMasterCredit = newCredit("scrum-master", "Stef");
|
||||
var productOwnerCredit = newCredit("product-owner", "Omar");
|
||||
var mergeCommanderCredit = newCredit("merge-commander", "Bas");
|
||||
var localizationCredit = newCredit("localization", "Ticho");
|
||||
var aiCredit = newCredit("ai", "Michiel");
|
||||
var developersCredit = newCredit("developers", "Michiel, Bas, Stef, Omar, Ticho");
|
||||
var moralSupportCredit = newCredit("moral-support", "Wesley");
|
||||
var openglCredit = newCredit("opengl", "Omar");
|
||||
|
||||
var topSpacer = new Region();
|
||||
topSpacer.setPrefHeight(App.getHeight());
|
||||
|
||||
var bottomSpacer = new Region();
|
||||
bottomSpacer.setPrefHeight(App.getHeight());
|
||||
|
||||
var creditsContainer = Primitive.vbox(
|
||||
topSpacer,
|
||||
|
||||
scrumMasterCredit,
|
||||
productOwnerCredit,
|
||||
mergeCommanderCredit,
|
||||
localizationCredit,
|
||||
aiCredit,
|
||||
developersCredit,
|
||||
moralSupportCredit,
|
||||
openglCredit,
|
||||
|
||||
bottomSpacer
|
||||
);
|
||||
|
||||
var creditsScroll = Primitive.scroll(creditsContainer);
|
||||
|
||||
creditsScroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
creditsScroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
|
||||
add(Pos.CENTER, creditsScroll);
|
||||
|
||||
animate(creditsScroll, 15);
|
||||
}
|
||||
|
||||
private HBox newCredit(String key, String other) {
|
||||
var credit = new Text(": " + other);
|
||||
credit.getStyleClass().add("header");
|
||||
|
||||
var creditBox = Primitive.hbox(
|
||||
Primitive.header(key),
|
||||
credit
|
||||
);
|
||||
|
||||
creditBox.setPrefHeight(App.getHeight() / 3.0);
|
||||
return creditBox;
|
||||
}
|
||||
|
||||
private void animate(ScrollPane scroll, int length) {
|
||||
final Timeline timeline = new Timeline(
|
||||
new KeyFrame(Duration.seconds(0), new KeyValue(scroll.vvalueProperty(), 0.0)),
|
||||
new KeyFrame(Duration.seconds(length), new KeyValue(scroll.vvalueProperty(), 1.0))
|
||||
);
|
||||
|
||||
timeline.setCycleCount(Timeline.INDEFINITE);
|
||||
timeline.play();
|
||||
}
|
||||
}
|
||||
114
app/src/main/java/org/toop/app/widget/view/GameView.java
Normal file
@@ -0,0 +1,114 @@
|
||||
package org.toop.app.widget.view;
|
||||
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
import org.toop.app.widget.popup.GameOverPopup;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.text.Text;
|
||||
import org.toop.app.widget.tutorial.BaseTutorialWidget;
|
||||
import org.toop.app.widget.tutorial.Connect4TutorialWidget;
|
||||
import org.toop.app.widget.tutorial.ReversiTutorialWidget;
|
||||
import org.toop.app.widget.tutorial.TicTacToeTutorialWidget;
|
||||
|
||||
public final class GameView extends ViewWidget {
|
||||
private final Text currentPlayerHeader;
|
||||
private final Text currentMoveHeader;
|
||||
private final Text nextPlayerHeader;
|
||||
private final Button forfeitButton;
|
||||
private final Button exitButton;
|
||||
private final Button tutorialButton;
|
||||
private final TextField chatInput;
|
||||
|
||||
public GameView(Runnable onForfeit, Runnable onExit, Consumer<String> onMessage, String gameType) {
|
||||
currentPlayerHeader = Primitive.header("");
|
||||
currentMoveHeader = Primitive.header("");
|
||||
nextPlayerHeader = Primitive.header("");
|
||||
|
||||
if (onForfeit != null) {
|
||||
forfeitButton = Primitive.button("forfeit", () -> onForfeit.run());
|
||||
} else {
|
||||
forfeitButton = null;
|
||||
}
|
||||
|
||||
exitButton = Primitive.button("exit", () -> {
|
||||
onExit.run();
|
||||
transitionPrevious();
|
||||
});
|
||||
|
||||
if (onMessage != null) {
|
||||
chatInput = Primitive.input("enter-your-message", "", null);
|
||||
chatInput.setOnAction(_ -> {
|
||||
onMessage.accept(chatInput.getText());
|
||||
chatInput.clear();
|
||||
});
|
||||
} else {
|
||||
chatInput = null;
|
||||
}
|
||||
|
||||
switch(gameType) {
|
||||
case "TicTacToe":
|
||||
this.tutorialButton = Primitive.button("tutorialstring", () -> new TicTacToeTutorialWidget(() -> {})); break;
|
||||
case "Reversi":
|
||||
this.tutorialButton = Primitive.button("tutorialstring", () -> new ReversiTutorialWidget(() -> {})); break;
|
||||
case "Connect4":
|
||||
this.tutorialButton = Primitive.button("tutorialstring", () -> new Connect4TutorialWidget(() -> {})); break;
|
||||
default:
|
||||
this.tutorialButton = null; break;
|
||||
}
|
||||
|
||||
setupLayout();
|
||||
}
|
||||
|
||||
private void setupLayout() {
|
||||
var playerInfo = Primitive.vbox(
|
||||
currentPlayerHeader,
|
||||
Primitive.hbox(
|
||||
Primitive.separator(),
|
||||
currentMoveHeader,
|
||||
Primitive.separator()
|
||||
),
|
||||
nextPlayerHeader
|
||||
);
|
||||
|
||||
add(Pos.TOP_RIGHT, playerInfo);
|
||||
|
||||
var buttons = Primitive.vbox(
|
||||
forfeitButton,
|
||||
exitButton
|
||||
);
|
||||
|
||||
add(Pos.BOTTOM_LEFT, buttons);
|
||||
|
||||
if (chatInput != null) {
|
||||
add(Pos.BOTTOM_RIGHT, Primitive.vbox(chatInput));
|
||||
}
|
||||
|
||||
if (tutorialButton != null) {
|
||||
add(Pos.TOP_LEFT, tutorialButton);
|
||||
}
|
||||
}
|
||||
|
||||
public void nextPlayer(boolean isMe, String currentPlayer, String currentMove, String nextPlayer) {
|
||||
Platform.runLater(() -> {
|
||||
currentPlayerHeader.setText(currentPlayer);
|
||||
currentMoveHeader.setText(currentMove);
|
||||
nextPlayerHeader.setText(nextPlayer);
|
||||
|
||||
if (isMe) {
|
||||
currentPlayerHeader.getStyleClass().add("my-turn");
|
||||
} else {
|
||||
currentPlayerHeader.getStyleClass().remove("my-turn");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void gameOver(boolean iWon, String winner) {
|
||||
new GameOverPopup(iWon, winner).show(Pos.CENTER);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package org.toop.app.widget.view;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.game.Connect4Game;
|
||||
import org.toop.app.game.ReversiGame;
|
||||
import org.toop.app.game.TicTacToeGameThread;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.WidgetContainer;
|
||||
import org.toop.app.widget.complex.PlayerInfoWidget;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
import org.toop.app.widget.popup.ErrorPopup;
|
||||
import org.toop.app.widget.tutorial.*;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.toop.local.AppSettings;
|
||||
public class LocalMultiplayerView extends ViewWidget {
|
||||
private final GameInformation information;
|
||||
|
||||
public LocalMultiplayerView(GameInformation.Type type) {
|
||||
this(new GameInformation(type));
|
||||
}
|
||||
|
||||
public LocalMultiplayerView(GameInformation information) {
|
||||
this.information = information;
|
||||
var playButton = Primitive.button("play", () -> {
|
||||
for (var player : information.players) {
|
||||
if (player.isHuman && player.name.isEmpty()) {
|
||||
new ErrorPopup(AppContext.getString("please-enter-your-name")).show(Pos.CENTER);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (information.type) {
|
||||
case TICTACTOE:
|
||||
if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstTTT()) {
|
||||
new ShowEnableTutorialWidget(
|
||||
() -> new TicTacToeTutorialWidget(() -> new TicTacToeGameThread(information)),
|
||||
() -> Platform.runLater(() -> new TicTacToeGameThread(information)),
|
||||
() -> AppSettings.getSettings().setFirstTTT(false)
|
||||
);
|
||||
} else {
|
||||
new TicTacToeGameThread(information);
|
||||
}
|
||||
break;
|
||||
case REVERSI:
|
||||
if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstReversi()) {
|
||||
new ShowEnableTutorialWidget(
|
||||
() -> new ReversiTutorialWidget(() -> new ReversiGame(information)),
|
||||
() -> Platform.runLater(() -> new ReversiGame(information)),
|
||||
() -> AppSettings.getSettings().setFirstReversi(false)
|
||||
);
|
||||
} else {
|
||||
new ReversiGame(information);
|
||||
}
|
||||
break;
|
||||
case CONNECT4:
|
||||
if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstConnect4()) {
|
||||
new ShowEnableTutorialWidget(
|
||||
() -> new Connect4TutorialWidget(() -> new Connect4Game(information)),
|
||||
() -> Platform.runLater(() -> new Connect4Game(information)),
|
||||
() -> AppSettings.getSettings().setFirstConnect4(false)
|
||||
);
|
||||
} else {
|
||||
new Connect4Game(information);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// case BATTLESHIP -> new BattleshipGame(information);
|
||||
});
|
||||
|
||||
var playerSection = setupPlayerSections();
|
||||
|
||||
add(Pos.CENTER, Primitive.vbox(
|
||||
playerSection,
|
||||
Primitive.separator(),
|
||||
playButton
|
||||
));
|
||||
}
|
||||
|
||||
private ScrollPane setupPlayerSections() {
|
||||
int playerCount = information.type.getPlayerCount();
|
||||
VBox[] playerBoxes = new VBox[playerCount];
|
||||
|
||||
for (int i = 0; i < playerCount; i++) {
|
||||
var player = information.players[i];
|
||||
|
||||
var playerHeader = Primitive.header("");
|
||||
playerHeader.setText("player" + " #" + (i + 1));
|
||||
|
||||
var playerWidget = new PlayerInfoWidget(player);
|
||||
|
||||
playerBoxes[i] = Primitive.vbox(
|
||||
playerHeader,
|
||||
Primitive.separator(),
|
||||
playerWidget.getNode()
|
||||
);
|
||||
}
|
||||
|
||||
return Primitive.scroll(Primitive.hbox(
|
||||
playerBoxes
|
||||
));
|
||||
}
|
||||
}
|
||||
29
app/src/main/java/org/toop/app/widget/view/LocalView.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package org.toop.app.widget.view;
|
||||
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
public class LocalView extends ViewWidget {
|
||||
public LocalView() {
|
||||
var ticTacToeButton = Primitive.button("tic-tac-toe", () -> {
|
||||
transitionNext(new LocalMultiplayerView(GameInformation.Type.TICTACTOE));
|
||||
});
|
||||
|
||||
var reversiButton = Primitive.button("reversi", () -> {
|
||||
transitionNext(new LocalMultiplayerView(GameInformation.Type.REVERSI));
|
||||
});
|
||||
|
||||
var connect4Button = Primitive.button("connect4", () -> {
|
||||
transitionNext(new LocalMultiplayerView(GameInformation.Type.CONNECT4));
|
||||
});
|
||||
|
||||
add(Pos.CENTER, Primitive.vbox(
|
||||
ticTacToeButton,
|
||||
reversiButton,
|
||||
connect4Button
|
||||
));
|
||||
}
|
||||
}
|
||||
38
app/src/main/java/org/toop/app/widget/view/MainView.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package org.toop.app.widget.view;
|
||||
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
public class MainView extends ViewWidget {
|
||||
public MainView() {
|
||||
var localButton = Primitive.button("local", () -> {
|
||||
transitionNext(new LocalView());
|
||||
});
|
||||
|
||||
var onlineButton = Primitive.button("online", () -> {
|
||||
transitionNext(new OnlineView());
|
||||
});
|
||||
|
||||
var creditsButton = Primitive.button("credits", () -> {
|
||||
transitionNext(new CreditsView());
|
||||
});
|
||||
|
||||
var optionsButton = Primitive.button("options", () -> {
|
||||
transitionNext(new OptionsView());
|
||||
});
|
||||
|
||||
var quitButton = Primitive.button("quit", () -> {
|
||||
App.startQuit();
|
||||
});
|
||||
|
||||
add(Pos.CENTER, Primitive.vbox(
|
||||
localButton,
|
||||
onlineButton,
|
||||
creditsButton,
|
||||
optionsButton,
|
||||
quitButton
|
||||
));
|
||||
}
|
||||
}
|
||||
38
app/src/main/java/org/toop/app/widget/view/OnlineView.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package org.toop.app.widget.view;
|
||||
|
||||
import org.toop.app.Server;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.LabeledInputWidget;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
public class OnlineView extends ViewWidget {
|
||||
public OnlineView() {
|
||||
var serverInformationHeader = Primitive.header("server-information");
|
||||
|
||||
var serverIPInput = new LabeledInputWidget("ip-address", "enter-the-server-ip", "", _ -> {});
|
||||
var serverPortInput = new LabeledInputWidget("port", "enter-the-server-port", "", _ -> {});
|
||||
var playerNameInput = new LabeledInputWidget("player-name", "enter-your-name", "", _ -> {});
|
||||
|
||||
var connectButton = Primitive.button("connect", () -> {
|
||||
new Server(
|
||||
serverIPInput.getValue(),
|
||||
serverPortInput.getValue(),
|
||||
playerNameInput.getValue()
|
||||
);
|
||||
});
|
||||
|
||||
add(Pos.CENTER, Primitive.vbox(
|
||||
serverInformationHeader,
|
||||
Primitive.separator(),
|
||||
|
||||
serverIPInput.getNode(),
|
||||
serverPortInput.getNode(),
|
||||
playerNameInput.getNode(),
|
||||
Primitive.separator(),
|
||||
|
||||
connectButton
|
||||
));
|
||||
}
|
||||
}
|
||||
161
app/src/main/java/org/toop/app/widget/view/OptionsView.java
Normal file
@@ -0,0 +1,161 @@
|
||||
package org.toop.app.widget.view;
|
||||
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.LabeledChoiceWidget;
|
||||
import org.toop.app.widget.complex.LabeledSliderWidget;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
import org.toop.app.widget.complex.ToggleWidget;
|
||||
import org.toop.framework.audio.VolumeControl;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.local.AppContext;
|
||||
import org.toop.local.AppSettings;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
public class OptionsView extends ViewWidget {
|
||||
public OptionsView() {
|
||||
add(Pos.CENTER, Primitive.hbox(
|
||||
generalSection(),
|
||||
volumeSection(),
|
||||
styleSection()
|
||||
));
|
||||
}
|
||||
|
||||
private VBox generalSection() {
|
||||
var languageWidget = new LabeledChoiceWidget<>(
|
||||
"language",
|
||||
new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(Locale locale) {
|
||||
return AppContext.getString(locale.getDisplayName().toLowerCase());
|
||||
}
|
||||
@Override
|
||||
public Locale fromString(String s) { return null; }
|
||||
},
|
||||
AppContext.getLocale(),
|
||||
newLocale -> {
|
||||
AppSettings.getSettings().setLocale(newLocale.toString());
|
||||
AppContext.setLocale(newLocale);
|
||||
reload(new OptionsView());
|
||||
},
|
||||
AppContext.getLocalization().getAvailableLocales().toArray(new Locale[0])
|
||||
);
|
||||
|
||||
var fullscreenToggle = new ToggleWidget(
|
||||
"fullscreen", "windowed",
|
||||
AppSettings.getSettings().getFullscreen(),
|
||||
fullscreen -> {
|
||||
AppSettings.getSettings().setFullscreen(fullscreen);
|
||||
App.setFullscreen(fullscreen);
|
||||
}
|
||||
);
|
||||
|
||||
return Primitive.vbox(
|
||||
Primitive.header("general"),
|
||||
Primitive.separator(),
|
||||
|
||||
languageWidget.getNode(),
|
||||
fullscreenToggle.getNode()
|
||||
);
|
||||
}
|
||||
|
||||
private VBox volumeSection() {
|
||||
var masterVolumeWidget = new LabeledSliderWidget(
|
||||
"master-volume",
|
||||
0, 100,
|
||||
AppSettings.getSettings().getVolume(),
|
||||
val -> {
|
||||
AppSettings.getSettings().setVolume(val);
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeVolume(val, VolumeControl.MASTERVOLUME))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
);
|
||||
|
||||
var effectsVolumeWidget = new LabeledSliderWidget(
|
||||
"effects-volume",
|
||||
0, 100,
|
||||
AppSettings.getSettings().getFxVolume(),
|
||||
val -> {
|
||||
AppSettings.getSettings().setFxVolume(val);
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeVolume(val, VolumeControl.FX))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
);
|
||||
|
||||
var musicVolumeWidget = new LabeledSliderWidget(
|
||||
"music-volume",
|
||||
0, 100,
|
||||
AppSettings.getSettings().getMusicVolume(),
|
||||
val -> {
|
||||
AppSettings.getSettings().setMusicVolume(val);
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeVolume(val, VolumeControl.MUSIC))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
);
|
||||
|
||||
return Primitive.vbox(
|
||||
Primitive.header("volume"),
|
||||
Primitive.separator(),
|
||||
|
||||
masterVolumeWidget.getNode(),
|
||||
effectsVolumeWidget.getNode(),
|
||||
musicVolumeWidget.getNode()
|
||||
);
|
||||
}
|
||||
|
||||
private VBox styleSection() {
|
||||
var themeWidget = new LabeledChoiceWidget<>(
|
||||
"theme",
|
||||
new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(String theme) {
|
||||
return AppContext.getString(theme);
|
||||
}
|
||||
@Override
|
||||
public String fromString(String s) { return null; }
|
||||
},
|
||||
AppSettings.getSettings().getTheme(),
|
||||
newTheme -> {
|
||||
AppSettings.getSettings().setTheme(newTheme);
|
||||
App.setStyle(newTheme, AppSettings.getSettings().getLayoutSize());
|
||||
},
|
||||
"dark", "light", "high-contrast"
|
||||
);
|
||||
|
||||
var layoutWidget = new LabeledChoiceWidget<>(
|
||||
"layout-size",
|
||||
new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(String layout) {
|
||||
return AppContext.getString(layout);
|
||||
}
|
||||
@Override
|
||||
public String fromString(String s) { return null; }
|
||||
},
|
||||
AppSettings.getSettings().getLayoutSize(),
|
||||
newLayout -> {
|
||||
AppSettings.getSettings().setLayoutSize(newLayout);
|
||||
App.setStyle(AppSettings.getSettings().getTheme(), newLayout);
|
||||
},
|
||||
"small", "medium", "large"
|
||||
);
|
||||
|
||||
|
||||
return Primitive.vbox(
|
||||
Primitive.header("style"),
|
||||
Primitive.separator(),
|
||||
|
||||
themeWidget.getNode(),
|
||||
layoutWidget.getNode()
|
||||
);
|
||||
}
|
||||
}
|
||||
60
app/src/main/java/org/toop/app/widget/view/ServerView.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package org.toop.app.widget.view;
|
||||
|
||||
import org.toop.app.widget.Primitive;
|
||||
import org.toop.app.widget.complex.ViewWidget;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ListView;
|
||||
|
||||
public final class ServerView extends ViewWidget {
|
||||
private final String user;
|
||||
private final Consumer<String> onPlayerClicked;
|
||||
private final Runnable onDisconnect;
|
||||
|
||||
private final ListView<Button> listView;
|
||||
|
||||
public ServerView(String user, Consumer<String> onPlayerClicked, Runnable onDisconnect) {
|
||||
this.user = user;
|
||||
this.onPlayerClicked = onPlayerClicked;
|
||||
this.onDisconnect = onDisconnect;
|
||||
|
||||
this.listView = new ListView<>();
|
||||
|
||||
setupLayout();
|
||||
}
|
||||
|
||||
private void setupLayout() {
|
||||
var playerHeader = Primitive.header(user);
|
||||
|
||||
var playerListSection = Primitive.vbox(
|
||||
playerHeader,
|
||||
Primitive.separator(),
|
||||
listView
|
||||
);
|
||||
|
||||
add(Pos.CENTER, playerListSection);
|
||||
|
||||
var disconnectButton = Primitive.button("disconnect", () -> {
|
||||
onDisconnect.run();
|
||||
transitionPrevious();
|
||||
});
|
||||
|
||||
add(Pos.BOTTOM_LEFT, Primitive.vbox(disconnectButton));
|
||||
}
|
||||
|
||||
public void update(List<String> players) {
|
||||
Platform.runLater(() -> {
|
||||
listView.getItems().clear();
|
||||
|
||||
for (String player : players) {
|
||||
var playerButton = Primitive.button(player, () -> onPlayerClicked.accept(player));
|
||||
listView.getItems().add(playerButton);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,67 @@
|
||||
package org.toop.local;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.toop.framework.resource.ResourceManager;
|
||||
import org.toop.framework.resource.resources.LocalizationAsset;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
|
||||
public class AppContext {
|
||||
private static Locale currentLocale = Locale.getDefault();
|
||||
private static final LocalizationAsset localization = ResourceManager.get("localization");
|
||||
private static Locale locale = Locale.forLanguageTag("en");
|
||||
|
||||
public static void setCurrentLocale(Locale locale) {
|
||||
currentLocale = locale;
|
||||
private static final ObjectProperty<Locale> localeProperty = new SimpleObjectProperty<>(locale);
|
||||
private static final Logger logger = LogManager.getLogger(AppContext.class);
|
||||
|
||||
public static LocalizationAsset getLocalization() {
|
||||
return localization;
|
||||
}
|
||||
|
||||
public static void setLocale(Locale locale) {
|
||||
AppContext.locale = locale;
|
||||
localeProperty.set(locale);
|
||||
}
|
||||
|
||||
public static Locale getLocale() {
|
||||
return currentLocale;
|
||||
return locale;
|
||||
}
|
||||
|
||||
public static String getString(String key) {
|
||||
assert localization != null;
|
||||
|
||||
// TODO: Gebruik ResourceBundle.getBundle() zodat de fallback automatisch gaat.
|
||||
// Hiervoor zou de assetManager aangepast moeten worden.
|
||||
|
||||
try{ // Main return
|
||||
return localization.getString(key, locale);
|
||||
}
|
||||
catch (MissingResourceException e) {
|
||||
logger.error("Missing resource key: {}, in bundle: {}. ", key, locale, e);
|
||||
}
|
||||
|
||||
try{ // Fallback return
|
||||
return localization.getString(key, localization.getFallback());
|
||||
}
|
||||
catch (MissingResourceException e) {
|
||||
logger.error("Missing resource key: {}, in default bundle!", key, e);
|
||||
}
|
||||
// Default return
|
||||
return "MISSING RESOURCE";
|
||||
}
|
||||
|
||||
public static StringBinding bindToKey(String key) {
|
||||
return Bindings.createStringBinding(
|
||||
() -> localization.getString(key, locale),
|
||||
localeProperty
|
||||
);
|
||||
}
|
||||
}
|
||||
108
app/src/main/java/org/toop/local/AppSettings.java
Normal file
@@ -0,0 +1,108 @@
|
||||
package org.toop.local;
|
||||
|
||||
import org.toop.app.App;
|
||||
import org.toop.framework.audio.VolumeControl;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.resource.ResourceManager;
|
||||
import org.toop.framework.resource.ResourceMeta;
|
||||
import org.toop.framework.resource.resources.SettingsAsset;
|
||||
import org.toop.framework.settings.Settings;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
|
||||
public class AppSettings {
|
||||
private static SettingsAsset settingsAsset;
|
||||
|
||||
public static void applySettings() {
|
||||
settingsAsset = getPath();
|
||||
if (!settingsAsset.isLoaded()) {
|
||||
settingsAsset.load();
|
||||
}
|
||||
|
||||
checkSettings();
|
||||
|
||||
Settings settingsData = settingsAsset.getContent();
|
||||
|
||||
AppContext.setLocale(Locale.of(settingsData.locale));
|
||||
App.setFullscreen(settingsData.fullScreen);
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.volume, VolumeControl.MASTERVOLUME))
|
||||
.asyncPostEvent();
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.fxVolume, VolumeControl.FX))
|
||||
.asyncPostEvent();
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.musicVolume, VolumeControl.MUSIC))
|
||||
.asyncPostEvent();
|
||||
App.setStyle(settingsAsset.getTheme(), settingsAsset.getLayoutSize());
|
||||
}
|
||||
|
||||
public static SettingsAsset getPath() {
|
||||
if (settingsAsset == null) {
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
String basePath;
|
||||
|
||||
if (os.contains("win")) {
|
||||
basePath = System.getenv("APPDATA");
|
||||
if (basePath == null) {
|
||||
basePath = System.getProperty("user.home");
|
||||
}
|
||||
} else if (os.contains("mac")) {
|
||||
basePath = System.getProperty("user.home") + "/Library/Application Support";
|
||||
} else {
|
||||
basePath = System.getProperty("user.home") + "/.config";
|
||||
}
|
||||
|
||||
File settingsFile =
|
||||
new File(basePath + File.separator + "ISY1" + File.separator + "settings.json");
|
||||
// this.settingsAsset = new SettingsAsset(settingsFile);
|
||||
ResourceManager.addAsset(new ResourceMeta<>("settings.json", new SettingsAsset(settingsFile)));
|
||||
}
|
||||
return ResourceManager.get("settings.json");
|
||||
}
|
||||
|
||||
public static SettingsAsset getSettings() {
|
||||
return settingsAsset;
|
||||
}
|
||||
|
||||
public static void checkSettings() {
|
||||
Settings s = settingsAsset.getContent();
|
||||
boolean changed = false;
|
||||
|
||||
if (s.showTutorials == null) {
|
||||
settingsAsset.setTutorialFlag(true);
|
||||
changed = true;
|
||||
}
|
||||
if (s.firstReversi == null) {
|
||||
settingsAsset.setFirstReversi(true);
|
||||
changed = true;
|
||||
}
|
||||
if (s.firstTTT == null) {
|
||||
settingsAsset.setFirstTTT(true);
|
||||
changed = true;
|
||||
}
|
||||
if (s.firstConnect4 == null) {
|
||||
settingsAsset.setFirstConnect4(true);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
getSettings().save();
|
||||
}
|
||||
}
|
||||
|
||||
public static void doDefaultSettings() {
|
||||
settingsAsset.setFirstConnect4(true);
|
||||
settingsAsset.setFirstTTT(true);
|
||||
settingsAsset.setFirstReversi(true);
|
||||
settingsAsset.setLocale("en");
|
||||
settingsAsset.setTheme("dark");
|
||||
settingsAsset.setFullscreen(false);
|
||||
settingsAsset.setVolume(100);
|
||||
settingsAsset.setFxVolume(20);
|
||||
settingsAsset.setMusicVolume(15);
|
||||
settingsAsset.setTutorialFlag(true);
|
||||
settingsAsset.setLayoutSize("medium");
|
||||
}
|
||||
}
|
||||
BIN
app/src/main/resources/assets/audio/fx/harsh-button-click.wav
Normal file
BIN
app/src/main/resources/assets/audio/fx/medium-button-click.wav
Normal file
BIN
app/src/main/resources/assets/audio/fx/soft-button-click.wav
Normal file
BIN
app/src/main/resources/assets/audio/music/bignic - Gladius.mp3
Normal file
|
Before Width: | Height: | Size: 357 KiB |
BIN
app/src/main/resources/assets/images/cat.jpg
Normal file
|
After Width: | Height: | Size: 596 KiB |
BIN
app/src/main/resources/assets/images/connect41.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/src/main/resources/assets/images/connect42.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
app/src/main/resources/assets/images/reversi1.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/src/main/resources/assets/images/reversi2.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
app/src/main/resources/assets/images/tictactoe1.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
app/src/main/resources/assets/images/tictactoe2.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
@@ -1,17 +0,0 @@
|
||||
# Window title
|
||||
windowTitle=ISY Games Selector
|
||||
|
||||
# Main Menu buttons
|
||||
mainMenuSelectTicTacToe=Tic Tac Toe
|
||||
mainMenuSelectReversi=Reversi
|
||||
mainMenuSelectSudoku=Sudoku
|
||||
mainMenuSelectBattleship=Battleship
|
||||
mainMenuSelectOther=Other
|
||||
mainMenuSelectCredits=Credits
|
||||
mainMenuSelectOptions=Options
|
||||
mainMenuSelectQuit=Quit
|
||||
|
||||
# Quit Menu text and buttons
|
||||
quitMenuTextSure=Are you sure?
|
||||
quitMenuButtonYes=Yes
|
||||
quitMenuButtonNo=No
|
||||
@@ -0,0 +1,99 @@
|
||||
accept=\u0642\u0628\u0648\u0644
|
||||
ai=\u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0635\u0646\u0627\u0639\u064a
|
||||
app-title=\u0645\u062e\u062a\u0627\u0631 \u0627\u0644\u0643\u0627\u0645 \u0627\u0644\u0645\u062e\u062a\u0627\u0631
|
||||
are-you-sure=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f?
|
||||
back=\u0627\u0644\u0631\u062c\u0648\u0639
|
||||
cancel=\u0625\u0644\u063a\u0627\u0621
|
||||
challenge=\u062a\u062d\u062f\u064a
|
||||
connect4=Connect 4
|
||||
computer-difficulty=\u0635\u0639\u0648\u0628 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631
|
||||
computer-think-time=\u0648\u0642\u062a \u062a\u0641\u0643\u064a\u0631 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631
|
||||
computer=\u0643\u0645\u0628\u064a\u0648\u062a\u0631
|
||||
connect=\u0627\u062a\u0635\u0627\u0644
|
||||
credits=\u0627\u0644\u0645\u0633\u0627\u0647\u0645\u0629
|
||||
dark=\u0638\u0644\u0627\u0645
|
||||
deny=\u0631\u0641\u0636
|
||||
developers=\u0627\u0644\u0645\u0637\u0648\u0631\u0648\u0646
|
||||
disconnect=\u0641\u0635\u0644 \u0627\u0644\u0627\u062a\u0635\u0627\u0644
|
||||
effects-volume=\u0635\u0648\u062a \u0627\u0644\u062a\u0623\u062b\u064a\u0631\u0627\u062a
|
||||
enter-the-server-ip=\u0623\u062f\u062e\u0644 \u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0633\u064a\u0631\u0641\u0631
|
||||
enter-the-server-port=\u0623\u062f\u062e\u0644 \u0645\u0646\u0641\u0630 \u0627\u0644\u0633\u064a\u0631\u0641\u0631
|
||||
enter-your-name=\u0623\u062f\u062e\u0644 \u0627\u0633\u0645\u0643
|
||||
error=\u062e\u0637\u0623
|
||||
exit=\u062e\u0631\u0648\u062c
|
||||
forfeit=\u0627\u0633\u062a\u0643\u0644\u0627\u0644
|
||||
fullscreen=\u0643\u0627\u0645\u0644 \u0627\u0644\u0634\u0627\u0634\u0629
|
||||
game-over=\u0627\u0646\u062a\u0647\u062a \u0627\u0644\u0644\u0639\u0628\u0629
|
||||
general=\u0639\u0627\u0645
|
||||
high-contrast=\u062A\u0628\u0627\u0646\u064A\u0629 \u0639\u0627\u0644\u064A
|
||||
invalid-username=\u0627\u0633\u0645 \u063a\u064a\u0631 \u0635\u062d\u064a\u062d
|
||||
ip-address=\u0639\u0646\u0648\u0627\u0646 IP
|
||||
is-not-a-valid-ip-address=\u0644\u064a\u0633 \u0639\u0646\u0648\u0627\u0646 IP \u0635\u062d\u064a\u062d
|
||||
is-not-a-valid-port=\u0644\u064a\u0633 \u0645\u0646\u0641\u0630 \u0635\u062d\u064a\u062d
|
||||
language=\u0644\u063a\u0629
|
||||
large=\u0633\u064a\u0631
|
||||
layout-size=\u062d\u062c\u0645 \u0627\u0644\u062a\u0635\u0645\u064a\u0645
|
||||
light=\u0636\u0624\u0621
|
||||
local=\u0645\u062d\u0644\u064a
|
||||
localization=\u062a\u0639\u0631\u064a\u0628 \u0627\u0644\u0644\u063a\u0629
|
||||
master-volume=\u0635\u0648\u062a \u0627\u0644\u0645\u0633\u062a\u0648\u0649
|
||||
medium=\u0645\u062a\u0648\u0633\u0637
|
||||
merge-commander=Merge Commander
|
||||
moral-support=\u062f\u0639\u0645 \u0623\u0639\u0635\u0627\u0628\u064a
|
||||
music-volume=\u0635\u0648\u062a \u0627\u0644\u0645\u0648\u0633\u064a\u0642\u0649
|
||||
name=\u0627\u0633\u0645
|
||||
never=\u0644\u0627\u060c \u0644\u0627 \u0623\u0631\u064A\u062F \u0623\u0646 \u0623\u0631\u0649 \u0623\u064A \u062F\u0631\u0648\u0633 \u0639\u0644\u0649 \u0627\u0644\u0625\u0637\u0644\u0627\u0642.
|
||||
no=\u0644\u0627
|
||||
ok=\u0645\u0648\u0627\u0641\u0642
|
||||
online=\u0645\u062a\u0635\u0644
|
||||
opengl=OpenGL
|
||||
options=\u062e\u064a\u0627\u0631\u0627\u062a
|
||||
play=\u0644\u0639\u0628
|
||||
player-name=\u0627\u0633\u0645 \u0627\u0644\u0644\u0627\u0639\u0628
|
||||
player=\u0644\u0627\u0639\u0628
|
||||
please-enter-your-name=\u064a\u0631\u062c\u0649 \u0623\u062f\u062e\u0644 \u0627\u0633\u0645\u0643
|
||||
port=\u0645\u0646\u0641\u0630
|
||||
product-owner=\u0635\u0627\u062d\u0628 \u0627\u0644\u0645\u0646\u062a\u062c
|
||||
quit=\u062e\u0631\u0648\u062c
|
||||
reversi=\u0631\u064a\u0641\u0631\u0633\u064a
|
||||
scrum-master=Scrum Master
|
||||
send=\u0625\u0631\u0633\u0627\u0644
|
||||
server-information=\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u0633\u064a\u0631\u0641\u0631
|
||||
small=\u0635\u063a\u064a\u0631
|
||||
style=\u0623\u0633\u0644\u0648\u0628
|
||||
the-game-ended-in-a-draw=\u0627\u0646\u062a\u0647\u062a \u0627\u0644\u0644\u0639\u0628\u0629 \u0628\u062a\u0639\u0627\u062f\u0644
|
||||
theme=\u0645\u0648\u0636\u0648\u0639
|
||||
tic-tac-toe=\u062a\u064a\u0643 \u062a\u0627\u0643 \u062a\u0648
|
||||
tictactoe1 =\u0645\u0631\u062d\u0628\u064b\u0627 \u0628\u0643 \u0641\u064a \u0644\u0639\u0628\u0629 \u0625\u0643\u0633-\u0623\u0648! \u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0642\u064a\u0627\u0645 \u0628\u062d\u0631\u0643\u062a\u0643 \u0628\u0627\u0644\u0646\u0642\u0631 \u0639\u0644\u0649 \u0623\u064a \u0645\u0646 \u0627\u0644\u0645\u0631\u0628\u0639\u0627\u062a \u0627\u0644\u062a\u0633\u0639\u0629 \u0639\u0644\u0649 \u0627\u0644\u0644\u0648\u062d\u0629. \u0627\u0644\u0645\u062b\u0627\u0644 \u0623\u0639\u0644\u0627\u0647:
|
||||
tictactoe2 =\u064a\u0641\u0648\u0632 \u0627\u0644\u0644\u0627\u0639\u0628 \u0639\u0646\u062f\u0645\u0627 \u064a\u062d\u0635\u0644 \u0639\u0644\u0649 \u062b\u0644\u0627\u062b \u0642\u0637\u0639 \u0645\u062a\u062a\u0627\u0644\u064a\u0629 ? \u0623\u0641\u0642\u064a\u064b\u0627 \u0623\u0648 \u0639\u0645\u0648\u062f\u064a\u064b\u0627 \u0623\u0648 \u0642\u0637\u0631\u064a\u064b\u0627. \u0641\u064a \u0627\u0644\u0645\u062b\u0627\u0644 \u0623\u0639\u0644\u0627\u0647\u060c \u064a\u0641\u0648\u0632 \u0627\u0644\u0644\u0627\u0639\u0628 \u0628\u0635\u0641 \u0642\u0637\u0631\u064a \u0645\u0646 \u062b\u0644\u0627\u062b \u0642\u0637\u0639
|
||||
to-a-game-of=\u0625\u0644\u0649 \u0644\u0639\u0628\u0629 \u0645\u0646
|
||||
tutorial=\u0647\u0644 \u062a\u0631\u064a\u062f \u0645\u0634\u0627\u0647\u062f\u0629 \u062f\u0644\u064a\u0644 \u0644\u0647\u0630\u0627 \u0627\u0644\u0644\u0639\u0628\u0629\u061f
|
||||
volume=\u0635\u0648\u062a
|
||||
windowed=\u0641\u064a \u0646\u0641\u0630\u0629
|
||||
yes=\u0646\u0639\u0645
|
||||
you-lost-against=\u0623\u0646\u062a \u062e\u0633\u0631\u062a \u0636\u062f
|
||||
you-were-challenged-by=\u062a\u062d\u062f\u064a\u062a \u0645\u0646
|
||||
you-win=\u0623\u0646\u062a \u062a\u0641\u0648\u0632
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=\u0645\u0631\u062d\u0628\u0627 \u0628\u0643 \u0641\u064a \u0644\u0639\u0628\u0629 Connect 4! \u064a\u0645\u0643\u0646\u0643 \u062a\u0633\u0645\u064a\u0629 \u0627\u0644\u0644\u0639\u0628 \u0645\u0646 \u0637\u0631\u0641 \u0645\u0646 \u0627\u0644\u0639\u0645\u0648\u062f\u0627\u062a. \u0633\u064a\u062a\u0645 \u0648\u0636\u0639 \u0627\u0644\u0644\u062d\u0629 \u0627\u0644\u0623\u0642\u0644 \u0641\u064a \u062a\u0644\u0643 \u0627\u0644\u0639\u0645\u0648\u062f\u0629 \u0627\u0644\u0645\u0644\u0623\u0629 \u0627\u0644\u062a\u064a \u0644\u064a\u0633\u062a\u0645\u0644\u0623 \u0627\u0644\u0645\u0644\u0623\u0629.
|
||||
connect4.2=\u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0641\u0648\u0632 \u0628\u0647\u0632\u0645 \u0623\u0631\u062c\u0639 \u0645\u0646 \u0627\u0644\u0642\u0637\u0639 \u0627\u0644\u0641\u064a \u0627\u0644\u0623\u0641\u0642 \u0623\u0648 \u0627\u0644\u0645\u064a\u0646 \u0623\u0648 \u0623\u0641\u0642 \u0639\u0644\u0649 \u0627\u0644\u0645\u0644\u0623\u0629!
|
||||
reversi1=\u0645\u0631\u062d\u0628\u0627 \u0628\u0643 \u0641\u064a \u0644\u0639\u0628\u0629 Reversi! \u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0644\u0639\u0628 \u0628\u0627\u0644\u0646\u0642\u0631 \u0639\u0644\u0649 \u0623\u064a \u0646\u0642\u0637\u0629 \u0645\u0634\u0631\u0641\u0629.
|
||||
reversi2=\u0639\u0646\u062f\u0645\u0627 \u062a\u0646\u0642\u0631 \u0639\u0644\u0649 \u0646\u0642\u0637\u0629 \u0633\u064a\u062a\u063a\u064a\u0631 \u062c\u0645\u064a\u0639 \u0627\u0644\u0644\u0648\u0639\u0627\u0628 \u0628\u064a\u0646 \u0645\u0643\u0627\u0646 \u062a\u0636\u0639 \u0627\u0644\u0646\u0642\u0637\u0629 \u0648\u0646\u0642\u0637\u0629 \u0627\u0644\u0644\u0648\u0639 \u0627\u0644\u062a\u0627\u0644\u064a \u0627\u0644\u0645\u0648\u062c\u0648\u062f.
|
||||
reversi3=\u0645\u0631\u062a\u0643 \u0642\u062f \u064a\u062a\u063a\u0627\u0637 \u0625\u0630\u0627 \u0644\u0645 \u064a\u0643\u0646 \u0647\u0646\u0627\u0643 \u062d\u0631\u0643 \u0642\u0627\u0646\u0648\u0646\u064a.
|
||||
reversi4=\u0627\u0644\u0644\u0627\u0639\u0628 \u0627\u0644\u0630\u064a \u064a\u0641\u0648\u0632 \u0641\u064a \u0646\u0647\u0627\u064a\u0629 \u0627\u0644\u0644\u0639\u0628 \u0647\u0648 \u0627\u0644\u0630\u064a \u064a\u0643\u0648\u0646 \u0644\u062f\u064a\u0647 \u0627\u0644\u0623\u0643\u062b\u0631 \u0645\u0646 \u0627\u0644\u0644\u0648\u0639\u0627\u0628 \u0639\u0644\u0649 \u0627\u0644\u0644\u0648\u062d\u0629.
|
||||
tutorialstring=\u0627\u0644\u062f\u0631\u0633 \u0627\u0644\u062a\u0648\u0636\u064a\u062d\u064a
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629
|
||||
chinese=\u4e2d\u6587 (\u0627\u0644\u0635\u064a\u0646\u064a\u0629)
|
||||
dutch=Nederlands (\u0627\u0644\u0647\u0648\u0644\u0646\u062f\u064a\u0629)
|
||||
english=English (\u0627\u0644\u0625\u0646\u062c\u0644\u064a\u0632\u064a\u0629)
|
||||
french=Fran\u00e7ais (\u0627\u0644\u0641\u0631\u0646\u0633\u064a\u0629)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u0627\u0644\u062c\u0648\u0631\u062c\u064a\u0629)
|
||||
german=Deutsch (\u0627\u0644\u0623\u0644\u0645\u0627\u0646\u064a\u0629)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\u0627\u0644\u0647\u0646\u062f\u064a\u0629)
|
||||
italian=Italiano (\u0627\u0644\u0625\u064a\u0637\u0627\u0644\u064a\u0629)
|
||||
japanese=\u65e5\u672c\u8a9e (\u0627\u0644\u064a\u0627\u0628\u0627\u0646\u064a\u0629)
|
||||
korean=\ud55c\uad6d\uc5b4 (\u0627\u0644\u0643\u0648\u0631\u064a\u0629)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\u0627\u0644\u0631\u0648\u0633\u064a\u0629)
|
||||
spanish=Espa\u00f1ol (\u0627\u0644\u0625\u0633\u0628\u0627\u0646\u064a\u0629)
|
||||
@@ -1,17 +1,101 @@
|
||||
# Window title
|
||||
windowTitle=ISY Spiele-Auswahl
|
||||
accept=Akzeptieren
|
||||
ai=K\u00fcnstliche Intelligenz
|
||||
app-title=ISY Spiele-Auswahl
|
||||
are-you-sure=Sind Sie sicher?
|
||||
back=Zur\u00fcck
|
||||
cancel=Abbrechen
|
||||
challenge=Herausforderung
|
||||
computer-difficulty=Computer Schwierigkeit
|
||||
computer-think-time=Computer Denkzeit
|
||||
computer=Computer
|
||||
connect=Verbinden
|
||||
connect4=Connect 4
|
||||
|
||||
# Main Menu buttons
|
||||
mainMenuSelectTicTacToe=Tic Tac Toe
|
||||
mainMenuSelectReversi=Reversi
|
||||
mainMenuSelectSudoku=Sudoku
|
||||
mainMenuSelectBattleship=Flottenman\u00F6ver
|
||||
mainMenuSelectOther=Andere
|
||||
mainMenuSelectCredits=Credits
|
||||
mainMenuSelectOptions=Optionen
|
||||
mainMenuSelectQuit=Beenden
|
||||
credits=Credits
|
||||
dark=Dunkel
|
||||
deny=Ablehnen
|
||||
developers=Entwickler
|
||||
disconnect=Trennen
|
||||
effects-volume=Effektlautst\u00e4rke
|
||||
enter-the-server-ip=Server-IP eingeben
|
||||
enter-the-server-port=Server-Port eingeben
|
||||
enter-your-name=Geben Sie Ihren Namen ein
|
||||
error=Fehler
|
||||
exit=Beenden
|
||||
forfeit=Aufgeben
|
||||
fullscreen=Vollbild
|
||||
game-over=Spiel vorbei
|
||||
general=Allgemein
|
||||
high-contrast=Hoher Kontrast
|
||||
invalid-username=Ung\u00fcltiger Benutzername
|
||||
ip-address=IP-Adresse
|
||||
is-not-a-valid-ip-address=ist keine g\u00fcltige IP-Adresse
|
||||
is-not-a-valid-port=ist kein g\u00fcltiger Port
|
||||
language=Sprache
|
||||
large=Gro\u00df
|
||||
layout-size=Layout-Gr\u00f6\u00dfe
|
||||
light=Hell
|
||||
local=Lokal
|
||||
localization=Lokalisierung
|
||||
master-volume=Gesamtlautst\u00e4rke
|
||||
medium=Mittel
|
||||
merge-commander=Merge Commander
|
||||
moral-support=Mentale Unterst\u00fctzung
|
||||
music-volume=Musiklautst\u00e4rke
|
||||
name=Name
|
||||
never=Nein, ich m\u00f6chte niemals irgendwelche Tutorials sehen.
|
||||
no=Nein
|
||||
ok=Ok
|
||||
online=Online
|
||||
opengl=OpenGL
|
||||
options=Optionen
|
||||
play=Spielen
|
||||
player-name=Spielername
|
||||
player=Spieler
|
||||
please-enter-your-name=Bitte geben Sie Ihren Namen ein
|
||||
port=Port
|
||||
product-owner=Produktverantwortlicher
|
||||
quit=Beenden
|
||||
reversi=Reversi
|
||||
scrum-master=Scrum Master
|
||||
send=Senden
|
||||
server-information=Serverinformationen
|
||||
small=Klein
|
||||
style=Stil
|
||||
the-game-ended-in-a-draw=Das Spiel endete unentschieden
|
||||
theme=Thema
|
||||
tic-tac-toe=Tic Tac Toe
|
||||
tictactoe1 =Willkommen beim Spiel Tic Tac Toe! Du kannst deinen Zug machen, indem du auf eines der 9 Felder auf dem Spielfeld klickst. Beispiel oben:
|
||||
tictactoe2 =Ein Spieler gewinnt, wenn er drei Steine in einer Reihe hat ? horizontal, vertikal oder diagonal. Im obigen Beispiel gewinnt der Spieler mit einer diagonalen Reihe von drei Steinen.
|
||||
to-a-game-of=zu einem Spiel von
|
||||
tutorial=M\u00f6chtest du ein Tutorial f\u00fcr dieses Spiel sehen?
|
||||
|
||||
# Quit Menu text and buttons
|
||||
quitMenuTextSure=Bist du sicher?
|
||||
quitMenuButtonYes=Ja
|
||||
quitMenuButtonNo=Nein
|
||||
volume=Lautst\u00e4rke
|
||||
windowed=Fenstermodus
|
||||
yes=Ja
|
||||
you-lost-against=Sie haben gegen ... verloren
|
||||
you-were-challenged-by=Sie wurden herausgefordert von ...
|
||||
you-win=Sie gewinnen
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=Willkommen beim Spiel Connect 4! Du kannst einen Zug machen, indem du auf eine der Spalten klickst. Der Zug wird in der niedrigsten noch freien Reihe dieser Spalte platziert.
|
||||
connect4.2=Du kannst gewinnen, indem du 4 Spielsteine deiner Farbe horizontal, diagonal oder vertikal verbindest! Siehe das obige Beispiel.
|
||||
reversi1=Willkommen beim Spiel Reversi! Du kannst einen Zug machen, indem du auf einen der leicht transparenten Punkte klickst.
|
||||
reversi2=Wenn du auf einen Punkt klickst, werden alle Spielsteine dazwischen umgedreht, bis zum n<>chsten Punkt. Siehe das Beispiel oben, wo Gelb die zu drehenden Steine ist.
|
||||
reversi3=Dein Zug kann <20>bersprungen werden, wenn es keinen legalen Zug gibt. Dein Gegner spielt dann weiter, bis du einen legalen Zug machen kannst.
|
||||
reversi4=Der Spieler, der am Ende die meisten Steine auf dem Brett hat, gewinnt.
|
||||
tutorialstring=Tutorial
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabisch)
|
||||
chinese=\u4e2d\u6587 (Chinesisch)
|
||||
dutch=Nederlands (Niederl\u00e4ndisch)
|
||||
english=English (Englisch)
|
||||
french=Fran\u00e7ais (Franz\u00f6sisch)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgisch)
|
||||
german=Deutsch
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
|
||||
italian=Italiano (Italienisch)
|
||||
japanese=\u65e5\u672c\u8a9e (Japanisch)
|
||||
korean=\ud55c\uad6d\uc5b4 (Koreanisch)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russisch)
|
||||
spanish=Espa\u00f1ol (Spanisch)
|
||||
@@ -0,0 +1,103 @@
|
||||
accept=Accept
|
||||
ai=Artificial Intelligence
|
||||
app-title=ISY Games Selector
|
||||
are-you-sure=Are you sure?
|
||||
back=Back
|
||||
cancel=Cancel
|
||||
challenge=Challenge
|
||||
computer-difficulty=Computer difficulty
|
||||
computer-think-time=Computer think time
|
||||
computer=Computer
|
||||
connect=Connect
|
||||
credits=Credits
|
||||
dark=Dark
|
||||
deny=Deny
|
||||
developers=Developers
|
||||
disconnect=Disconnect
|
||||
effects-volume=Effects Volume
|
||||
enter-the-server-ip=Enter the server ip
|
||||
enter-the-server-port=Enter the server port
|
||||
enter-your-name=Enter your name
|
||||
error=Error
|
||||
exit=Exit
|
||||
forfeit=Forfeit
|
||||
fullscreen=Fullscreen
|
||||
game-over=Game Over
|
||||
general=General
|
||||
high-contrast=High contrast
|
||||
invalid-username=invalid username
|
||||
ip-address=IP address
|
||||
is-not-a-valid-ip-address=is not a valid-ip address
|
||||
is-not-a-valid-port=is not a valid port
|
||||
language=Language
|
||||
large=Large
|
||||
layout-size=Layout Size
|
||||
light=Light
|
||||
local=Local
|
||||
localization=Localization
|
||||
master-volume=Master Volume
|
||||
medium=Medium
|
||||
merge-commander=Merge Commander
|
||||
moral-support=Moral Support
|
||||
music-volume=Music Volume
|
||||
name=Name
|
||||
no=No
|
||||
never=No, I never want to see any tutorials
|
||||
ok=Ok
|
||||
online=Online
|
||||
opengl=OpenGL
|
||||
options=Options
|
||||
play=Play
|
||||
player-name=Player name
|
||||
player=Player
|
||||
please-enter-your-name=Please enter your name
|
||||
port=Port
|
||||
product-owner=Product Owner
|
||||
quit=Quit
|
||||
reversi=Reversi
|
||||
scrum-master=Scrum Master
|
||||
send=Send
|
||||
server-information=Server information
|
||||
small=Small
|
||||
style=Style
|
||||
the-game-ended-in-a-draw=The game ended in a draw
|
||||
theme=Theme
|
||||
tic-tac-toe=Tic Tac Toe
|
||||
tictactoe1 =Welcome to the game of Tic Tac Toe! You can make your move by clicking on any of the 9 squares on the board. Example above:
|
||||
tictactoe2 =A player wins by getting 3 pieces in a row - horizontally, vertically or diagonally. In the example above, the player wins with a diagonal row of three pieces.
|
||||
tutorial=Do you want a tutorial for this game?
|
||||
connect4=Connect 4
|
||||
to-a-game-of=to a game of
|
||||
volume=Volume
|
||||
windowed=Windowed
|
||||
yes=Yes
|
||||
you-lost-against=You lost against
|
||||
you-were-challenged-by=You were challenged by
|
||||
you-win=You win
|
||||
>=>
|
||||
<=<
|
||||
// tutorial
|
||||
connect4.1=Welcome to the game of Connect 4! You can make a move by clicking one of the columns. The move will be placed in the lowest row of that column that is not filled yet.
|
||||
connect4.2=You can win by getting 4 pieces of your row horizontally, diagonally or vertically! For an example, see above.
|
||||
reversi1=Welcome to the game of Reversi! You can make a move by clicking on one of the slightly transparent dots.
|
||||
reversi2=Clicking on a dot will flip all the moves between where you place the dot and the next dot it finds. See the example above, where yellow is the moves to be flipped.
|
||||
reversi3=Your turn may be skipped if there is no legal move. This will let your opponent play again until you get an opportunity at a legal move.
|
||||
reversi4=The player who wins at the end of the game is the one who has the most pieces on the board.
|
||||
tutorialstring=Tutorial
|
||||
startgame=Start game!
|
||||
goback=Go back
|
||||
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabic)
|
||||
chinese=\u4e2d\u6587 (Chinese)
|
||||
dutch=Nederlands (Dutch)
|
||||
english=English
|
||||
french=Fran\u00e7ais (French)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgian)
|
||||
german=Deutsch (German)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
|
||||
italian=Italiano (Italian)
|
||||
japanese=\u65e5\u672c\u8a9e (Japanese)
|
||||
korean=\ud55c\uad6d\uc5b4 (Korean)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russian)
|
||||
spanish=Espa\u00f1ol (Spanish)
|
||||
@@ -1,17 +1,101 @@
|
||||
# Window title
|
||||
windowTitle=Selector de juegos ISY
|
||||
accept=Aceptar
|
||||
ai=Inteligencia Artificial
|
||||
app-title=Selector de Juegos ISY
|
||||
are-you-sure=\u00bfEst\u00e1s seguro?
|
||||
back=Atr\u00e1s
|
||||
cancel=Cancelar
|
||||
challenge=Desaf\u00edo
|
||||
computer-difficulty=Dificultad del ordenador
|
||||
computer-think-time=Tiempo de pensamiento del ordenador
|
||||
computer=Ordenador
|
||||
connect=Conectar
|
||||
connect4=Connect 4
|
||||
|
||||
# Main Menu buttons
|
||||
mainMenuSelectTicTacToe=Tres en raya
|
||||
mainMenuSelectReversi=Reversi
|
||||
mainMenuSelectSudoku=Sudoku
|
||||
mainMenuSelectBattleship=Batalla naval
|
||||
mainMenuSelectOther=Otros
|
||||
mainMenuSelectCredits=Cr\u00E9ditos
|
||||
mainMenuSelectOptions=Opciones
|
||||
mainMenuSelectQuit=Salir
|
||||
credits=Cr\u00e9ditos
|
||||
dark=Oscuro
|
||||
deny=Denegar
|
||||
developers=Desarrolladores
|
||||
disconnect=Desconectar
|
||||
effects-volume=Volumen de efectos
|
||||
enter-the-server-ip=Introduce la IP del servidor
|
||||
enter-the-server-port=Introduce el puerto del servidor
|
||||
enter-your-name=Introduce tu nombre
|
||||
error=Error
|
||||
exit=Salir
|
||||
forfeit=Rendirse
|
||||
fullscreen=Pantalla completa
|
||||
game-over=Fin del juego
|
||||
general=General
|
||||
high-contrast=Alto contraste
|
||||
invalid-username=nombre de usuario inv\u00e1lido
|
||||
ip-address=Direcci\u00f3n IP
|
||||
is-not-a-valid-ip-address=no es una direcci\u00f3n IP v\u00e1lida
|
||||
is-not-a-valid-port=no es un puerto v\u00e1lido
|
||||
language=Idioma
|
||||
large=Grande
|
||||
layout-size=Tama\u00f1o de dise\u00f1o
|
||||
light=Claro
|
||||
local=Local
|
||||
localization=Localizaci\u00f3n
|
||||
master-volume=Volumen maestro
|
||||
medium=Mediano
|
||||
merge-commander=Merge Commander
|
||||
moral-support=Apoyo moral
|
||||
music-volume=Volumen de m\u00fasica
|
||||
name=Nombre
|
||||
never=No, no quiero ver ning\u00fan tutorial nunca.
|
||||
no=No
|
||||
ok=OK
|
||||
online=En l\u00ednea
|
||||
opengl=OpenGL
|
||||
options=Opciones
|
||||
play=Jugar
|
||||
player-name=Nombre del jugador
|
||||
player=Jugador
|
||||
please-enter-your-name=Por favor, introduce tu nombre
|
||||
port=Puerto
|
||||
product-owner=Propietario del producto
|
||||
quit=Salir
|
||||
reversi=Reversi
|
||||
scrum-master=Scrum Master
|
||||
send=Enviar
|
||||
server-information=Informaci\u00f3n del servidor
|
||||
small=Peque\u00f1o
|
||||
style=Estilo
|
||||
the-game-ended-in-a-draw=El juego termin\u00f3 en empate
|
||||
theme=Tema
|
||||
tic-tac-toe=Tres en raya
|
||||
tictactoe1 =\u00a1Bienvenido al juego del Tres en Raya! Puedes hacer tu jugada haciendo clic en cualquiera de los 9 cuadros del tablero. Ejemplo arriba:
|
||||
tictactoe2 =Un jugador gana al conseguir 3 fichas en l\u00ednea, ya sea horizontal, vertical o diagonalmente. En el ejemplo de arriba, el jugador gana con una fila diagonal de tres fichas.
|
||||
to-a-game-of=a un juego de
|
||||
tutorial=\u00bfQuieres ver un tutorial para este juego?
|
||||
volume=Volumen
|
||||
windowed=En ventana
|
||||
yes=S\u00ed
|
||||
you-lost-against=Perdiste contra
|
||||
you-were-challenged-by=Fuiste desafiado por
|
||||
you-win=Ganaste
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=\u00a1Bienvenido al juego de Connect 4! Puedes hacer un movimiento haciendo clic en una de las columnas. El movimiento se colocar<61> en la fila m<>s baja de esa columna que no est<73> llena.
|
||||
connect4.2=\u00a1Puedes ganar consiguiendo 4 fichas de tu color horizontal, diagonal o verticalmente! Mira el ejemplo de arriba.
|
||||
reversi1=\u00a1Bienvenido al juego de Reversi! Puedes hacer un movimiento haciendo clic en uno de los puntos ligeramente transparentes.
|
||||
reversi2=Al hacer clic en un punto, se voltear<61>n todas las fichas entre donde colocas el punto y el siguiente punto que encuentre. Mira el ejemplo de arriba, donde amarillo son las fichas a voltear.
|
||||
reversi3=Tu turno puede ser saltado si no hay un movimiento legal. Esto permitir<69> que tu oponente juegue nuevamente hasta que tengas una oportunidad legal.
|
||||
reversi4=El jugador que gane al final del juego es quien tenga m<>s fichas en el tablero.
|
||||
tutorialstring=Tutorial
|
||||
|
||||
# Quit Menu text and buttons
|
||||
quitMenuTextSure=\u00BFEst\u00E1s seguro?
|
||||
quitMenuButtonYes=S\u00ED
|
||||
quitMenuButtonNo=No
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Ar\u00e1bigo)
|
||||
chinese=\u4e2d\u6587 (Chino)
|
||||
dutch=Nederlands (Neerland\u00e9s)
|
||||
english=English (Ingl\u00e9s)
|
||||
french=Fran\u00e7ais (Franc\u00e9s)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgiano)
|
||||
german=Deutsch (Alem\u00e1n)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
|
||||
italian=Italiano (Italiano)
|
||||
japanese=\u65e5\u672c\u8a9e (Japon\u00e9s)
|
||||
korean=\ud55c\uad6d\uc5b4 (Coreano)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Ruso)
|
||||
spanish=Espa\u00f1ol
|
||||
@@ -1,17 +1,100 @@
|
||||
# Window title
|
||||
windowTitle=S\u00E9lecteur de jeux ISY
|
||||
accept=Accepter
|
||||
ai=Intelligence Artificielle
|
||||
app-title=S\u00c9LECTEUR DE JEUX ISY
|
||||
are-you-sure=\u00cates-vous s\u00fbr ?
|
||||
back=Retour
|
||||
cancel=Annuler
|
||||
challenge=D\u00e9fi
|
||||
computer-difficulty=Difficult\u00e9 de l'ordinateur
|
||||
computer-think-time=Temps de r\u00e9flexion de l'ordinateur
|
||||
computer=Ordinateur
|
||||
connect=Connexion
|
||||
connect4=Connect 4
|
||||
|
||||
# Main Menu buttons
|
||||
mainMenuSelectTicTacToe=Morpion
|
||||
mainMenuSelectReversi=Reversi
|
||||
mainMenuSelectSudoku=Sudoku
|
||||
mainMenuSelectBattleship=Bataille navale
|
||||
mainMenuSelectOther=Autres
|
||||
mainMenuSelectCredits=Cr\u00E9dits
|
||||
mainMenuSelectOptions=Options
|
||||
mainMenuSelectQuit=Quitter
|
||||
credits=Cr\u00e9dits
|
||||
dark=Sombre
|
||||
deny=Refuser
|
||||
developers=D\u00e9veloppeurs
|
||||
disconnect=D\u00e9connexion
|
||||
effects-volume=Volume des effets
|
||||
enter-the-server-ip=Entrez l'adresse IP du serveur
|
||||
enter-the-server-port=Entrez le port du serveur
|
||||
enter-your-name=Entrez votre nom
|
||||
error=Erreur
|
||||
exit=Quitter
|
||||
forfeit=Abandonner
|
||||
fullscreen=Plein \u00e9cran
|
||||
game-over=Fin de la partie
|
||||
general=G\u00e9n\u00e9ral
|
||||
high-contrast=Haut contraste
|
||||
invalid-username=nom d'utilisateur invalide
|
||||
ip-address=Adresse IP
|
||||
is-not-a-valid-ip-address=n'est pas une adresse IP valide
|
||||
is-not-a-valid-port=n'est pas un port valide
|
||||
language=Langue
|
||||
large=Grand
|
||||
layout-size=Format de l'affichage
|
||||
light=Clair
|
||||
local=Local
|
||||
localization=Traduction
|
||||
master-volume=Volume principal
|
||||
medium=Moyen
|
||||
merge-commander=Merge Commander
|
||||
moral-support=Soutien moral
|
||||
music-volume=Volume de la musique
|
||||
name=Nom
|
||||
never=Non, je ne veux jamais voir de tutoriels.
|
||||
no=Non
|
||||
ok=OK
|
||||
online=En ligne
|
||||
opengl=OpenGL
|
||||
options=Options
|
||||
play=Jouer
|
||||
player-name=Nom du joueur
|
||||
player=Joueur
|
||||
please-enter-your-name=Veuillez entrer votre nom
|
||||
port=Port
|
||||
product-owner=Responsable produit
|
||||
quit=Quitter
|
||||
reversi=Reversi
|
||||
scrum-master=Scrum Master
|
||||
send=Envoyer
|
||||
server-information=Informations du serveur
|
||||
small=Petit
|
||||
style=Style
|
||||
the-game-ended-in-a-draw=La partie s'est termin\u00e9e par un match nul
|
||||
theme=Th\u00e8me
|
||||
tic-tac-toe=Morpion
|
||||
tictactoe1 =Bienvenue dans le jeu du Tic Tac Toe ! Vous pouvez jouer en cliquant sur l\u2019une des 9 cases du plateau. Exemple ci-dessus :
|
||||
tictactoe2 =Un joueur gagne en alignant 3 pi\u00e8ces \u2013 horizontalement, verticalement ou en diagonale. Dans l\u2019exemple ci-dessus, le joueur gagne avec une diagonale de trois pi\u00e8ces.
|
||||
to-a-game-of=\u00e0 une partie de
|
||||
tutorial=Veux-tu voir un tutoriel pour ce jeu\u00a0?
|
||||
volume=Volume
|
||||
windowed=Fen\u00eatrr\u00e9
|
||||
yes=Oui
|
||||
you-lost-against=Vous avez perdu contre
|
||||
you-were-challenged-by=Vous avez \u00e9t\u00e9 d\u00e9fi\u00e9 par
|
||||
you-win=Vous avez gagn\u00e9
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=Bienvenue dans le jeu Connect 4 ! Vous pouvez effectuer un mouvement en cliquant sur l'une des colonnes. Le mouvement sera plac<61> dans la ligne la plus basse de cette colonne qui n'est pas encore remplie.
|
||||
connect4.2=Vous pouvez gagner en alignant 4 pions de votre couleur horizontalement, diagonalement ou verticalement ! Voir l'exemple ci-dessus.
|
||||
reversi1=Bienvenue dans le jeu Reversi ! Vous pouvez jouer en cliquant sur l'un des points l<>g<EFBFBD>rement transparents.
|
||||
reversi2=Cliquer sur un point retournera tous les pions entre le point plac<61> et le prochain point trouv<75>. Voir l'exemple ci-dessus, o<> le jaune indique les pions <20> retourner.
|
||||
reversi3=Votre tour peut <20>tre saut<75> s'il n'y a pas de coup l<>gal. Cela permettra <20> votre adversaire de jouer jusqu'<27> ce que vous ayez un coup l<>gal.
|
||||
reversi4=Le joueur qui a le plus de pions <20> la fin du jeu gagne.
|
||||
tutorialstring=Tutoriel
|
||||
|
||||
# Quit Menu text and buttons
|
||||
quitMenuTextSure=\u00CAtes-vous s\u00FBr?
|
||||
quitMenuButtonYes=Oui
|
||||
quitMenuButtonNo=Non
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabe)
|
||||
chinese=\u4e2d\u6587 (Chinois)
|
||||
dutch=Nederlands (N\u00e9erlandais)
|
||||
english=English (Anglais)
|
||||
french=Fran\u00e7ais
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (G\u00e9orgien)
|
||||
german=Deutsch (Allemand)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
|
||||
italian=Italiano (Italien)
|
||||
japanese=\u65e5\u672c\u8a9e (Japonais)
|
||||
korean=\ud55c\uad6d\uc5b4 (Cor\u00e9en)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russe)
|
||||
spanish=Espa\u00f1ol (Espagnol)
|
||||
@@ -0,0 +1,100 @@
|
||||
accept=\u0938\u094d\u0935\u0940\u0915\u093e\u0930
|
||||
ai=\u0915\u0943\u0924\u094d\u0930\u093f\u092e \u092c\u0941\u0926\u094d\u0927\u093f
|
||||
app-title=ISY \u0917\u0947\u092e \u091a\u092f\u0928\u0915\u093e\u0930\u0940
|
||||
are-you-sure=\u0915\u094d\u092f\u093e \u0906\u092a \u0928\u093f\u0936\u094d\u091a\u093f\u0924 \u0939\u0948\u0902?
|
||||
back=\u092a\u0940\u091b\u0947
|
||||
cancel=\u0930\u0926\u094d\u0926 \u0915\u0930\u0947\u0902
|
||||
challenge=\u091a\u0941\u0928\u094c\u0924\u0940
|
||||
computer-difficulty=\u0915\u0902\u092a\u094d\u092f\u0942\u091f\u0930 \u0915\u0940 \u0915\u0920\u0928\u093e\u0908
|
||||
computer-think-time=\u0915\u0902\u092a\u094d\u092f\u0942\u091f\u0930 \u091a\u093f\u0902\u0924\u0928 \u0938\u092e\u092f
|
||||
computer=\u0915\u0902\u092a\u094d\u092f\u0942\u091f\u0930
|
||||
connect=\u091c\u094b\u095c\u0947\u0902
|
||||
connect4=Connect 4
|
||||
|
||||
credits=\u0915\u094d\u0930\u0947\u0921\u093f\u091f\u094d\u0938
|
||||
dark=\u0917\u0939\u0930\u093e
|
||||
deny=\u0907\u0902\u0915\u093e\u0930
|
||||
developers=\u0935\u093f\u0915\u093e\u0938\u093f\u0924\u093e
|
||||
disconnect=\u091c\u094b\u095c \u091f\u0942\u091f\u0928\u093e
|
||||
effects-volume=\u090f\u092b\u0947\u0915\u094d\u091f \u0935\u0949\u0932\u094d\u092f\u0942\u092e
|
||||
enter-the-server-ip=\u0938\u0930\u094d\u0935\u0930 IP \u0926\u093e\u0916\u093f\u090f
|
||||
enter-the-server-port=\u0938\u0930\u094d\u0935\u0930 \u092a\u094b\u0930\u094d\u091f \u0926\u093e\u0916\u093f\u090f
|
||||
enter-your-name=\u0905\u092a\u0928\u093e \u0928\u093e\u092e \u0926\u093e\u0916\u093f\u090f
|
||||
error=\u0924\u094d\u0930\u0941\u091f\u093f
|
||||
exit=\u092c\u093e\u0939\u0930 \u0928\u093f\u0915\u093e\u0932\u0940\u090f\u0902
|
||||
forfeit=\u0939\u093e\u0930 \u092e\u093e\u0928\u0928\u093e
|
||||
fullscreen=\u092a\u0942\u0930\u0940 \u0938\u094d\u0915\u094d\u0930\u0940\u0928
|
||||
game-over=\u0916\u0947\u0932 \u0916\u0924\u094d\u092e
|
||||
general=\u0938\u093e\u092e\u093e\u0928\u094d\u092f
|
||||
high-contrast=\u0909\u091A\u094D\u091A\u093F\u0924 \u0915\u0949\u0902\u091F\u094D\u0930\u093E\u0938\u094D\u091F
|
||||
invalid-username=\u0905\u092e\u093e\u0928\u094d\u092f \u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e \u0928\u093e\u092e
|
||||
ip-address=IP \u092a\u0924\u093e
|
||||
is-not-a-valid-ip-address=\u092f\u0939 \u090f\u0915 \u0905\u092e\u093e\u0928\u094d\u092f IP \u092a\u0924\u093e \u0928\u0939\u0940\u0902 \u0939\u0948
|
||||
is-not-a-valid-port=\u092f\u0939 \u090f\u0915 \u0905\u092e\u093e\u0928\u094d\u092f \u092a\u094b\u0930\u094d\u091f \u0928\u0939\u0940\u0902 \u0939\u0948
|
||||
language=\u092d\u093e\u0937\u093e
|
||||
large=\u092c\u095c\u093e
|
||||
layout-size=\u0932\u0947\u090f\u0913\u091f \u0915\u093e \u0906\u0915\u093e\u0930
|
||||
light=\u0915\u0947\u091c\u093c\u093e
|
||||
local=\u0938\u094d\u0925\u093e\u0928\u0940\u092f
|
||||
localization=\u0938\u094d\u0925\u093e\u0928\u0940\u092f\u0915\u0930\u0923
|
||||
master-volume=\u092e\u093e\u0938\u094d\u091f\u0930 \u0935\u0949\u0932\u094d\u092f\u0942\u092e
|
||||
medium=\u092e\u0927\u094d\u092f\u092e
|
||||
merge-commander=\u092e\u0930\u094d\u091c \u0915\u092e\u093e\u0902\u0921\u0930
|
||||
moral-support=\u0928\u0948\u0924\u093f\u0915 \u0938\u0939\u093e\u0930\u093e
|
||||
music-volume=\u0938\u0902\u0917\u0940\u0924 \u0935\u0949\u0932\u094d\u092f\u0942\u092e
|
||||
name=\u0928\u093e\u092e
|
||||
never=\u0928\u0939\u0940\u0902, \u092e\u0948\u0902 \u0915\u092c\u094d\u0939\u0940 \u092d\u0940 \u0915\u094b\u0908 \u091f\u094d\u092f\u0942\u091f\u094b\u0930\u093f\u092f\u0932 \u0928\u0939\u0940\u0902 \u0926\u0947\u0916\u0928\u093e \u091a\u093e\u0939\u0924\u093e/\u091a\u093e\u0939\u0924\u0940\u0964
|
||||
no=\u0928\u0939\u0940\u0902
|
||||
ok=\u0920\u0940\u0915 \u0939\u0948
|
||||
online=\u0911\u0928\u0932\u093e\u0907\u0928
|
||||
opengl=OpenGL
|
||||
options=\u0935\u093f\u0915\u0932\u094d\u092a
|
||||
play=\u0916\u0947\u0932\u0947\u0902
|
||||
player-name=\u0916\u093f\u0932\u093e\u095e\u0940 \u0915\u093e \u0928\u093e\u092e
|
||||
player=\u0916\u093f\u0932\u093e\u095e\u0940
|
||||
please-enter-your-name=\u0915\u0943\u092a\u092f\u093e \u0905\u092a\u0928\u093e \u0928\u093e\u092e \u0926\u093e\u0916\u093f\u090f
|
||||
port=\u092a\u094b\u0930\u094d\u091f
|
||||
product-owner=\u092a\u094d\u0930\u094b\u0921\u0915\u094d\u091f \u0915\u093e \u092e\u093e\u0932\u093f\u0915
|
||||
quit=\u091b\u094b\u0921\u0947\u0902
|
||||
reversi=\u0930\u093f\u0935\u0930\u094d\u0938\u0940
|
||||
scrum-master=\u0938\u094d\u0915\u094d\u0930\u092e \u092e\u093e\u0938\u094d\u091f\u0930
|
||||
send=\u092d\u0947\u091c\u0947\u0902
|
||||
server-information=\u0938\u0930\u094d\u0935\u0930 \u091c\u093e\u0928\u0915\u093e\u0930\u0940
|
||||
small=\u091b\u094b\u091f\u093e
|
||||
style=\u0936\u0948\u0932\u0940
|
||||
the-game-ended-in-a-draw=\u0916\u0947\u0932 \u091f\u0940\u0915 \u0939\u094b \u0917\u092f\u093e
|
||||
theme=\u0925\u0940\u092e
|
||||
tic-tac-toe=\u091f\u093f\u0915-\u091f\u0948\u0915-\u091f\u094b
|
||||
tictactoe1 =\u091f\u093f\u0915-\u091f\u0948\u0915-\u091f\u094b \u0915\u0947 \u0916\u0947\u0932 \u092e\u0947\u0902 \u0906\u092a\u0915\u093e \u0938\u094d\u0935\u093e\u0917\u0924 \u0939\u0948! \u0906\u092a \u092c\u094b\u0930\u094d\u0921 \u092a\u0930 \u0915\u093f\u0938\u0940 \u092d\u0940 9 \u0916\u093e\u0928\u0947 \u092a\u0930 \u0915\u094d\u0932\u093f\u0915 \u0915\u0930\u0915\u0947 \u0905\u092a\u0928\u0940 \u091a\u093e\u0932 \u091a\u0932 \u0938\u0915\u0924\u0947 \u0939\u0948\u0902\u0964 \u090a\u092a\u0930 \u0926\u093f\u092f\u093e \u0917\u092f\u093e \u0909\u0926\u093e\u0939\u0930\u0923 \u0926\u0947\u0916\u0947\u0902:
|
||||
tictactoe2 =\u0915\u094b\u0908 \u0916\u093f\u0932\u093e\u0921\u093c\u0940 \u0924\u092c \u091c\u0940\u0924\u0924\u093e \u0939\u0948 \u091c\u092c \u0935\u0939 \u092a\u0948 \u092a\u0902\u0915\u094d\u0924\u093f \u092e\u0947\u0902 \u0924\u0940\u0928 \u0928\u093f\u0936\u093e\u0928 \u090f\u0915 \u092a\u0902\u0915\u094d\u0924\u093f \u092e\u0947\u0902 \u0932\u0917\u093e \u0926\u0947\u0924\u093e \u0939\u0948 ? \u0915\u094d\u0937\u0948\u0924\u093f\u091c, \u090a\u0930\u094d\u0927\u094d\u0935\u093e\u0927\u0930 \u092f\u093e \u0924\u093f\u0930\u091b\u0947\u0964 \u090a\u092a\u0930 \u0909\u0926\u093e\u0939\u0930\u0923 \u092e\u0947\u0902, \u0916\u093f\u0932\u093e\u0921\u093c\u0940 \u0924\u093f\u0930\u091b\u0940 \u092a\u0902\u0915\u094d\u0924\u093f \u092e\u0947\u0902 \u0924\u093f\u0930\u091b\u0940 \u092a\u0902\u0915\u094d\u0924\u093f \u0938\u0947 \u091c\u0940\u0924\u0924\u093e \u0939\u0948\u0964
|
||||
to-a-game-of=\u0916\u0947\u0932 \u0915\u0940 \u090f\u0915 \u0916\u0947\u0932 \u0915\u0940 \u0913\u0930
|
||||
tutorial=\u0915\u094d\u092f\u093e \u0906\u092a \u0907\u0938 \u0917\u0947\u092e \u0915\u0947 \u0932\u093f\u090f \u0915\u094b\u0908 \u091f\u094d\u092f\u0942\u091f\u094b\u0930\u093f\u092f\u0932 \u0926\u0947\u0916\u0928\u093e \u091a\u093e\u0939\u0924\u0947 \u0939\u0948\u0902?
|
||||
volume=\u0935\u0949\u0932\u094d\u092f\u0942\u092e
|
||||
windowed=\u0935\u093f\u0902\u0921\u094b \u092e\u094b\u0921
|
||||
yes=\u0939\u093e\u0901
|
||||
you-lost-against=\u0906\u092a \u0939\u093e\u0930 \u0917\u090f
|
||||
you-were-challenged-by=\u0906\u092a\u0915\u094b \u091a\u0941\u0928\u094c\u0924\u0940 \u0926\u0940 \u0917\u0908
|
||||
you-win=\u0906\u092a \u091c\u0940\u0924 \u0917\u090f
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=\u0915\u0928\u094d\u0928\u0947 \u0915\u0940 \u091c\u0948 \u0915\u0947 \u091c\u094c\u0915 \u0915\u0928\u0947\u0915\u094d\u091f 4 \u092e\u0947\u0902! \u0906\u092a \u0915\u0940 \u091a\u0948\u0928 \u092a\u0932\u0938 \u092a\u0928\u094d\u0928 \u0928\u093e\u092e\u094d\u092c\u0921\u093e\u0928\u0947 \u0915\u0940 \u092f\u094b\u0917\u0924\u0940 \u092e\u0947\u0902 \u0915\u0940 \u0928\u093f\u091a\u094d\u091a\u0942\u0928 \u0915\u0940 \u0924\u0939 \u091a\u093f\u0928 \u092a\u0924\u093f \u0928\u0939\u0940\u0902 \u0926\u0947 \u092c\u0924\u0940.
|
||||
connect4.2=\u092a\u093e\u0902\u091a \u092e\u0946\u092c\u0921 \u0915\u0940 \u092a\u0930\u092a\u0930\u092f\u094d\u0928 \u092d\u093e\u0935\u0940 \u0938\u0947 4 \u092a\u093f\u0938 \u0924\u093e\u0924\u093e \u0915\u0940 \u0930\u094f\u0936\u0942 \u0938\u0940\u0926\u094d\u0927 \u092e\u0947\u0902 \u092a\u0940\u0928\u094d\u0928\u094b\u0902 \u0915\u0940 \u092e\u093e\u0928\u094d\u0926\u0930 \u0939\u0940.
|
||||
reversi1=\u0915\u0928\u094d\u0928\u0947 \u0915\u0940 \u091c\u0948 \u0910 \u0930\u0947\u0935\u0930\u094d\u0938\u0940 \u092e\u0947\u0902 \u0926\u0948\u091a \u092c\u0922\u093e\u0928 \u0915\u0940 \u092a\u0924\u094d\u0928 \u092a\u0930 \u092a\u094d\u0932\u0947 \u0916\u0942\u0928\u0947 \u0915\u0940 \u092a\u094d\u0930\u092f\u0948\u0915\u0944 \u0915\u0930\u0948\u0902.
|
||||
reversi2=\u0915\u093f\u0938 \u092a\u0930 \u092a\u093f\u0938 \u092a\u0948\u0918 \u0915\u0940 \u091a\u0928 \u092e\u0947\u0902 \u0938\u092e\u093e\u0930\u094e \u092a\u093f\u0938 \u092a\u0940\u0918 \u092e\u0947\u0902 \u092a\u0930\u093f\u0923\u0924 \u0915\u093e \u092a\u0930\u093f\u0928\u0942\u0924\u0940 \u0915\u0940 \u092a\u094d\u0930\u0924\u093f \u092a\u0941\u0928\u0940 \u092a\u0930\u093f\u0928\u094d\u0924 \u0915\u0940 \u092a\u0940\u0938 \u092a\u0930\u094d\u092f\u0928\u0947 \u091c\u093e\u0902\u0918\u0942.
|
||||
reversi3=\u092f\u0939 \u092a\u0930\u094d\u092f \u0938\u0947 \u0938\u0947\u091a \u0915\u0940 \u091c\u093e\u0902\u091c \u0928\u0939\u0940\u0902 \u0939\u0948 \u0914\u0938\u0924\u0947 \u0915\u0948 \u092a\u0948\u0928 \u092a\u0930\u094d\u092f \u0939\u0948 \u0914\u092a\u0915\u0940 \u0915\u0940 \u092a\u0932\u0947 \u092d\u0942\u0924 \u0915\u0940 \u0906\u0927\u093e \u092a\u0948\u0928 \u091c\u093e\u0902\u091c \u0915\u0930 \u0938\u0915\u0924\u0947 \u0939\u0948\u0902.
|
||||
reversi4=\u0916\u0941\u092f \u0915\u093f \u0915\u0940 \u0928\u093f\u092e\u0940 \u092e\u0947\u0902 \u091a\u093e\u0932 \u0938\u092c\u0938\u0947 \u091a\u0942\u0928\u094d\u0928\u0947 \u0939\u0948, \u0935\u0949 \u0915\u0947 \u092e\u093e\u0924\u094d\u0930 \u091c\u0940\u0924\u0947 \u0939\u0948.
|
||||
tutorialstring=\u0924\u0942\u091f\u0949\u0930\u093f\u092f\u0932
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0905\u0930\u092c\u0940)
|
||||
chinese=\u4e2d\u6587 (\u091a\u0940\u0928\u0940)
|
||||
dutch=Nederlands (\u0921\u091a)
|
||||
english=English (\u0905\u0902\u0917\u094d\u0930\u0947\u091c\u0940)
|
||||
french=Fran\u00e7ais (\u092b\u094d\u0930\u0947\u0902\u091a)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u091c\u094d\u091c\u094b\u0930\u094d\u091c\u093f\u092f\u0928)
|
||||
german=Deutsch (\u091c\u0930\u094d\u092e\u0928)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940
|
||||
italian=Italiano (\u0907\u091f\u093e\u0932\u093f\u092f\u0928)
|
||||
japanese=\u65e5\u672c\u8a9e (\u091c\u093e\u092a\u093e\u0928\u0940)
|
||||
korean=\ud55c\uad6d\uc5b4 (\u0915\u094b\u0930\u093f\u092f\u0928)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\u0930\u0942\u0938\u0940)
|
||||
spanish=Espa\u00f1ol (\u0938\u094d\u092a\u0947\u0928\u093f\u0936)
|
||||
@@ -1,17 +1,99 @@
|
||||
# Window title
|
||||
windowTitle=Selettore giochi ISY
|
||||
accept=Accetta
|
||||
ai=Intelligenza Artificiale
|
||||
app-title=Selettore di Giochi ISY
|
||||
are-you-sure=Sei sicuro?
|
||||
back=Indietro
|
||||
cancel=Annulla
|
||||
challenge=Sfida
|
||||
computer-difficulty=Difficolt\u00e0 del computer
|
||||
computer-think-time=Tempo di riflessione del computer
|
||||
computer=Computer
|
||||
connect=Connetti
|
||||
connect4=Connect 4
|
||||
credits=Crediti
|
||||
dark=Scuro
|
||||
deny=Nega
|
||||
developers=Sviluppatori
|
||||
disconnect=Disconnetti
|
||||
effects-volume=Volume degli effetti
|
||||
enter-the-server-ip=Inserisci l'IP del server
|
||||
enter-the-server-port=Inserisci la porta del server
|
||||
enter-your-name=Inserisci il tuo nome
|
||||
error=Errore
|
||||
exit=Esci
|
||||
forfeit=Abbandona
|
||||
fullscreen=Schermo intero
|
||||
game-over=Fine del gioco
|
||||
general=Generale
|
||||
high-contrast=Alto contrasto
|
||||
invalid-username=nome utente non valido
|
||||
ip-address=Indirizzo IP
|
||||
is-not-a-valid-ip-address=non \u00e8 un indirizzo IP valido
|
||||
is-not-a-valid-port=non \u00e8 una porta valida
|
||||
language=Lingua
|
||||
large=Grande
|
||||
layout-size=Dimensione layout
|
||||
light=Chiaro
|
||||
local=Locale
|
||||
localization=Localizzazione
|
||||
master-volume=Volume principale
|
||||
medium=Medio
|
||||
merge-commander=Merge Commander
|
||||
moral-support=Supporto morale
|
||||
music-volume=Volume della musica
|
||||
name=Nome
|
||||
never=No, non voglio mai vedere alcun tutorial.
|
||||
no=No
|
||||
ok=OK
|
||||
online=Online
|
||||
opengl=OpenGL
|
||||
options=Opzioni
|
||||
play=Gioca
|
||||
player-name=Nome del giocatore
|
||||
player=Giocatore
|
||||
please-enter-your-name=Per favore inserisci il tuo nome
|
||||
port=Porta
|
||||
product-owner=Proprietario del prodotto
|
||||
quit=Esci
|
||||
reversi=Reversi
|
||||
scrum-master=Scrum Master
|
||||
send=Invia
|
||||
server-information=Informazioni sul server
|
||||
small=Piccolo
|
||||
style=Stile
|
||||
the-game-ended-in-a-draw=La partita \u00e8 terminata in parit\u00e0
|
||||
theme=Tema
|
||||
tic-tac-toe=Tris
|
||||
tictactoe1 =Benvenuto nel gioco del Tris! Puoi fare la tua mossa cliccando su uno dei 9 quadrati della griglia. Esempio sopra:
|
||||
tictactoe2 =Un giocatore vince mettendo 3 simboli in fila ? orizzontalmente, verticalmente o diagonalmente. Nell?esempio sopra, il giocatore vince con una fila diagonale di tre simboli.
|
||||
to-a-game-of=a una partita di
|
||||
tutorial=Vuoi vedere un tutorial per questo gioco?
|
||||
volume=Volume
|
||||
windowed=Finestra
|
||||
yes=S\u00ec
|
||||
you-lost-against=Hai perso contro
|
||||
you-were-challenged-by=Sei stato sfidato da
|
||||
you-win=Hai vinto
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=Benvenuto nel gioco Connect 4! Puoi fare una mossa cliccando su una delle colonne. La mossa sar<61> posizionata nella riga pi<70> bassa di quella colonna che non <20> ancora piena.
|
||||
connect4.2=Puoi vincere ottenendo 4 pedine del tuo colore in orizzontale, diagonale o verticale! Guarda l'esempio sopra.
|
||||
reversi1=Benvenuto nel gioco Reversi! Puoi fare una mossa cliccando su uno dei punti leggermente trasparenti.
|
||||
reversi2=Cliccando su un punto, tutti i pezzi tra dove metti il punto e il prossimo punto trovato verranno girati. Guarda l'esempio sopra, dove il giallo indica i pezzi da girare.
|
||||
reversi3=Il tuo turno pu<70> essere saltato se non ci sono mosse legali. Questo permetter<65> al tuo avversario di giocare fino a quando non avrai un'opportunit<69> legale.
|
||||
reversi4=Il giocatore che alla fine del gioco ha pi<70> pezzi sulla scacchiera vince.
|
||||
tutorialstring=Tutorial
|
||||
|
||||
# Main Menu buttons
|
||||
mainMenuSelectTicTacToe=Tris
|
||||
mainMenuSelectReversi=Reversi
|
||||
mainMenuSelectSudoku=Sudoku
|
||||
mainMenuSelectBattleship=Battaglia navale
|
||||
mainMenuSelectOther=Altro
|
||||
mainMenuSelectCredits=Crediti
|
||||
mainMenuSelectOptions=Opzioni
|
||||
mainMenuSelectQuit=Esci
|
||||
|
||||
# Quit Menu text and buttons
|
||||
quitMenuTextSure=Sei sicuro?
|
||||
quitMenuButtonYes=S\u00EC
|
||||
quitMenuButtonNo=No
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabo)
|
||||
chinese=\u4e2d\u6587 (Cinese)
|
||||
dutch=Nederlands (Olandese)
|
||||
english=English (Inglese)
|
||||
french=Fran\u00e7ais (Francese)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgiano)
|
||||
german=Deutsch (Tedesco)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
|
||||
italian=Italiano
|
||||
japanese=\u65e5\u672c\u8a9e (Giapponese)
|
||||
korean=\ud55c\uad6d\uc5b4 (Coreano)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russo)
|
||||
spanish=Espa\u00f1ol (Spagnolo)
|
||||
@@ -0,0 +1,99 @@
|
||||
accept=\u627f\u8a8d
|
||||
ai=\u4eba\u5de5\u77e9\u7565
|
||||
app-title=ISY\u30b2\u30fc\u30e0\u30bb\u30ec\u30af\u30bf\u30fc
|
||||
are-you-sure=\u672c\u5f53\u306b\u3088\u308d\u3057\u3044\u3067\u3059\u304b\uff1f
|
||||
back=\u623b\u308b
|
||||
cancel=\u30ad\u30e3\u30f3\u30bb\u30eb
|
||||
challenge=\u6311\u6226
|
||||
computer-difficulty=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u306e\u96e3\u6613\u5ea6
|
||||
computer-think-time=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u306e\u601d\u8003\u6642\u9593
|
||||
computer=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf
|
||||
connect=\u63a5\u7d9a
|
||||
connect4=Connect 4
|
||||
credits=\u30af\u30ec\u30b8\u30c3\u30c8
|
||||
dark=\u30c0\u30fc\u30af
|
||||
deny=\u62d2\u5426
|
||||
developers=\u958b\u767a\u8005
|
||||
disconnect=\u5207\u65ad
|
||||
effects-volume=\u52b9\u679c\u97f3\u91cf
|
||||
enter-the-server-ip=\u30b5\u30fc\u30d0\u30fcIP\u3092\u5165\u529b
|
||||
enter-the-server-port=\u30b5\u30fc\u30d0\u30fc\u30dd\u30fc\u30c8\u3092\u5165\u529b
|
||||
enter-your-name=\u540d\u524d\u3092\u5165\u529b
|
||||
error=\u30a8\u30e9\u30fc
|
||||
exit=\u7d42\u4e86
|
||||
forfeit=\u8f9e\u9000
|
||||
fullscreen=\u30d5\u30eb\u30b9\u30af\u30ea\u30fc\u30f3
|
||||
game-over=\u30b2\u30fc\u30e0\u30aa\u30fc\u30d0\u30fc
|
||||
general=\u4e00\u822c
|
||||
high-contrast=\u9AD8\u30B3\u30F3\u30C8\u30E9\u30B9
|
||||
invalid-username=\u7121\u52b9\u306a\u30e6\u30fc\u30b6\u30fc\u540d
|
||||
ip-address=IP\u30a2\u30c9\u30ec\u30b9
|
||||
is-not-a-valid-ip-address=\u6709\u52b9\u306aIP\u30a2\u30c9\u30ec\u30b9\u3067\u306f\u3042\u308a\u307e\u305b\u3093
|
||||
is-not-a-valid-port=\u6709\u52b9\u306a\u30dd\u30fc\u30c8\u756a\u53f7\u3067\u306f\u3042\u308a\u307e\u305b\u3093
|
||||
language=\u8a00\u8a9e
|
||||
large=\u5927
|
||||
layout-size=\u30ec\u30a4\u30a2\u30a6\u30c8\u30b5\u30a4\u30ba
|
||||
light=\u30e9\u30a4\u30c8
|
||||
local=\u30ed\u30fc\u30ab\u30eb
|
||||
localization=\u30ed\u30fc\u30ab\u30e9\u30a4\u30bc\u30fc\u30b7\u30e7\u30f3
|
||||
master-volume=\u30de\u30b9\u30bf\u30fc\u30dc\u30ea\u30e5\u30fc\u30e0
|
||||
medium=\u4e2d
|
||||
merge-commander=\u30de\u30fc\u30b8\u30b3\u30de\u30f3\u30c0\u30fc
|
||||
moral-support=\u30e1\u30f3\u30bf\u30eb\u30b5\u30dd\u30fc\u30c8
|
||||
music-volume=\u97f3\u697d\u97f3\u91cf
|
||||
name=\u540d\u524d
|
||||
never=\u3044\u3044\u3048\u3001\u30c1\u30e5\u30fc\u30c8\u30ea\u30a2\u30eb\u306f\u4e8c\u5ea6\u3068\u898b\u305f\u304f\u3042\u308a\u307e\u305b\u3093\u3002
|
||||
no=\u3044\u3044\u3048
|
||||
ok=OK
|
||||
online=\u30aa\u30f3\u30e9\u30a4\u30f3
|
||||
opengl=OpenGL
|
||||
options=\u30aa\u30d7\u30b7\u30e7\u30f3
|
||||
play=\u30d7\u30ec\u30a4
|
||||
player-name=\u30d7\u30ec\u30a4\u30e4\u30fc\u540d
|
||||
player=\u30d7\u30ec\u30a4\u30e4\u30fc
|
||||
please-enter-your-name=\u540d\u524d\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044
|
||||
port=\u30dd\u30fc\u30c8
|
||||
product-owner=\u30d7\u30ed\u30c0\u30af\u30c8\u30aa\u30fc\u30ca\u30fc
|
||||
quit=\u7d42\u4e86
|
||||
reversi=\u30ea\u30d0\u30fc\u30b7
|
||||
scrum-master=\u30b9\u30af\u30e9\u30e0\u30de\u30b9\u30bf\u30fc
|
||||
send=\u9001\u4fe1
|
||||
server-information=\u30b5\u30fc\u30d0\u60c5\u5831
|
||||
small=\u5c0f
|
||||
style=\u30b9\u30bf\u30a4\u30eb
|
||||
the-game-ended-in-a-draw=\u30b2\u30fc\u30e0\u306f\u5f15\u304d\u5206\u3051\u306b\u7d42\u308f\u308a\u307e\u3057\u305f
|
||||
theme=\u30c6\u30fc\u30de
|
||||
tic-tac-toe=\u4e09\u76ee\u4e26\u3079
|
||||
tictactoe1 =\u4e09\u76ee\u4e26\u3079\u306e\u30b2\u30fc\u30e0\u3078\u3088\u3046\u3053\u305d\uff01\u30dc\u30fc\u30c9\u4e0a\u306e9\u3064\u306e\u30de\u30b9\u306e\u3044\u305a\u308c\u304b\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u624b\u3092\u6253\u3061\u307e\u3057\u3087\u3046\u3002\u4e0a\u306e\u4f8b\u3092\u53c2\u7167\uff1a
|
||||
tictactoe2 =\u30d7\u30ec\u30a4\u30e4\u30fc\u306f\u3001\u6a2a\u30fb\u7e26\u30fb\u65b9\u5411\u306e\u3044\u305a\u308c\u304b\u3067\u30de\u30fc\u30af\u30923\u3064\u4e26\u3079\u308b\u3068\u52dd\u3061\u3067\u3059\u3002\u4e0a\u306e\u4f8b\u3067\u306f\u3001\u30d7\u30ec\u30a4\u30e4\u30fc\u304c\u659c\u3081\u306b3\u3064\u4e26\u3079\u3066\u52dd\u3063\u3066\u3044\u307e\u3059\u3002
|
||||
to-a-game-of=\u30b2\u30fc\u30e0\u306b
|
||||
tutorial=\u3053\u306e\u30b2\u30fc\u30e0\u306e\u30c1\u30e5\u30fc\u30c8\u30ea\u30a2\u30eb\u3092\u898b\u305f\u3044\u3067\u3059\u304b\uff1f
|
||||
volume=\u97f3\u91cf
|
||||
windowed=\u30a6\u30a3\u30f3\u30c9\u30a6\u8868\u793a
|
||||
yes=\u306f\u3044
|
||||
you-lost-against=\u3042\u306a\u305f\u306f ... \u306b\u6557\u308c\u307e\u3057\u305f
|
||||
you-were-challenged-by=\u3042\u306a\u305f\u306f ... \u304b\u3089\u6311\u6226\u3055\u308c\u307e\u3057\u305f
|
||||
you-win=\u52dd\u5229\u3067\u3059
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=\u30b3\u30cd\u30af\u30c84\u306e\u30b2\u30fc\u30e0\u3078\u3088\u3046\u3053\u305d! \u30ab\u30e9\u30e0\u306e\u4e0a\u306e\u30ab\u30e9\u30e0\u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u52d5\u304b\u3057\u3092\u884c\u3048\u307e\u3059\u3002\u52d5\u304b\u3057\u306f\u3001\u3060\u307e\u308a\u306f\u307e\u3067\u5869\u3067\u306a\u3044\u884c\u306b\u8a2d\u7f6e\u3055\u308c\u307e\u3059\u3002
|
||||
connect4.2=\u6a2a\u7dda\u3001\u65b9\u5411\u306e\u307f\u3082\u306a\u3057\u3067\u30014\u3064\u306e\u8ca0\u3051\u3092\u7d50\u5408\u3055\u305b\u308b\u3068\u52dd\u3061\u307e\u3059! \u4e0a\u306e\u4f8b\u3092\u898b\u3066\u304f\u3060\u3055\u3044\u3002
|
||||
reversi1=\u30ea\u30d0\u30fc\u30b7\u30fb\u30b2\u30fc\u30e0\u3078\u3088\u3046\u3053\u305d! \u30ab\u30e9\u30e0\u306e\u30b9\u30dd\u30c3\u30c8\u30c9\u30c3\u30c8\u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u52d5\u304b\u3057\u306e\u30d7\u30ec\u30a4\u304c\u3067\u304d\u307e\u3059\u3002
|
||||
reversi2=\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u3001\u3064\u306a\u304c\u308a\u3092\u542b\u3081\u305f\u8ca0\u3051\u304c\u307e\u3067\u306e\u8ca0\u3051\u304c\u5909\u308f\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002
|
||||
reversi3=\u6b21\u306e\u52d5\u304b\u3057\u304c\u306a\u3044\u5834\u5408\u3001\u8a8d\u5b9a\u3055\u308c\u305f\u52d5\u304b\u3057\u306e\u6642\u9593\u306f\u62d2\u7d76\u3055\u308c\u308b\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002
|
||||
reversi4=\u672c\u6b21\u306b\u30dc\u30fc\u30c9\u4e0a\u3067\u6700\u591a\u306e\u8ca0\u3051\u3092\u6301\u3064\u30d7\u30ec\u30a4\u30e4\u30fc\u304c\u52dd\u3061\u307e\u3059\u3002
|
||||
tutorialstring=\u30c1\u30e5\u30fc\u30c8\u30ea\u30a2\u30eb
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u30a2\u30e9\u30d3\u30a2\u8a9e)
|
||||
chinese=\u4e2d\u6587 (\u4e2d\u6587)
|
||||
dutch=Nederlands (\u30aa\u30e9\u30f3\u30c0\u8a9e)
|
||||
english=English (\u82f1\u8a9e)
|
||||
french=Fran\u00e7ais (\u30d5\u30e9\u30f3\u30b9\u8a9e)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u30b0\u30eb\u30b8\u30a2\u8a9e)
|
||||
german=Deutsch (\u30c9\u30a4\u30c4\u8a9e)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\u30d2\u30f3\u30c7\u30a3\u8a9e)
|
||||
italian=Italiano (\u30a4\u30bf\u30ea\u30a2\u8a9e)
|
||||
japanese=\u65e5\u672c\u8a9e
|
||||
korean=\ud55c\uad6d\uc5b4 (\u97d3\u56fd\u8a9e)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\u30ed\u30b7\u30a2\u8a9e)
|
||||
spanish=Espa\u00f1ol (\u30b9\u30da\u30a4\u30f3\u8a9e)
|
||||
@@ -0,0 +1,99 @@
|
||||
accept=\uC218\uB77D
|
||||
ai=\uC778\uACF5 \uC9C0\uB2A5
|
||||
app-title=ISY \uAC8C\uC784 \uC120\uD0DD\uAE30
|
||||
are-you-sure=\uC815\uB9D0\uB85C \uD655\uC2E4\uD569\uB2C8\uAE4C?
|
||||
back=\uB4A4\uB85C
|
||||
cancel=\uCDE8\uC18C
|
||||
challenge=\uCC38\uC5EC
|
||||
computer-difficulty=\uCEF4\uD4E8\uD130 \uC5B4\uB9AC\uAE30
|
||||
computer-think-time=\uCEF4\uD4E8\uD130 \uC0DD\uAC01 \uC2DC\uAC04
|
||||
computer=\uCEF4\uD4E8\uD130
|
||||
connect=\uC5F0\uACB0
|
||||
connect4=Connect 4
|
||||
credits=\uD06C\uB808\uB527
|
||||
dark=\uC5B4\uB460
|
||||
deny=\uAC70\uBD80
|
||||
developers=\uAC1C\uBC1C\uC790
|
||||
disconnect=\uC5F0\uACB0 \uC624\uD508
|
||||
effects-volume=\uD6A8\uACFC\uC74C \uBCFC\uB968
|
||||
enter-the-server-ip=\uC11C\uBC84 IP\uB97C \uC785\uB825\uD558\uC138\uC694
|
||||
enter-the-server-port=\uC11C\uBC84 \uD3EC\uD2B8\uB97C \uC785\uB825\uD558\uC138\uC694
|
||||
enter-your-name=\uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694
|
||||
error=\uC624\uB958
|
||||
exit=\uB098\uAC00\uAE30
|
||||
forfeit=\uAE30\uAD6C
|
||||
fullscreen=\uC804\uCCB4 \uD654\uBA74
|
||||
game-over=\uAC8C\uC784 \uC885\uB8CC
|
||||
general=\uC77C\uBC18
|
||||
high-contrast=\uACE0\uB3C4 \uB2E8\uC5B4
|
||||
invalid-username=\uBB34\uD6A8\uD55C \uC0AC\uC6A9\uC790 \uC774\uB984
|
||||
ip-address=IP \uC8FC\uC18C
|
||||
is-not-a-valid-ip-address=\uC62C\uBC14\uB978 IP \uC8FC\uC18C\uAC00 \uC544\uB2D9\uB2C8\uB2E4
|
||||
is-not-a-valid-port=\uC62C\uBC14\uB978 \uD3EC\uD2B8\uAC00 \uC544\uB2D9\uB2C8\uB2E4
|
||||
language=\uC5B8\uC5B4
|
||||
large=\uD070
|
||||
layout-size=\uB77C\uC774\uC6C3 \uD06C\uAE30
|
||||
light=\uBCF4\uD1B5
|
||||
local=\uB85C\uCEEC
|
||||
localization=\uB85C\uCEEC\uB9AC\uC870
|
||||
master-volume=\uBAA8\uB4E0 \uBCFC\uB968
|
||||
medium=\uBCF4\uD1B5
|
||||
merge-commander=\uBA54\uC9C0 \uCEE8\uBA38\uB2C8
|
||||
moral-support=\uC815\uC2E0\uC801 \uC9C0\uC6D0
|
||||
music-volume=\uC74C\uC545 \uBCFC\uB968
|
||||
name=\uC774\uB984
|
||||
no=\uC544\uB2C8\uC624
|
||||
never=\uc544\ub2c8\uc694, \uc800\ub294 \ud29c\ud1a0\ub9ac\uc5bc\uc744 \ub2e4\uc2dc\ub294 \ubcf4\uace0 \uc2f6\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
|
||||
ok=\uD655\uC778
|
||||
online=\uC628\uB77C\uC778
|
||||
opengl=OpenGL
|
||||
options=\uC635\uC158
|
||||
play=\uC7AC\uC0DD
|
||||
player-name=\uD50C\uB808\uC774\uC5B4 \uC774\uB984
|
||||
player=\uD50C\uB808\uC774\uC5B4
|
||||
please-enter-your-name=\uC774\uB984\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694
|
||||
port=\uD3EC\uD2B8
|
||||
product-owner=\uD504\uB85C\uB354\uD2B8 \uC624\uB108
|
||||
quit=\uC885\uB8CC
|
||||
reversi=\uB9AC\uBC84\uC2DC
|
||||
scrum-master=\uC2A4\uD06C\uB7FC \uB9C8\uC2A4\uD130
|
||||
send=\uBCF4\uB0B4\uAE30
|
||||
server-information=\uC11C\uBC84 \uC815\uBCF4
|
||||
small=\uC791\uC740
|
||||
style=\uC2A4\uD0C0\uC77C
|
||||
the-game-ended-in-a-draw=\uAC8C\uC784\uC774 \uBB34\uC2B9\uBD80\uB85C \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4
|
||||
theme=\uC8FC\uC81C
|
||||
tic-tac-toe=\uD2F0\uD06C\uD0D1\uD1A0
|
||||
tictactoe1 =\ud2f1\ud0dd\ud1a0 \uac8c\uc784\uc5d0 \uc624\uc2e0 \uac83\uc744 \ud658\uc601\ud569\ub2c8\ub2e4! \ubcf4\ub4dc\uc758 9\uac1c \uce78 \uc911 \ud558\ub098\ub97c \ud074\ub9ad\ud558\uc5ec \uc6c0\uc9c1\uc77c \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc704\uc758 \uc608\uc2dc\ub97c \ucc38\uace0\ud558\uc138\uc694:
|
||||
tictactoe2 =\ud50c\ub808\uc774\uc5b4\ub294 \uac00\ub85c, \uc138\ub85c \ub610\ub294 \ub300\uac01\uc120\uc73c\ub85c \ub9d0 3\uac1c\ub97c \uc77c\ub82c\ub85c \ub193\uc73c\uba74 \uc2b9\ub9ac\ud569\ub2c8\ub2e4. \uc704\uc758 \uc608\uc5d0\uc11c \ud50c\ub808\uc774\uc5b4\ub294 \ub300\uac01\uc120\uc73c\ub85c \uc138 \uac1c\ub97c \uc5f0\uacb0\ud558\uc5ec \uc774\uacbc\uc2b5\ub2c8\ub2e4.
|
||||
to-a-game-of=... \uAC8C\uC784\uC5D0
|
||||
tutorial=\uc774 \uac8c\uc784\uc758 \ud29c\ud1a0\ub9ac\uc5bc\uc744 \ubcf4\uace0 \uc2f6\ub098\uc694?
|
||||
volume=\uBCFC\uB968
|
||||
windowed=\uCC3D \uBAA9\uB85D
|
||||
yes=\uB124
|
||||
you-lost-against=... \uC5D0\uAC8C \uC9C0\uC600\uC2B5\uB2C8\uB2E4
|
||||
you-were-challenged-by=... \uB85C\uBD80\uD130 \uCC38\uC5EC \uC694\uCCAD\uC744 \uBC1B\uC558\uC2B5\uB2C8\uB2E4
|
||||
you-win=\uC774\uACBC\uC2B5\uB2C8\uB2E4
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=Connect 4 \uacbd\uc6b0\uc5d0 \uc81c\uc2dc\ud569\ub2c8\ub2e4! \ud648\ub825\uc744 \ub2e4\ub978 \uc0c1\uc704\ub85c \ud074\ub9ad\ud558\uc2dc\uba70 \ub2e4\uc74c \uc815\uc758 \ud648\ub825\uc744 \ub610\ub294 \uc704\ub85c \uc0ac\uc6a9\ud558\uc2dc\uba70 \ud648\ub825\uc744 \uc124\uc815\ud569\ub2c8\ub2e4.
|
||||
connect4.2=\uc0ac\uc6a9\uc790\uc758 \ud648\uc744 \uc54c\ub824 \ud574\uc8fc\uba70 \ud574\ub2f9 \ud648\uc758 4\uae38\uc744 \ud574\uc8fc\uba70 \ud655\uc9c0, \ub354\ub7ec \ubc29\uacfc \ub610\ub294 \uc0ac\uc6a9\uc790 \ud648\uc758 \uc5f4\ub9b0 \ucd5c\ub300 \ubc29\ud574\uc5d0 \uc5c6\uc74c\uc774\ub2e4!
|
||||
reversi1=Reversi \uacbd\uc6b0\uc5d0 \uc81c\uc2dc\ud569\ub2c8\ub2e4! \ub2e4\ub978 \ud615\uc2dd\uc758 \ud648\uc744 \ud074\ub9ad\ud558\uc2dc\uba70 \ub2e4\uc74c \uc815\uc758 \ud648\uc744 \uc124\uc815\ud569\ub2c8\ub2e4.
|
||||
reversi2=\ud074\ub9ad \ud558\uba70, \ub2e4\ub978 \ud648 \uc704\ub85c \ucd5c\uc2e0 \ubc1b\ub294 \ud648\uc5d0 \ub300\ud574 \ub2e4\uc774\ubc84\ub77c\uc758 \ud648\uc744 \ubcc0\uacbd\ud569\ub2c8\ub2e4.
|
||||
reversi3=\uc0ac\uc6a9\uc790\uc758 \ud648\uc744 \ud074 \uc218 \uc5c6\uc2b5\uc2b5\ub2c8\ub2e4. \uc0ac\uc6a9\uc790 \ub2f5\uc5d0 \ub300\ud574 \uc811\ub2c8\ub2e4.
|
||||
reversi4=\uacbd\uc6b0 \uc5d0\uc11c \ucd5c\ub300 \ud648\uc744 \uac00\uc838\ub294 \uc0ac\uc6a9\uc790\uc774 \uc52c\uc544\uc624\uba70 \uc0ac\uc6a9\uc790\uc758 \ud648\uc744 \uc54c\ub824\ud569\ub2c8\ub2e4.
|
||||
tutorialstring=\ud14c\ud2b8\ub9ad
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0639\u0631\u0628\u064a\u0629)
|
||||
chinese=\u4e2d\u6587 (\u4e2d\u6587)
|
||||
dutch=Nederlands (\ub3c4\ucc99)
|
||||
english=English (\uc601\uad6d\uc5b4)
|
||||
french=Fran\u00e7ais (\ud504\ub791\uc81c\uc2a4\ucf54)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\uac8c\uc774\uc874)
|
||||
german=Deutsch (\ub3c4\ucf54)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\ud567\ub9ac)
|
||||
italian=Italiano (\uc774\ud0c0\ub9ac\uc5b4\ub098)
|
||||
japanese=\u65e5\u672c\u8a9e (\uc65c\uc790\ub9ac\uc5b4)
|
||||
korean=\ud55c\uad6d\uc5b4
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\ub85c\uc6b0\uc2a4\uc544\uc774\ucf58)
|
||||
spanish=Espa\u00f1ol (\uc2a4\ud398\ub974\uc2a4\uc544\uc774\ucf58)
|
||||
@@ -1,17 +1,99 @@
|
||||
# Window title
|
||||
windowTitle=ISY Spellen Kiezer
|
||||
accept=Accepteren
|
||||
ai=Kunstmatige Intelligentie
|
||||
app-title=ISY Spel Kiezer
|
||||
are-you-sure=Weet je het zeker?
|
||||
back=Terug
|
||||
cancel=Annuleren
|
||||
challenge=Uitdaging
|
||||
computer-difficulty=Computermoeilijkheid
|
||||
computer-think-time=Denktijd computer
|
||||
computer=Computer
|
||||
connect=Verbinden
|
||||
credits=Credits
|
||||
dark=Donker
|
||||
deny=Weigeren
|
||||
developers=Ontwikkelaars
|
||||
disconnect=Verbreken
|
||||
effects-volume=Effectvolume
|
||||
enter-the-server-ip=Voer het server-IP in
|
||||
enter-the-server-port=Voer de serverpoort in
|
||||
enter-your-name=Voer je naam in
|
||||
error=Fout
|
||||
exit=Afsluiten
|
||||
forfeit=Opgeven
|
||||
fullscreen=Volledig scherm
|
||||
game-over=Spel afgelopen
|
||||
general=Algemeen
|
||||
high-contrast=Hoog contrast
|
||||
invalid-username=ongeldige gebruikersnaam
|
||||
ip-address=IP-adres
|
||||
is-not-a-valid-ip-address=is geen geldig IP-adres
|
||||
is-not-a-valid-port=is geen geldige poort
|
||||
language=Taal
|
||||
large=Groot
|
||||
layout-size=Lay-outgrootte
|
||||
light=Licht
|
||||
local=Lokaal
|
||||
localization=Lokalisatie
|
||||
master-volume=Hoofdvolume
|
||||
medium=Middelgroot
|
||||
merge-commander=Merge Commander
|
||||
moral-support=Morele steun
|
||||
music-volume=Muziekvolume
|
||||
name=Naam
|
||||
never=Nee, ik wil nooit tutorials zien.
|
||||
no=Nee
|
||||
ok=Ok<EFBFBD>
|
||||
online=Online
|
||||
opengl=OpenGL
|
||||
options=Opties
|
||||
play=Spelen
|
||||
player-name=Spelersnaam
|
||||
player=Speler
|
||||
please-enter-your-name=Voer alstublieft je naam in
|
||||
port=Poort
|
||||
product-owner=Producteigenaar
|
||||
quit=Stoppen
|
||||
reversi=Reversi
|
||||
scrum-master=Scrum Master
|
||||
send=Verzenden
|
||||
server-information=Serverinformatie
|
||||
small=Klein
|
||||
style=Stijl
|
||||
the-game-ended-in-a-draw=Het spel eindigde in een gelijkspel
|
||||
theme=Thema
|
||||
tic-tac-toe=Boter Kaas en Eieren
|
||||
tictactoe1 =Welkom bij het spel Boter, Kaas en Eieren! Je kunt je zet doen door op een van de 9 vakjes op het bord te klikken. Voorbeeld hierboven:
|
||||
tictactoe2 =Een speler wint door 3 stukken op een rij te krijgen ? horizontaal, verticaal of diagonaal. In het voorbeeld hierboven wint de speler met een diagonale rij van drie stukken.
|
||||
connect4=Vier op een rij
|
||||
to-a-game-of=voor een spelletje
|
||||
tutorial=Wil je een tutorial voor dit spel zien?
|
||||
volume=Volume
|
||||
windowed=Venstermodus
|
||||
yes=Ja
|
||||
you-lost-against=Je hebt verloren van
|
||||
you-were-challenged-by=Je bent uitgedaagd door
|
||||
you-win=Je wint
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=Welkom bij het spel Connect 4! Je kunt een zet doen door op een van de kolommen te klikken. De zet wordt geplaatst in de laagste nog lege rij van die kolom.
|
||||
connect4.2=Je kunt winnen door 4 van je stukken horizontaal, diagonaal of verticaal op een rij te krijgen! Zie het voorbeeld hierboven.
|
||||
reversi1=Welkom bij het spel Reversi! Je kunt een zet doen door op een van de licht transparante stippen te klikken.
|
||||
reversi2=Door op een stip te klikken draai je alle stukken om tussen de plaats waar je de stip zet en de volgende stip die wordt gevonden. Zie het voorbeeld hierboven, waar geel de stukken zijn die omgedraaid worden.
|
||||
reversi3=Je beurt kan worden overgeslagen als er geen legale zet is. Hierdoor kan je tegenstander doorgaan tot jij een legale zet kunt doen.
|
||||
reversi4=De speler die aan het einde van het spel de meeste stukken op het bord heeft, wint.
|
||||
tutorialstring=Tutorial
|
||||
|
||||
# Main Menu buttons
|
||||
mainMenuSelectTicTacToe=Boter Kaas En Eieren
|
||||
mainMenuSelectReversi=Reversi
|
||||
mainMenuSelectSudoku=Sudoku
|
||||
mainMenuSelectBattleship=Zeeslag
|
||||
mainMenuSelectOther=Anders
|
||||
mainMenuSelectCredits=Credits
|
||||
mainMenuSelectOptions=Opties
|
||||
mainMenuSelectQuit=Afsluiten
|
||||
|
||||
# Quit Menu text and buttons
|
||||
quitMenuTextSure=Weet je het zeker?
|
||||
quitMenuButtonYes=Ja
|
||||
quitMenuButtonNo=Nee
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabisch)
|
||||
chinese=\u4e2d\u6587 (Chinees)
|
||||
dutch=Nederlands
|
||||
english=English (Engels)
|
||||
french=Fran\u00e7ais (Frans)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgisch)
|
||||
german=Deutsch (Duits)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
|
||||
italian=Italiano (Italiaans)
|
||||
japanese=\u65e5\u672c\u8a9e (Japans)
|
||||
korean=\ud55c\uad6d\uc5b4 (Koreaans)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russisch)
|
||||
spanish=Espa\u00f1ol (Spaans)
|
||||
@@ -0,0 +1,99 @@
|
||||
accept=\u041f\u0440\u0438\u043d\u044f\u0442\u044c
|
||||
ai=\u0418\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442
|
||||
app-title=ISY \u0412\u044b\u0431\u043e\u0440 \u0438\u0433\u0440
|
||||
are-you-sure=\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b?
|
||||
back=\u041d\u0430\u0437\u0430\u0434
|
||||
cancel=\u041e\u0442\u043c\u0435\u043d\u0430
|
||||
challenge=\u0412\u044b\u0437\u043e\u0432
|
||||
connect4=Connect 4
|
||||
computer-difficulty=\u0421\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430
|
||||
computer-think-time=\u0412\u0440\u0435\u043c\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430
|
||||
computer=\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440
|
||||
connect=\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f
|
||||
credits=\u041a\u0440\u0435\u0434\u0438\u0442\u044b
|
||||
dark=\u0422\u0451\u043c\u043d\u044b\u0439
|
||||
deny=\u041e\u0442\u043a\u0430\u0437\u0430\u0442\u044c
|
||||
developers=\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438
|
||||
disconnect=\u041e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f
|
||||
effects-volume=\u0413\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432
|
||||
enter-the-server-ip=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 IP \u0441\u0435\u0440\u0432\u0435\u0440\u0430
|
||||
enter-the-server-port=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u043e\u0440\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430
|
||||
enter-your-name=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0435 \u0438\u043c\u044f
|
||||
error=\u041e\u0448\u0438\u0431\u043a\u0430
|
||||
exit=\u0412\u044b\u0445\u043e\u0434
|
||||
forfeit=\u0421\u0434\u0430\u0442\u044c \u0441\u043e\u0440\u043e\u0432\u043d\u043e\u0441\u0442\u0438
|
||||
fullscreen=\u041f\u043e\u043b\u043d\u043e\u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c
|
||||
game-over=\u0418\u0433\u0440\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u0430
|
||||
general=\u041e\u0431\u0449\u0438\u0435
|
||||
high-contrast=\u0412\u044B\u0441\u043E\u043A\u0430\u044F \u043A\u043E\u043D\u0442\u0440\u0430\u0441\u0442\u043D\u043E\u0441\u0442\u044C
|
||||
invalid-username=\u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e\u0435 \u0438\u043c\u044f
|
||||
ip-address=IP \u0430\u0434\u0440\u0435\u0441
|
||||
is-not-a-valid-ip-address=\u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c IP \u0430\u0434\u0440\u0435\u0441\u043e\u043c
|
||||
is-not-a-valid-port=\u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u043e\u0440\u0442\u043e\u043c
|
||||
language=\u042f\u0437\u044b\u043a
|
||||
large=\u0411\u043e\u043b\u044c\u0448\u043e\u0439
|
||||
layout-size=\u0420\u0430\u0437\u043c\u0435\u0440 \u043c\u043e\u043d\u0442\u0430\u0436\u0430
|
||||
light=\u0421\u0432\u0435\u0442\u043b\u044b\u0439
|
||||
local=\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439
|
||||
localization=\u041b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f
|
||||
master-volume=\u041e\u0431\u0449\u0438\u0439 \u0433\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c
|
||||
medium=\u0421\u0440\u0435\u0434\u043d\u0438\u0439
|
||||
merge-commander=Merge Commander
|
||||
moral-support=\u041c\u043e\u0440\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430
|
||||
music-volume=\u0413\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c \u043c\u0443\u0437\u044b\u043a\u0438
|
||||
name=\u0418\u043c\u044f
|
||||
never=\u041d\u0435\u0442, \u044f \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0445\u043e\u0447\u0443 \u0432\u0438\u0434\u0435\u0442\u044c \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0438.
|
||||
no=\u041d\u0435\u0442
|
||||
ok=OK
|
||||
online=\u0412 \u0441\u0435\u0442\u0438
|
||||
opengl=OpenGL
|
||||
options=\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
|
||||
play=\u0418\u0433\u0440\u0430\u0442\u044c
|
||||
player-name=\u0418\u043c\u044f \u0438\u0433\u0440\u043e\u043a\u0430
|
||||
player=\u0418\u0433\u0440\u043e\u043a
|
||||
please-enter-your-name=\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0435 \u0438\u043c\u044f
|
||||
port=\u041f\u043e\u0440\u0442
|
||||
product-owner=\u0412\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430
|
||||
quit=\u0412\u044b\u0445\u043e\u0434
|
||||
reversi=\u0420\u0435\u0432\u0435\u0440\u0441\u0438
|
||||
scrum-master=Scrum Master
|
||||
send=\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c
|
||||
server-information=\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0435
|
||||
small=\u041c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439
|
||||
style=\u0421\u0442\u0438\u043b\u044c
|
||||
the-game-ended-in-a-draw=\u0418\u0433\u0440\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430\u0441\u044c \u043d\u0438\u0447\u044c\u0435\u0439
|
||||
theme=\u0422\u0435\u043c\u0430
|
||||
tic-tac-toe=\u041a\u0440\u0435\u0441\u0442\u0438\u043a\u043e
|
||||
tictactoe1 =\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u0438\u0433\u0440\u0443 \u041a\u0440\u0435\u0441\u0442\u0438\u043a\u0438-\u043d\u043e\u043b\u0438\u043a\u0438! \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u043e\u0434, \u043d\u0430\u0436\u0430\u0432 \u043d\u0430 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 9 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u043e\u0432 \u043d\u0430 \u043f\u043e\u043b\u0435. \u041f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0448\u0435:
|
||||
tictactoe2 =\u0418\u0433\u0440\u043e\u043a \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442, \u0435\u0441\u043b\u0438 \u0441\u0442\u0430\u0432\u0438\u0442 3 \u0441\u0438\u043c\u0432\u043e\u043b\u0430 \u043f\u043e\u0434\u0440\u044f\u0434 ? \u043f\u043e \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u0438, \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438 \u0438\u043b\u0438 \u0434\u0438\u0430\u0433\u043e\u043d\u0430\u043b\u0438. \u0412 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u043e\u043c \u0432\u044b\u0448\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0433\u0440\u043e\u043a \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442 \u043f\u043e \u0434\u0438\u0430\u0433\u043e\u043d\u0430\u043b\u0438
|
||||
to-a-game-of=\u043a \u0438\u0433\u0440\u0435 \u0432
|
||||
tutorial=\u0425\u043e\u0447\u0435\u0448\u044c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0443\u0447\u0435\u0431\u043d\u0438\u043a \u043f\u043e \u044d\u0442\u043e\u0439 \u0438\u0433\u0440\u0435?
|
||||
volume=\u0413\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c
|
||||
windowed=\u041e\u043a\u043d\u043e
|
||||
yes=\u0414\u0430
|
||||
you-lost-against=\u0412\u044b \u043f\u0440\u043e\u0438\u0433\u0440\u0430\u043b\u0438 \u043a\u043e\u043c\u0443
|
||||
you-were-challenged-by=\u0412\u0430\u0441 \u0432\u044b\u0437\u0432\u0430\u043b \u043d\u0430 \u0441\u043e\u0440\u0435\u0432\u043d\u0438\u043a
|
||||
you-win=\u0412\u044b \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442\u0435
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u0438\u0433\u0440\u0443 Connect 4! \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u043e\u0434, \u043a\u043b\u0438\u043a\u043d\u0443\u044f \u043f\u043e \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432. \u0425\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d \u0432 \u043d\u0438\u0436\u0430\u0439 \u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432 \u044d\u0442\u043e\u0439 \u043a\u043e\u043b\u043e\u043d\u043a\u0435.
|
||||
connect4.2=\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u0438\u0433\u0440\u0430\u0442\u044c, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0432 4 \u0444\u0438\u0448\u043a\u0438 \u0432\u0430\u0448\u0435\u0433\u043e \u0446\u0432\u0435\u0442\u0430 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e, \u0434\u0438\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u0438\u043b\u0438 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e!
|
||||
reversi1=\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u0438\u0433\u0440\u0443 Reversi! \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u043e\u0434, \u043a\u043b\u0438\u043a\u043d\u0443\u044f \u043f043 \u043f043 \u043d043 \u043e043 \u043d043 \u043e043 \u043a043 \u0430043 \u043a043 \u0430043.
|
||||
reversi2=\u041d043 \u043d043 \u0430043 \u043a043 \u0430043 \u043a043 \u043e043 \u043c043 \u0435043 \u0436043 \u0435043 \u0434043 \u0435043 \u043d043 \u0430043.
|
||||
reversi3=\u0412043 \u0430043 \u0436043 \u0434043 \u0430043 \u043d043 \u0438043 \u043d043 \u0435043 \u0435043 \u0432043 \u0430043.
|
||||
reversi4=\u0418043 \u0433043 \u0440043 \u043e043 \u043a043 \u043e043 \u0442043 \u043e043 \u0442043 \u043e043 \u0435043 \u0435043 \u0430043 \u0435043 \u043d043 \u0438043 \u0435043 \u0435043 \u043c043 \u0430043.
|
||||
tutorialstring=\u0423\u0447\u0435\u0431\u043d\u0438\u043a
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0410\u0440\u0430\u0431\u0441\u043a\u0438\u0439)
|
||||
chinese=\u4e2d\u6587 (\u041a\u0438\u0442\u0430\u0439\u0441\u043a\u0438\u0439)
|
||||
dutch=Nederlands (\u041d\u0438\u0434\u0435\u0440\u043b\u0430\u043d\u0434\u0441\u043a\u0438\u0439)
|
||||
english=English (\u0410\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439)
|
||||
french=Fran\u00e7ais (\u0424\u0440\u0430\u043d\u0446\u0443\u0437\u0441\u043a\u0438\u0439)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u0413\u0440\u0443\u0437\u0438\u043d\u0441\u043a\u0438\u0439)
|
||||
german=Deutsch (\u041d\u0435\u043c\u0435\u0446\u043a\u0438\u0439)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\u0425\u0438\u043d\u0434\u0438)
|
||||
italian=Italiano (\u0418\u0442\u0430\u043b\u044c\u044f\u043d\u0441\u043a\u0438\u0439)
|
||||
japanese=\u65e5\u672c\u8a9e (\u042f\u043f\u043e\u043d\u0441\u043a\u0438\u0439)
|
||||
korean=\ud55c\uad6d\uc5b4 (\u041a\u043e\u0440\u0435\u0439\u0441\u043a\u0438\u0439)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439
|
||||
spanish=Espa\u00f1ol (\u0418\u0441\u043f\u0430\u043d\u0441\u043a\u0438\u0439)
|
||||
@@ -1,30 +1,99 @@
|
||||
# suppress inspection "LossyEncoding" for whole file
|
||||
# Window title
|
||||
windowTitle=ISY \u6E38\u620F\u9009\u62E9\u5668
|
||||
# ?????
|
||||
accept=\u63a5\u53d7
|
||||
ai=\u4eba\u5de5\u667a\u80fd
|
||||
app-title=ISY \u6e38\u620f\u9009\u62e9\u5668
|
||||
are-you-sure=\u60a8\u786e\u5b9a\u5417\uff1f
|
||||
back=\u8fd4\u56de
|
||||
cancel=\u53d6\u6d88
|
||||
challenge=\u6311\u6218
|
||||
computer-difficulty=\u8ba1\u7b97\u673a\u96be\u5ea6
|
||||
computer-think-time=\u8ba1\u7b97\u673a\u601d\u8003\u65f6\u95f4
|
||||
computer=\u8ba1\u7b97\u673a
|
||||
connect=\u8fde\u63a5
|
||||
connect4=Connect 4
|
||||
credits=\u81f4\u8c22
|
||||
dark=\u6697\u8272
|
||||
deny=\u62d2\u7edd
|
||||
developers=\u5f00\u53d1\u8005
|
||||
disconnect=\u65ad\u5f00\u8fde\u63a5
|
||||
effects-volume=\u6548\u679c\u97f3\u91cf
|
||||
enter-the-server-ip=\u8f93\u5165\u670d\u52a1\u5668 IP
|
||||
enter-the-server-port=\u8f93\u5165\u670d\u52a1\u5668\u7aef\u53e3
|
||||
enter-your-name=\u8f93\u5165\u60a8\u7684\u540d\u5b57
|
||||
error=\u9519\u8bef
|
||||
exit=\u9000\u51fa
|
||||
forfeit=\u68c0\u8f93
|
||||
fullscreen=\u5168\u5c4f
|
||||
game-over=\u6e38\u620f\u7ed3\u675f
|
||||
general=\u901a\u7528
|
||||
high-contrast=\u9AD8\u5BF9\u6BD4\u5EA6
|
||||
invalid-username=\u7528\u6237\u540d\u65e0\u6548
|
||||
ip-address=IP \u5730\u5740
|
||||
is-not-a-valid-ip-address=\u4e0d\u662f\u6709\u6548\u7684 IP \u5730\u5740
|
||||
is-not-a-valid-port=\u4e0d\u662f\u6709\u6548\u7684\u7aef\u53e3
|
||||
language=\u8bed\u8a00
|
||||
large=\u5927
|
||||
layout-size=\u5e03\u5c40\u5927\u5c0f
|
||||
light=\u4eae\u8272
|
||||
local=\u672c\u5730
|
||||
localization=\u672c\u5730\u5316
|
||||
master-volume=\u603b\u97f3\u91cf
|
||||
medium=\u4e2d
|
||||
merge-commander=\u5408\u5e76\u6307\u6325
|
||||
moral-support=\u7cbe\u795e\u652f\u6301
|
||||
music-volume=\u97f3\u4e50\u97f3\u91cf
|
||||
name=\u540d\u5b57
|
||||
never=\u4e0d\uff0c\u6211\u5b8c\u5168\u4e0d\u60f3\u518d\u770b\u5230\u4efb\u4f55\u6559\u7a0b\u3002
|
||||
no=\u4e0d
|
||||
ok=\u786e\u5b9a
|
||||
online=\u5728\u7ebf
|
||||
opengl=OpenGL
|
||||
options=\u9009\u9879
|
||||
play=\u6e38\u73a9
|
||||
player-name=\u73a9\u5bb6\u540d
|
||||
player=\u73a9\u5bb6
|
||||
please-enter-your-name=\u8bf7\u8f93\u5165\u60a8\u7684\u540d\u5b57
|
||||
port=\u7aef\u53e3
|
||||
product-owner=\u4ea7\u54c1\u62e5\u6709\u8005
|
||||
quit=\u9000\u51fa
|
||||
reversi=\u9ed1\u767d\u68cb
|
||||
scrum-master=\u9879\u76ee\u7ecf\u7406
|
||||
send=\u53d1\u9001
|
||||
server-information=\u670d\u52a1\u5668\u4fe1\u606f
|
||||
small=\u5c0f
|
||||
style=\u98ce\u683c
|
||||
the-game-ended-in-a-draw=\u6e38\u620f\u4ee5\u548c\u5c40\u7ed3\u675f
|
||||
theme=\u4e3b\u9898
|
||||
tic-tac-toe=\u4e09\u5b9a\u7ebf
|
||||
tictactoe1 =\u6b22\u8fce\u6765\u5230\u4e95\u5b57\u68cb\u6e38\u620f\uff01\u4f60\u53ef\u4ee5\u901a\u8fc7\u70b9\u51fb\u68cb\u76d8\u4e0a\u4efb\u610f\u4e00\u4e2a\u4e5d\u4e2a\u65b9\u683c\u6765\u843d\u5b50\u3002\u4e0a\u65b9\u793a\u4f8b\uff1a
|
||||
tictactoe2 =\u73a9\u5bb6\u5728\u6a2a\u3001\u7ad6\u6216\u659c\u7ebf\u4e0a\u8fde\u7eed\u653e\u7f6e\u4e09\u4e2a\u68cb\u5b50\u5373\u53ef\u83b7\u80dc\u3002\u5728\u4e0a\u65b9\u7684\u793a\u4f8b\u4e2d\uff0c\u73a9\u5bb6\u901a\u8fc7\u659c\u7ebf\u4e0a\u7684\u4e09\u4e2a\u68cb\u5b50\u83b7\u80dc\u4e86\u6bd4\u8d5b\u3002
|
||||
to-a-game-of=\u6311\u6218\u4e00\u573a
|
||||
tutorial=\u4f60\u60f3\u770b\u8fd9\u4e2a\u6e38\u620f\u7684\u6559\u7a0b\u5417\uff1f
|
||||
volume=\u97f3\u91cf
|
||||
windowed=\u7a97\u53e3\u6a21\u5f0f
|
||||
yes=\u662f
|
||||
you-lost-against=\u60a8\u8f93\u7ed9\u4e86
|
||||
you-were-challenged-by=\u60a8\u88ab\u6311\u6218\u81ea
|
||||
you-win=\u60a8\u83b7\u80dc\u4e86
|
||||
>=>
|
||||
<=<
|
||||
connect4.1=\u6b22\u8fce\u6765\u5230 Connect 4 \u6e38\u620f! \u4f60\u53ef\u4ee5\u70b9\u51fb\u4e00\u5217\u6761\u76ee\u64cd\u4f5c. \u64cd\u4f5c\u5c06\u88c5\u7f6e\u5728\u672a\u88c5\u5165\u7684\u6700\u4f4e\u884c.
|
||||
connect4.2=\u5982\u679c\u5f97\u52304\u4e2a\u5bf9\u5e94\u7684\u4ee3\u7406\u7ec4\u6210\u6c34\u5e73\u3001\u5347\u5e26\u6216\u5782\u76f4\u5373\u53ef\u80dc. \u770b\u4e0a\u65b9\u793a\u4f8b.
|
||||
reversi1=\u6b22\u8fce\u6765\u5230 Reversi \u6e38\u620f! \u4f60\u53ef\u4ee5\u70b9\u51fb\u4e00\u4e2a\u9ed8\u8272\u5149\u900f\u7a7a\u70b9\u64cd\u4f5c.
|
||||
reversi2=\u70b9\u51fb\u4e00\u4e2a\u70b9\u65f6\u5c06\u5c06\u6240\u6709\u4e2d\u95f4\u7684\u4ee3\u7406\u7ffb\u8f6c\u3002 \u770b\u4e0a\u65b9\u793a\u4f8b\uff0c\u9ec4\u8272\u662f\u5bf9\u4ee3\u7406\u9700\u64ad\u7684\u4ee3\u7406.
|
||||
reversi3=\u5982\u679c\u6ca1\u6709\u5408\u6cd5\u64cd\u4f5c\u4f60\u7684\u8fdb\u6b65\u53ef\u80fd\u88ab\u5ffd\u7565. \u8fd9\u4f1a\u8ba9\u5bf9\u624b\u518d\u6b21\u64cd\u4f5c\u5230\u4f60\u6709\u5408\u6cd5\u64cd\u4f5c\u65f6.
|
||||
reversi4=\u672c\u6e38\u620f\u7ed3\u675f\u65f6\u8d62\u5f97\u6ee1\u8fc7\u76d8\u9762\u7684\u4ee3\u7406\u6570\u6700\u591a\u7684\u4eba\u5c31\u80dc.
|
||||
tutorialstring=\u6559\u7a0b
|
||||
|
||||
# Main Menu buttons
|
||||
mainMenuSelectTicTacToe=\u4E95\u5B57\u68CB
|
||||
# ???
|
||||
mainMenuSelectReversi=\u9ED1\u767D\u68CB
|
||||
# ???
|
||||
mainMenuSelectSudoku=\u6570\u72EC
|
||||
# ??
|
||||
mainMenuSelectBattleship=\u6D77\u6218\u68CB
|
||||
# ???
|
||||
mainMenuSelectOther=\u5176\u4ED6
|
||||
# ??
|
||||
mainMenuSelectCredits=\u5236\u4F5C\u4EBA\u5458
|
||||
# ????
|
||||
mainMenuSelectOptions=\u9009\u9879
|
||||
# ??
|
||||
mainMenuSelectQuit=\u9000\u51FA
|
||||
# ??
|
||||
|
||||
# Quit Menu text and buttons
|
||||
quitMenuTextSure=\u4F60\u786E\u5B9A\u5417\uFF1F
|
||||
# ?????
|
||||
quitMenuButtonYes=\u662F
|
||||
# ?
|
||||
quitMenuButtonNo=\u5426
|
||||
# ?
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u963f\u62c9\u4f2f\u8bed)
|
||||
chinese=\u4e2d\u6587
|
||||
dutch=Nederlands (\u8377\u5170\u8bed)
|
||||
english=English (\u82f1\u8bed)
|
||||
french=Fran\u00e7ais (\u6cd5\u8bed)
|
||||
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u683c\u9c81\u5409\u4e9a\u8bed)
|
||||
german=Deutsch (\u5fb7\u8bed)
|
||||
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\u5370\u5ea6\u8bed)
|
||||
italian=Italiano (\u610f\u5927\u5229\u8bed)
|
||||
japanese=\u65e5\u672c\u8a9e (\u65e5\u8bed)
|
||||
korean=\ud55c\uad6d\uc5b4 (\u97e9\u8bed)
|
||||
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\u4fc4\u8bed)
|
||||
spanish=Espa\u00f1ol (\u897f\u73ed\u7259\u8bed)
|
||||
@@ -1,37 +0,0 @@
|
||||
.background {
|
||||
-fx-background-color: linear-gradient(to bottom right, #21a7b2, #8f32b9);
|
||||
}
|
||||
|
||||
.text {
|
||||
-fx-fill: white;
|
||||
|
||||
-fx-font-family: "Segoe UI", sans-serif;
|
||||
-fx-font-weight: bold;
|
||||
-fx-font-size: 24px;
|
||||
}
|
||||
|
||||
.button, .text-field, .combo-box, .combo-box-popup .list-cell {
|
||||
-fx-padding: 10 20;
|
||||
|
||||
-fx-background-color: transparent;
|
||||
-fx-border-color: transparent;
|
||||
}
|
||||
|
||||
.combo-box-popup .list-view {
|
||||
-fx-background-color: #1d1d1d;
|
||||
}
|
||||
|
||||
.text-field {
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.button:hover, .text-field:hover, .combo-box:hover, .combo-box-popup .list-cell:hover {
|
||||
-fx-cursor: hand;
|
||||
|
||||
-fx-effect: dropshadow(gaussian, #00ffff7f, 10, 0.5, 0, 0);
|
||||
-fx-border-color: white;
|
||||
}
|
||||
|
||||
.text-field:focused, .combo-box:focused {
|
||||
-fx-border-color: white;
|
||||
}
|
||||
199
app/src/main/resources/assets/style/dark.css
Normal file
@@ -0,0 +1,199 @@
|
||||
.bg-primary {
|
||||
-fx-background-color: linear-gradient(to bottom, #2a3a45, #1c2730);
|
||||
}
|
||||
|
||||
.bg-secondary {
|
||||
-fx-background-color: linear-gradient(to bottom, #3b4a57, #2a3742);
|
||||
}
|
||||
|
||||
.bg-popup {
|
||||
-fx-background-color: rgba(20, 40, 55, 0.9);
|
||||
-fx-background-radius: 8;
|
||||
-fx-effect: dropshadow(gaussian, #224455cc, 8, 0, 0, 2);
|
||||
}
|
||||
|
||||
.song-display {
|
||||
-fx-padding: 8 12 8 12;
|
||||
-fx-spacing: 6px;
|
||||
-fx-alignment: center;
|
||||
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.5), 6, 0.5, 0, 2);
|
||||
-fx-min-width: 220px;
|
||||
-fx-max-width: 260px;
|
||||
}
|
||||
|
||||
.song-title {
|
||||
-fx-font-size: 14px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
-fx-pref-width: 200px;
|
||||
-fx-accent: red;
|
||||
}
|
||||
|
||||
.progress-bar > .track {
|
||||
-fx-background-radius: 30;
|
||||
}
|
||||
|
||||
.progress-bar > .bar {
|
||||
-fx-background-radius: 30px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
-fx-font-size: 11px;
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.skip-button {
|
||||
-fx-background-color: transparent;
|
||||
-fx-background-radius: 0;
|
||||
-fx-cursor: hand;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.skip-button .text {
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.pause-button {
|
||||
-fx-background-color: transparent;
|
||||
-fx-background-radius: 0;
|
||||
-fx-cursor: hand;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.pause-button .text {
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.previous-button {
|
||||
-fx-background-color: transparent;
|
||||
-fx-background-radius: 0;
|
||||
-fx-cursor: hand;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.previous-button .text {
|
||||
-fx-fill: white;
|
||||
}
|
||||
|
||||
.button {
|
||||
-fx-background-color: linear-gradient(to bottom, #1f5e20, #2e7d2e);
|
||||
-fx-background-radius: 8;
|
||||
-fx-border-color: #3caf3f;
|
||||
-fx-cursor: hand;
|
||||
-fx-effect: dropshadow(gaussian, #3caf3fdd, 6, 0, 0, 2);
|
||||
-fx-text-fill: #e0f2e9;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
-fx-background-color: linear-gradient(to bottom, #44a044, #57b257);
|
||||
-fx-border-color: #2f7d2f;
|
||||
}
|
||||
|
||||
.combo-box {
|
||||
-fx-background-color: linear-gradient(to bottom, #3c5155, #2a3a3e);
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-color: #3caf3f;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
.combo-box:hover {
|
||||
-fx-border-color: #55a755;
|
||||
}
|
||||
|
||||
.combo-box:focused {
|
||||
-fx-border-color: #88cc88;
|
||||
-fx-effect: dropshadow(gaussian, #88cc8899, 5, 0, 0, 1);
|
||||
}
|
||||
|
||||
.combo-box .arrow,
|
||||
.combo-box .arrow-button {
|
||||
-fx-background-color: transparent;
|
||||
-fx-border-color: transparent;
|
||||
}
|
||||
|
||||
.combo-box .list-cell {
|
||||
-fx-background-color: transparent;
|
||||
-fx-text-fill: #a8d0a8;
|
||||
}
|
||||
|
||||
.combo-box .list-view {
|
||||
-fx-background-color: #264233;
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-color: #3caf3f;
|
||||
}
|
||||
|
||||
.combo-box-popup .list-cell {
|
||||
-fx-text-fill: #a8d0a8;
|
||||
}
|
||||
|
||||
.combo-box-popup .list-cell:hover {
|
||||
-fx-background-color: #44a044;
|
||||
}
|
||||
|
||||
.combo-box-popup .list-cell:selected {
|
||||
-fx-background-color: #2e7d2e;
|
||||
-fx-text-fill: #e0f2e9;
|
||||
}
|
||||
|
||||
.input {
|
||||
-fx-background-color: linear-gradient(to bottom, #1f3a3b, #124040);
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-color: #3caf3f;
|
||||
-fx-text-fill: #a8d0a8;
|
||||
-fx-font-weight: normal;
|
||||
}
|
||||
|
||||
.input:hover {
|
||||
-fx-border-color: #55a755;
|
||||
}
|
||||
|
||||
.input:focused {
|
||||
-fx-border-color: #88cc88;
|
||||
-fx-effect: dropshadow(gaussian, #88cc8899, 5, 0, 0, 1);
|
||||
}
|
||||
|
||||
.my-turn {
|
||||
-fx-fill: #e05656;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.separator .line {
|
||||
-fx-border-color: #55a755;
|
||||
-fx-opacity: 1;
|
||||
}
|
||||
|
||||
.slider {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.slider .thumb {
|
||||
-fx-background-color: linear-gradient(to bottom, #2e7d2e, #44a044);
|
||||
-fx-background-radius: 50%;
|
||||
-fx-effect: dropshadow(gaussian, #3caf3fdd, 5, 0, 0, 1);
|
||||
}
|
||||
|
||||
.slider .thumb:hover {
|
||||
-fx-scale-x: 1.15;
|
||||
-fx-scale-y: 1.15;
|
||||
}
|
||||
|
||||
.slider .track {
|
||||
-fx-background-color: linear-gradient(to left, #57b257, #e05c5c);
|
||||
-fx-background-insets: 0;
|
||||
-fx-background-radius: 6;
|
||||
}
|
||||
|
||||
.text {
|
||||
-fx-fill: #a8d0a8;
|
||||
-fx-font-weight: normal;
|
||||
-fx-text-fill: #a8d0a8;
|
||||
}
|
||||
|
||||
.header {
|
||||
-fx-fill: #88cc88;
|
||||
-fx-font-weight: bold;
|
||||
-fx-text-fill: #88cc88;
|
||||
}
|
||||