Compare commits
162 Commits
main
...
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 | ||
|
|
e12e48b4fb |
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>
|
||||
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>
|
||||
41
.idea/resourceBundles.xml
generated
@@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ResourceBundleManager">
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_ar.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_de.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_en.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_es.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_fr.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_hi.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_it.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_ja.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_ko.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_nl.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_ru.properties" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_zh.properties" />
|
||||
<custom-resource-bundle>
|
||||
<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>
|
||||
<custom-resource-bundle>
|
||||
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_ar.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_en.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_hi.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_ja.properties" />
|
||||
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/localization_ko.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_ru.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>
|
||||
103
app/pom.xml
@@ -1,8 +1,13 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.toop</groupId>
|
||||
<artifactId>pism_app</artifactId>
|
||||
<parent>
|
||||
<groupId>org.toop</groupId>
|
||||
<artifactId>pism</artifactId>
|
||||
<version>0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>app</artifactId>
|
||||
<version>0.1</version>
|
||||
|
||||
<properties>
|
||||
@@ -24,24 +29,36 @@
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.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>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<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>
|
||||
@@ -112,14 +129,56 @@
|
||||
</java>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>25</source>
|
||||
<target>25</target>
|
||||
</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,167 +1,113 @@
|
||||
package org.toop.app;
|
||||
|
||||
import java.util.Stack;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.stage.Stage;
|
||||
import org.toop.app.layer.Layer;
|
||||
import org.toop.app.layer.layers.MainLayer;
|
||||
import org.toop.app.layer.layers.QuitPopup;
|
||||
import org.toop.framework.asset.ResourceManager;
|
||||
import org.toop.framework.asset.resources.CssAsset;
|
||||
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;
|
||||
|
||||
public final class App extends Application {
|
||||
private static Stage stage;
|
||||
private static Scene scene;
|
||||
private static StackPane root;
|
||||
import javafx.application.Application;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public final class App extends Application {
|
||||
private static Stage stage;
|
||||
private static Scene scene;
|
||||
|
||||
private static Stack<Layer> stack;
|
||||
private static int height;
|
||||
private static int width;
|
||||
|
||||
private static boolean isQuitting;
|
||||
private static boolean isQuitting;
|
||||
|
||||
public static void run(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
public static void run(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) throws Exception {
|
||||
final StackPane root = new StackPane();
|
||||
final Scene scene = new Scene(root);
|
||||
@Override
|
||||
public void start(Stage stage) throws Exception {
|
||||
final StackPane root = WidgetContainer.setup();
|
||||
final Scene scene = new Scene(root);
|
||||
|
||||
stage.setTitle(AppContext.getString("appTitle"));
|
||||
stage.setWidth(1080);
|
||||
stage.setHeight(720);
|
||||
stage.setTitle(AppContext.getString("app-title"));
|
||||
stage.titleProperty().bind(AppContext.bindToKey("app-title"));
|
||||
|
||||
stage.setOnCloseRequest(
|
||||
event -> {
|
||||
event.consume();
|
||||
stage.setWidth(1080);
|
||||
stage.setHeight(720);
|
||||
|
||||
if (!isQuitting) {
|
||||
quitPopup();
|
||||
}
|
||||
});
|
||||
scene.getRoot();
|
||||
|
||||
stage.setScene(scene);
|
||||
stage.setResizable(false);
|
||||
stage.setMinWidth(1080);
|
||||
stage.setMinHeight(720);
|
||||
stage.setOnCloseRequest(event -> {
|
||||
event.consume();
|
||||
startQuit();
|
||||
});
|
||||
|
||||
stage.show();
|
||||
stage.setScene(scene);
|
||||
stage.setResizable(true);
|
||||
|
||||
App.stage = stage;
|
||||
App.scene = scene;
|
||||
App.root = root;
|
||||
stage.show();
|
||||
|
||||
App.stack = new Stack<>();
|
||||
App.stage = stage;
|
||||
App.scene = scene;
|
||||
|
||||
App.width = (int) stage.getWidth();
|
||||
App.height = (int) stage.getHeight();
|
||||
App.width = (int)stage.getWidth();
|
||||
App.height = (int)stage.getHeight();
|
||||
|
||||
App.isQuitting = false;
|
||||
App.isQuitting = false;
|
||||
|
||||
final AppSettings settings = new AppSettings();
|
||||
settings.applySettings();
|
||||
AppSettings.applySettings();
|
||||
new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
|
||||
|
||||
new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
|
||||
activate(new MainLayer());
|
||||
}
|
||||
WidgetContainer.add(Pos.CENTER, new MainView());
|
||||
WidgetContainer.add(Pos.BOTTOM_RIGHT, new SongDisplay());
|
||||
}
|
||||
|
||||
public static void activate(Layer layer) {
|
||||
Platform.runLater(
|
||||
() -> {
|
||||
popAll();
|
||||
push(layer);
|
||||
});
|
||||
}
|
||||
public static void startQuit() {
|
||||
if (isQuitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
public static void push(Layer layer) {
|
||||
Platform.runLater(
|
||||
() -> {
|
||||
root.getChildren().addLast(layer.getLayer());
|
||||
stack.push(layer);
|
||||
});
|
||||
}
|
||||
WidgetContainer.add(Pos.CENTER, new QuitPopup());
|
||||
isQuitting = true;
|
||||
}
|
||||
|
||||
public static void pop() {
|
||||
Platform.runLater(
|
||||
() -> {
|
||||
root.getChildren().removeLast();
|
||||
stack.pop();
|
||||
public static void stopQuit() {
|
||||
isQuitting = false;
|
||||
}
|
||||
|
||||
isQuitting = false;
|
||||
});
|
||||
}
|
||||
public static void quit() {
|
||||
stage.close();
|
||||
System.exit(0); // TODO: This is like dropping a nuke
|
||||
}
|
||||
|
||||
public static void popAll() {
|
||||
Platform.runLater(
|
||||
() -> {
|
||||
final int childrenCount = root.getChildren().size();
|
||||
public static void setFullscreen(boolean fullscreen) {
|
||||
stage.setFullScreen(fullscreen);
|
||||
|
||||
for (int i = 0; i < childrenCount; i++) {
|
||||
try {
|
||||
root.getChildren().removeLast();
|
||||
} catch (Exception e) {
|
||||
IO.println(e);
|
||||
}
|
||||
}
|
||||
width = (int)stage.getWidth();
|
||||
height = (int)stage.getHeight();
|
||||
}
|
||||
|
||||
stack.removeAllElements();
|
||||
});
|
||||
}
|
||||
public static void setStyle(String theme, String layoutSize) {
|
||||
scene.getStylesheets().clear();
|
||||
|
||||
public static void quitPopup() {
|
||||
Platform.runLater(
|
||||
() -> {
|
||||
push(new QuitPopup());
|
||||
isQuitting = true;
|
||||
});
|
||||
}
|
||||
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 void quit() {
|
||||
stage.close();
|
||||
}
|
||||
public static int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public static void reloadAll() {
|
||||
stage.setTitle(AppContext.getString("appTitle"));
|
||||
|
||||
for (final Layer layer : stack) {
|
||||
layer.reload();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setFullscreen(boolean fullscreen) {
|
||||
stage.setFullScreen(fullscreen);
|
||||
|
||||
width = (int) stage.getWidth();
|
||||
height = (int) stage.getHeight();
|
||||
|
||||
reloadAll();
|
||||
}
|
||||
|
||||
public static void setStyle(String theme, String layoutSize) {
|
||||
final int stylesCount = scene.getStylesheets().size();
|
||||
|
||||
for (int i = 0; i < stylesCount; i++) {
|
||||
scene.getStylesheets().removeLast();
|
||||
}
|
||||
|
||||
scene.getStylesheets().add(ResourceManager.<CssAsset>get(theme + ".css").getUrl());
|
||||
scene.getStylesheets().add(ResourceManager.<CssAsset>get(layoutSize + ".css").getUrl());
|
||||
|
||||
reloadAll();
|
||||
}
|
||||
|
||||
public static int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public static int getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
public static int getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,56 @@
|
||||
package org.toop.app;
|
||||
|
||||
public record GameInformation(
|
||||
String[] playerName,
|
||||
boolean[] isPlayerHuman,
|
||||
int[] computerDifficulty,
|
||||
int[] computerThinkTime,
|
||||
boolean isConnectionLocal,
|
||||
String serverIP,
|
||||
String serverPort) {}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,130 +1,215 @@
|
||||
package org.toop.app.canvas;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
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) {}
|
||||
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 Canvas canvas;
|
||||
protected final GraphicsContext graphics;
|
||||
|
||||
protected final Color color;
|
||||
protected final Color color;
|
||||
protected final Color backgroundColor;
|
||||
|
||||
protected int width;
|
||||
protected int height;
|
||||
protected final int width;
|
||||
protected final int height;
|
||||
|
||||
protected final int rows;
|
||||
protected final int columns;
|
||||
protected final int rowSize;
|
||||
protected final int columnSize;
|
||||
|
||||
protected final int gapSize;
|
||||
protected final boolean edges;
|
||||
protected final int gapSize;
|
||||
protected final boolean edges;
|
||||
|
||||
protected final Cell[] cells;
|
||||
protected final Cell[] cells;
|
||||
|
||||
protected GameCanvas(
|
||||
Color color,
|
||||
int width,
|
||||
int height,
|
||||
int rows,
|
||||
int columns,
|
||||
int gapSize,
|
||||
boolean edges,
|
||||
Consumer<Integer> onCellClicked) {
|
||||
canvas = new Canvas(width, height);
|
||||
graphics = canvas.getGraphicsContext2D();
|
||||
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.color = color;
|
||||
this.backgroundColor = backgroundColor;
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
this.rowSize = rowSize;
|
||||
this.columnSize = columnSize;
|
||||
|
||||
this.gapSize = gapSize;
|
||||
this.edges = edges;
|
||||
this.gapSize = gapSize;
|
||||
this.edges = edges;
|
||||
|
||||
cells = new Cell[rows * columns];
|
||||
cells = new Cell[rowSize * columnSize];
|
||||
|
||||
final float cellWidth = ((float) width - (rows - 1) * gapSize) / rows;
|
||||
final float cellHeight = ((float) height - (columns - 1) * gapSize) / columns;
|
||||
final float cellWidth = ((float) width - gapSize * rowSize - gapSize) / rowSize;
|
||||
final float cellHeight = ((float) height - gapSize * columnSize - gapSize) / columnSize;
|
||||
|
||||
for (int y = 0; y < columns; y++) {
|
||||
final float startY = y * cellHeight + y * gapSize;
|
||||
for (int y = 0; y < columnSize; y++) {
|
||||
final float startY = y * cellHeight + y * gapSize + 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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
canvas.setOnMouseClicked(event -> {
|
||||
if (event.getButton() != MouseButton.PRIMARY) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int column = (int) ((event.getX() / width) * rows);
|
||||
final int row = (int) ((event.getY() / height) * columns);
|
||||
final int column = (int) ((event.getX() / this.width) * rowSize);
|
||||
final int row = (int) ((event.getY() / this.height) * columnSize);
|
||||
|
||||
event.consume();
|
||||
onCellClicked.accept(row * rows + column);
|
||||
});
|
||||
final Cell cell = cells[column + row * rowSize];
|
||||
|
||||
render();
|
||||
}
|
||||
if (cell.isInside(event.getX(), event.getY())) {
|
||||
event.consume();
|
||||
onCellClicked.accept(column + row * rowSize);
|
||||
}
|
||||
});
|
||||
|
||||
public void clear() {
|
||||
graphics.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
public void render() {
|
||||
graphics.setFill(color);
|
||||
|
||||
for (int x = 1; x < rows; x++) {
|
||||
graphics.fillRect(cells[x].x() - gapSize, 0, gapSize, height);
|
||||
}
|
||||
|
||||
for (int y = 1; y < columns; y++) {
|
||||
graphics.fillRect(0, cells[y * rows].y() - gapSize, width, gapSize);
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
if (edges) {
|
||||
graphics.fillRect(-gapSize, 0, gapSize, height);
|
||||
graphics.fillRect(0, -gapSize, width, gapSize);
|
||||
private void render() {
|
||||
graphics.setFill(backgroundColor);
|
||||
graphics.fillRect(0, 0, width, height);
|
||||
|
||||
graphics.fillRect(width - gapSize, 0, gapSize, height);
|
||||
graphics.fillRect(0, height - gapSize, width, gapSize);
|
||||
}
|
||||
}
|
||||
graphics.setFill(color);
|
||||
|
||||
public void draw(Color color, int cell) {
|
||||
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;
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
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.fillRect(x, y, width, height);
|
||||
graphics.fillOval(x + width/offset, y + height/offset, width, height);
|
||||
}
|
||||
|
||||
public void resize(int width, int height) {
|
||||
canvas.setWidth(width);
|
||||
canvas.setHeight(height);
|
||||
private void drawDotScaled(Color color, int cell, double scale) {
|
||||
final float cx = cells[cell].x() + gapSize;
|
||||
final float cy = cells[cell].y() + gapSize;
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
final float fullWidth = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
|
||||
clear();
|
||||
render();
|
||||
}
|
||||
final float scaledWidth = (float)(fullWidth * scale);
|
||||
final float offsetX = (fullWidth - scaledWidth) / 2;
|
||||
|
||||
public Canvas getCanvas() {
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,38 @@
|
||||
package org.toop.app.canvas;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
public class TicTacToeCanvas extends GameCanvas {
|
||||
public TicTacToeCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
|
||||
super(color, width, height, 3, 3, 10, false, onCellClicked);
|
||||
}
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public void drawX(Color color, int cell) {
|
||||
graphics.setStroke(color);
|
||||
graphics.setLineWidth(gapSize);
|
||||
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);
|
||||
}
|
||||
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
public void drawX(Color color, int cell) {
|
||||
graphics.setStroke(color);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
graphics.strokeLine(x, y, x + width, y + height);
|
||||
graphics.strokeLine(x + width, y, x, y + height);
|
||||
}
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
|
||||
public void drawO(Color color, int cell) {
|
||||
graphics.setStroke(color);
|
||||
graphics.setLineWidth(gapSize);
|
||||
graphics.strokeLine(x, y, x + width, y + height);
|
||||
graphics.strokeLine(x + width, y, x, y + height);
|
||||
}
|
||||
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
public void drawO(Color color, int cell) {
|
||||
graphics.setStroke(color);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
graphics.strokeOval(x, y, width, height);
|
||||
}
|
||||
}
|
||||
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,12 +0,0 @@
|
||||
package org.toop.app.layer;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
public abstract class Container {
|
||||
public abstract Region getContainer();
|
||||
|
||||
public abstract void addNodes(Node... nodes);
|
||||
|
||||
public abstract void addContainer(Container container, boolean fill);
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package org.toop.app.layer;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.canvas.GameCanvas;
|
||||
|
||||
public abstract class Layer {
|
||||
protected StackPane layer;
|
||||
protected Region background;
|
||||
|
||||
protected Layer(String... backgroundStyles) {
|
||||
layer = new StackPane();
|
||||
|
||||
background = new Region();
|
||||
background.getStyleClass().addAll(backgroundStyles);
|
||||
background.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
||||
|
||||
layer.getChildren().addLast(background);
|
||||
}
|
||||
|
||||
protected void addContainer(
|
||||
Container container,
|
||||
Pos position,
|
||||
int xOffset,
|
||||
int yOffset,
|
||||
int widthPercent,
|
||||
int heightPercent) {
|
||||
StackPane.setAlignment(container.getContainer(), position);
|
||||
|
||||
final double widthUnit = App.getWidth() / 100.0;
|
||||
final double heightUnit = App.getHeight() / 100.0;
|
||||
|
||||
if (widthPercent > 0) {
|
||||
container.getContainer().setMaxWidth(widthPercent * widthUnit);
|
||||
} else {
|
||||
container.getContainer().setMaxWidth(Region.USE_PREF_SIZE);
|
||||
}
|
||||
|
||||
if (heightPercent > 0) {
|
||||
container.getContainer().setMaxHeight(heightPercent * heightUnit);
|
||||
} else {
|
||||
container.getContainer().setMaxHeight(Region.USE_PREF_SIZE);
|
||||
}
|
||||
|
||||
container.getContainer().setTranslateX(xOffset * widthUnit);
|
||||
container.getContainer().setTranslateY(yOffset * heightUnit);
|
||||
|
||||
layer.getChildren().addLast(container.getContainer());
|
||||
}
|
||||
|
||||
protected void addGameCanvas(GameCanvas canvas, Pos position, int xOffset, int yOffset) {
|
||||
StackPane.setAlignment(canvas.getCanvas(), position);
|
||||
|
||||
final double widthUnit = App.getWidth() / 100.0;
|
||||
final double heightUnit = App.getHeight() / 100.0;
|
||||
|
||||
canvas.getCanvas().setTranslateX(xOffset * widthUnit);
|
||||
canvas.getCanvas().setTranslateY(yOffset * heightUnit);
|
||||
|
||||
layer.getChildren().addLast(canvas.getCanvas());
|
||||
}
|
||||
|
||||
protected void pop() {
|
||||
if (layer.getChildren().size() <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
layer.getChildren().removeLast();
|
||||
}
|
||||
|
||||
protected void popAll() {
|
||||
final int containers = layer.getChildren().size();
|
||||
|
||||
for (int i = 1; i < containers; i++) {
|
||||
layer.getChildren().removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
public StackPane getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
public abstract void reload();
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
package org.toop.app.layer;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.geometry.Orientation;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.text.Text;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
|
||||
public final class NodeBuilder {
|
||||
public static void addCss(Node node, String... cssClasses) {
|
||||
node.getStyleClass().addAll(cssClasses);
|
||||
}
|
||||
|
||||
public static void setCss(Node node, String... cssClasses) {
|
||||
node.getStyleClass().removeAll();
|
||||
node.getStyleClass().addAll(cssClasses);
|
||||
}
|
||||
|
||||
public static Text header(String x) {
|
||||
final Text element = new Text(x);
|
||||
setCss(element, "text-primary", "text-header");
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static Text text(String x) {
|
||||
final Text element = new Text(x);
|
||||
setCss(element, "text-secondary", "text-normal");
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static Label button(String x, Runnable runnable) {
|
||||
final Label element = new Label(x);
|
||||
setCss(element, "button", "text-normal");
|
||||
|
||||
element.setOnMouseClicked(
|
||||
_ -> {
|
||||
new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
|
||||
runnable.run();
|
||||
});
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static Label toggle(String x1, String x2, boolean toggled, Consumer<Boolean> consumer) {
|
||||
final Label element = new Label(toggled ? x2 : x1);
|
||||
setCss(element, "toggle", "text-normal");
|
||||
|
||||
final BooleanProperty checked = new SimpleBooleanProperty(toggled);
|
||||
|
||||
element.setOnMouseClicked(
|
||||
_ -> {
|
||||
new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
|
||||
checked.set(!checked.get());
|
||||
|
||||
if (checked.get()) {
|
||||
element.setText(x1);
|
||||
} else {
|
||||
element.setText(x2);
|
||||
}
|
||||
|
||||
consumer.accept(checked.get());
|
||||
});
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static Slider slider(int max, int initial, Consumer<Integer> consumer) {
|
||||
final Slider element = new Slider(0, max, initial);
|
||||
setCss(element, "bg-slider-track");
|
||||
|
||||
element.setMinorTickCount(0);
|
||||
element.setMajorTickUnit(1);
|
||||
element.setBlockIncrement(1);
|
||||
|
||||
element.setSnapToTicks(true);
|
||||
element.setShowTickLabels(true);
|
||||
|
||||
element.setOnMouseClicked(
|
||||
_ -> {
|
||||
new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
|
||||
});
|
||||
|
||||
element.valueProperty()
|
||||
.addListener(
|
||||
(_, _, newValue) -> {
|
||||
consumer.accept(newValue.intValue());
|
||||
});
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static TextField input(String x, Consumer<String> consumer) {
|
||||
final TextField element = new TextField(x);
|
||||
setCss(element, "input", "text-normal");
|
||||
|
||||
element.setOnMouseClicked(
|
||||
_ -> {
|
||||
new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
|
||||
});
|
||||
|
||||
element.textProperty()
|
||||
.addListener(
|
||||
(_, _, newValue) -> {
|
||||
consumer.accept(newValue);
|
||||
});
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static <T> ChoiceBox<T> choiceBox(Consumer<T> consumer) {
|
||||
final ChoiceBox<T> element = new ChoiceBox<>();
|
||||
setCss(element, "choice-box", "text-normal");
|
||||
|
||||
element.setOnMouseClicked(
|
||||
_ -> {
|
||||
new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
|
||||
});
|
||||
|
||||
element.valueProperty()
|
||||
.addListener(
|
||||
(_, _, newValue) -> {
|
||||
consumer.accept(newValue);
|
||||
});
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static Separator separator() {
|
||||
final Separator element = new Separator(Orientation.HORIZONTAL);
|
||||
setCss(element, "separator");
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.toop.app.layer;
|
||||
|
||||
import org.toop.app.App;
|
||||
|
||||
public abstract class Popup extends Layer {
|
||||
protected Popup(boolean popOnBackground, String... backgroundStyles) {
|
||||
super(backgroundStyles);
|
||||
|
||||
if (popOnBackground) {
|
||||
background.setOnMouseClicked(
|
||||
_ -> {
|
||||
App.pop();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected Popup(boolean popOnBackground) {
|
||||
this(popOnBackground, "bg-popup");
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package org.toop.app.layer.containers;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import org.toop.app.layer.Container;
|
||||
|
||||
public final class HorizontalContainer extends Container {
|
||||
private final HBox container;
|
||||
|
||||
public HorizontalContainer(int spacing, String... cssClasses) {
|
||||
container = new HBox(spacing);
|
||||
container.getStyleClass().addAll(cssClasses);
|
||||
}
|
||||
|
||||
public HorizontalContainer(int spacing) {
|
||||
this(spacing, "container");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNodes(Node... nodes) {
|
||||
container.getChildren().addAll(nodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addContainer(Container container, boolean fill) {
|
||||
if (fill) {
|
||||
container.getContainer().setMinSize(0, 0);
|
||||
container.getContainer().setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
||||
HBox.setHgrow(container.getContainer(), Priority.ALWAYS);
|
||||
} else {
|
||||
container.getContainer().setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
|
||||
}
|
||||
|
||||
this.container.getChildren().add(container.getContainer());
|
||||
|
||||
if (fill) {
|
||||
balanceChildWidths();
|
||||
}
|
||||
}
|
||||
|
||||
private void balanceChildWidths() {
|
||||
final ObservableList<Node> children = container.getChildren();
|
||||
final double widthPerChild = container.getWidth() / children.size();
|
||||
|
||||
for (final Node child : children) {
|
||||
if (child instanceof Region) {
|
||||
((Region) child).setPrefWidth(widthPerChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package org.toop.app.layer.containers;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.toop.app.layer.Container;
|
||||
|
||||
public final class VerticalContainer extends Container {
|
||||
private final VBox container;
|
||||
|
||||
public VerticalContainer(int spacing, String... cssClasses) {
|
||||
container = new VBox(spacing);
|
||||
container.getStyleClass().addAll(cssClasses);
|
||||
}
|
||||
|
||||
public VerticalContainer(int spacing) {
|
||||
this(spacing, "container");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNodes(Node... nodes) {
|
||||
container.getChildren().addAll(nodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addContainer(Container container, boolean fill) {
|
||||
if (fill) {
|
||||
container.getContainer().setMinSize(0, 0);
|
||||
container.getContainer().setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
||||
VBox.setVgrow(container.getContainer(), Priority.ALWAYS);
|
||||
} else {
|
||||
container.getContainer().setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
|
||||
}
|
||||
|
||||
this.container.getChildren().add(container.getContainer());
|
||||
|
||||
if (fill) {
|
||||
balanceChildHeights();
|
||||
}
|
||||
}
|
||||
|
||||
private void balanceChildHeights() {
|
||||
final ObservableList<Node> children = container.getChildren();
|
||||
final double heightPerChild = container.getHeight() / children.size();
|
||||
|
||||
for (final Node child : children) {
|
||||
if (child instanceof Region) {
|
||||
((Region) child).setPrefHeight(heightPerChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,235 +0,0 @@
|
||||
package org.toop.app.layer.layers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListView;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.layer.Container;
|
||||
import org.toop.app.layer.Layer;
|
||||
import org.toop.app.layer.NodeBuilder;
|
||||
import org.toop.app.layer.Popup;
|
||||
import org.toop.app.layer.containers.HorizontalContainer;
|
||||
import org.toop.app.layer.containers.VerticalContainer;
|
||||
import org.toop.app.layer.layers.game.TicTacToeLayer;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
public final class ConnectedLayer extends Layer {
|
||||
private static Timer pollTimer = new Timer();
|
||||
|
||||
private static class ChallengePopup extends Popup {
|
||||
private final GameInformation information;
|
||||
|
||||
private final String challenger;
|
||||
private final String game;
|
||||
|
||||
private final long clientID;
|
||||
private final int challengeID;
|
||||
|
||||
public ChallengePopup(
|
||||
GameInformation information,
|
||||
String challenger,
|
||||
String game,
|
||||
long clientID,
|
||||
String challengeID) {
|
||||
super(false, "bg-popup");
|
||||
|
||||
this.information = information;
|
||||
|
||||
this.challenger = challenger;
|
||||
this.game = game;
|
||||
|
||||
this.clientID = clientID;
|
||||
this.challengeID =
|
||||
Integer.parseInt(challengeID.substring(18, challengeID.length() - 2));
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
popAll();
|
||||
|
||||
final var challengeText = NodeBuilder.header(AppContext.getString("challengeText"));
|
||||
final var challengerNameText = NodeBuilder.header(challenger);
|
||||
|
||||
final var gameText = NodeBuilder.text(AppContext.getString("gameIsText"));
|
||||
final var gameNameText = NodeBuilder.text(game);
|
||||
|
||||
final var acceptButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("accept"),
|
||||
() -> {
|
||||
pollTimer.cancel();
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(
|
||||
new NetworkEvents.SendAcceptChallenge(
|
||||
clientID, challengeID))
|
||||
.postEvent();
|
||||
App.activate(new TicTacToeLayer(information, clientID));
|
||||
});
|
||||
|
||||
final var denyButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("deny"),
|
||||
() -> {
|
||||
App.pop();
|
||||
});
|
||||
|
||||
final Container controlContainer = new HorizontalContainer(30);
|
||||
controlContainer.addNodes(acceptButton, denyButton);
|
||||
|
||||
final Container mainContainer = new VerticalContainer(30);
|
||||
mainContainer.addNodes(challengeText, challengerNameText);
|
||||
mainContainer.addNodes(gameText, gameNameText);
|
||||
|
||||
mainContainer.addContainer(controlContainer, false);
|
||||
|
||||
addContainer(mainContainer, Pos.CENTER, 0, 0, 30, 30);
|
||||
}
|
||||
}
|
||||
|
||||
GameInformation information;
|
||||
long clientId;
|
||||
String user;
|
||||
List<String> onlinePlayers = new CopyOnWriteArrayList<>();
|
||||
|
||||
public ConnectedLayer(GameInformation information) {
|
||||
super("bg-primary");
|
||||
|
||||
this.information = information;
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(
|
||||
NetworkEvents.StartClient.class,
|
||||
information.serverIP(),
|
||||
Integer.parseInt(information.serverPort()))
|
||||
.onResponse(
|
||||
NetworkEvents.StartClientResponse.class,
|
||||
e -> {
|
||||
clientId = e.clientId();
|
||||
user = information.playerName()[0].replaceAll("\\s+", "");
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(
|
||||
new NetworkEvents.SendLogin(this.clientId, this.user))
|
||||
.postEvent();
|
||||
|
||||
Thread popThread = new Thread(this::populatePlayerList);
|
||||
popThread.setDaemon(false);
|
||||
popThread.start();
|
||||
})
|
||||
.postEvent();
|
||||
|
||||
new EventFlow().listen(this::handleReceivedChallenge);
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
private void populatePlayerList() {
|
||||
EventFlow sendGetPlayerList =
|
||||
new EventFlow().addPostEvent(new NetworkEvents.SendGetPlayerlist(this.clientId));
|
||||
new EventFlow()
|
||||
.listen(
|
||||
NetworkEvents.PlayerlistResponse.class,
|
||||
e -> {
|
||||
if (e.clientId() == this.clientId) {
|
||||
List<String> playerList =
|
||||
new java.util.ArrayList<>(
|
||||
List.of(e.playerlist())); // TODO: Garbage,
|
||||
// but works
|
||||
playerList.removeIf(name -> name.equalsIgnoreCase(user));
|
||||
if (this.onlinePlayers != playerList) {
|
||||
this.onlinePlayers.clear();
|
||||
this.onlinePlayers.addAll(playerList);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
TimerTask task =
|
||||
new TimerTask() {
|
||||
public void run() {
|
||||
sendGetPlayerList.postEvent();
|
||||
Platform.runLater(() -> reload());
|
||||
}
|
||||
};
|
||||
|
||||
pollTimer.schedule(task, 0L, 5000L); // TODO: Block app exit, fix later
|
||||
}
|
||||
|
||||
private void sendChallenge(String oppUsername, String gameType) {
|
||||
final AtomicInteger challengeId = new AtomicInteger(-1);
|
||||
|
||||
if (onlinePlayers.contains(oppUsername)) {
|
||||
new EventFlow()
|
||||
.addPostEvent(
|
||||
new NetworkEvents.SendChallenge(this.clientId, oppUsername, gameType))
|
||||
.listen(
|
||||
NetworkEvents.ChallengeResponse.class,
|
||||
e -> {
|
||||
challengeId.set(
|
||||
Integer.parseInt(
|
||||
e.challengeId()
|
||||
.substring(
|
||||
18, e.challengeId().length() - 2)));
|
||||
})
|
||||
.listen(
|
||||
NetworkEvents.GameMatchResponse.class,
|
||||
e -> {
|
||||
if (e.clientId() == this.clientId) {
|
||||
pollTimer.cancel();
|
||||
App.activate(new TicTacToeLayer(information, this.clientId));
|
||||
}
|
||||
},
|
||||
false)
|
||||
.postEvent();
|
||||
// ^
|
||||
// |
|
||||
// |
|
||||
// |
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReceivedChallenge(NetworkEvents.ChallengeResponse response) {
|
||||
App.push(
|
||||
new ChallengePopup(
|
||||
information,
|
||||
response.challengerName(),
|
||||
response.gameType(),
|
||||
clientId,
|
||||
response.challengeId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
popAll();
|
||||
|
||||
ListView<Label> players = new ListView<>();
|
||||
|
||||
for (int i = 0; i < onlinePlayers.size(); i++) {
|
||||
int finalI = i;
|
||||
players.getItems()
|
||||
.add(
|
||||
NodeBuilder.button(
|
||||
onlinePlayers.get(i),
|
||||
() -> {
|
||||
String clickedPlayer = onlinePlayers.get(finalI);
|
||||
sendChallenge(clickedPlayer, "tic-tac-toe");
|
||||
}));
|
||||
}
|
||||
|
||||
final Container playersContainer = new VerticalContainer(10);
|
||||
playersContainer.addNodes(players);
|
||||
|
||||
addContainer(playersContainer, Pos.CENTER, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package org.toop.app.layer.layers;
|
||||
|
||||
import javafx.animation.PauseTransition;
|
||||
import javafx.animation.TranslateTransition;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.util.Duration;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.layer.Container;
|
||||
import org.toop.app.layer.NodeBuilder;
|
||||
import org.toop.app.layer.Popup;
|
||||
import org.toop.app.layer.containers.HorizontalContainer;
|
||||
import org.toop.app.layer.containers.VerticalContainer;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
public final class CreditsPopup extends Popup {
|
||||
private final int lineHeight = 100;
|
||||
|
||||
public CreditsPopup() {
|
||||
super(true, "bg-primary");
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
popAll();
|
||||
|
||||
final String[] credits = {
|
||||
AppContext.getString("scrumMaster") + ": Stef",
|
||||
AppContext.getString("productOwner") + ": Omar",
|
||||
AppContext.getString("mergeCommander") + ": Bas",
|
||||
AppContext.getString("localization") + ": Ticho",
|
||||
AppContext.getString("ai") + ": Michiel",
|
||||
AppContext.getString("developers") + ": Michiel, Bas, Stef, Omar, Ticho",
|
||||
AppContext.getString("moralSupport") + ": Wesley",
|
||||
AppContext.getString("opengl") + ": Omar"
|
||||
};
|
||||
|
||||
final Text[] creditsHeaders = new Text[credits.length];
|
||||
|
||||
for (int i = 0; i < credits.length; i++) {
|
||||
creditsHeaders[i] = NodeBuilder.header(credits[i]);
|
||||
}
|
||||
|
||||
final Container creditsContainer = new HorizontalContainer(0);
|
||||
|
||||
final Container animatedContainer = new VerticalContainer(lineHeight);
|
||||
creditsContainer.addContainer(animatedContainer, true);
|
||||
|
||||
animatedContainer.addNodes(creditsHeaders);
|
||||
addContainer(creditsContainer, Pos.CENTER, 0, 0, 50, 100);
|
||||
|
||||
playCredits(animatedContainer, App.getHeight());
|
||||
}
|
||||
|
||||
private void playCredits(Container container, double sceneLength) {
|
||||
container.getContainer().setTranslateY(-sceneLength);
|
||||
|
||||
final TranslateTransition scrollCredits =
|
||||
new TranslateTransition(Duration.seconds(20), container.getContainer());
|
||||
scrollCredits.setFromY(-sceneLength - lineHeight);
|
||||
scrollCredits.setToY(sceneLength + lineHeight);
|
||||
|
||||
scrollCredits.setOnFinished(
|
||||
_ -> {
|
||||
final PauseTransition pauseCredits = new PauseTransition(Duration.seconds(3));
|
||||
pauseCredits.setOnFinished(_ -> playCredits(container, sceneLength));
|
||||
pauseCredits.play();
|
||||
});
|
||||
|
||||
scrollCredits.play();
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package org.toop.app.layer.layers;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.layer.Container;
|
||||
import org.toop.app.layer.Layer;
|
||||
import org.toop.app.layer.NodeBuilder;
|
||||
import org.toop.app.layer.containers.VerticalContainer;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
public final class MainLayer extends Layer {
|
||||
public MainLayer() {
|
||||
super("bg-primary");
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
popAll();
|
||||
|
||||
final var tictactoeButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("tictactoe"),
|
||||
() -> {
|
||||
App.activate(new MultiplayerLayer());
|
||||
});
|
||||
|
||||
final var othelloButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("othello"),
|
||||
() -> {
|
||||
App.activate(new MultiplayerLayer());
|
||||
});
|
||||
|
||||
final var creditsButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("credits"),
|
||||
() -> {
|
||||
App.push(new CreditsPopup());
|
||||
});
|
||||
|
||||
final var optionsButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("options"),
|
||||
() -> {
|
||||
App.push(new OptionsPopup());
|
||||
});
|
||||
|
||||
final var quitButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("quit"),
|
||||
() -> {
|
||||
App.quitPopup();
|
||||
});
|
||||
|
||||
final Container gamesContainer = new VerticalContainer(5);
|
||||
gamesContainer.addNodes(tictactoeButton, othelloButton);
|
||||
|
||||
final Container controlContainer = new VerticalContainer(5);
|
||||
controlContainer.addNodes(creditsButton, optionsButton, quitButton);
|
||||
|
||||
addContainer(gamesContainer, Pos.TOP_LEFT, 2, 2, 20, 0);
|
||||
addContainer(controlContainer, Pos.BOTTOM_LEFT, 2, -2, 20, 0);
|
||||
}
|
||||
}
|
||||
@@ -1,241 +0,0 @@
|
||||
package org.toop.app.layer.layers;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import javafx.geometry.Pos;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.layer.Container;
|
||||
import org.toop.app.layer.Layer;
|
||||
import org.toop.app.layer.NodeBuilder;
|
||||
import org.toop.app.layer.containers.HorizontalContainer;
|
||||
import org.toop.app.layer.containers.VerticalContainer;
|
||||
import org.toop.app.layer.layers.game.TicTacToeLayer;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
public final class MultiplayerLayer extends Layer {
|
||||
private boolean isConnectionLocal = true;
|
||||
|
||||
private boolean isPlayer1Human = true;
|
||||
private String player1Name = "";
|
||||
private int computer1Difficulty = 0;
|
||||
private int computer1ThinkTime = 0;
|
||||
|
||||
private boolean isPlayer2Human = true;
|
||||
private String player2Name = "";
|
||||
private int computer2Difficulty = 0;
|
||||
private int computer2ThinkTime = 0;
|
||||
|
||||
private String serverIP = "";
|
||||
private String serverPort = "";
|
||||
|
||||
public MultiplayerLayer() {
|
||||
super("bg-primary");
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
popAll();
|
||||
|
||||
final Container player1Container = new VerticalContainer(20);
|
||||
final Container player2Container = new VerticalContainer(20);
|
||||
|
||||
final var isPlayer1HumanToggle =
|
||||
NodeBuilder.toggle(
|
||||
AppContext.getString("human"),
|
||||
AppContext.getString("computer"),
|
||||
!isPlayer1Human,
|
||||
(computer) -> {
|
||||
isPlayer1Human = !computer;
|
||||
reload();
|
||||
});
|
||||
|
||||
player1Container.addNodes(isPlayer1HumanToggle);
|
||||
|
||||
if (isPlayer1Human) {
|
||||
final var playerNameText = NodeBuilder.text(AppContext.getString("playerName"));
|
||||
final var playerNameInput =
|
||||
NodeBuilder.input(
|
||||
player1Name,
|
||||
(name) -> {
|
||||
player1Name = name;
|
||||
});
|
||||
|
||||
player1Container.addNodes(playerNameText, playerNameInput);
|
||||
} else {
|
||||
player1Name = "Pism Bot V" + LocalDateTime.now().getSecond();
|
||||
|
||||
final var computerNameText = NodeBuilder.text(player1Name);
|
||||
final var computerNameSeparator = NodeBuilder.separator();
|
||||
|
||||
final var computerDifficultyText =
|
||||
NodeBuilder.text(AppContext.getString("computerDifficulty"));
|
||||
final var computerDifficultySeparator = NodeBuilder.separator();
|
||||
final var computerDifficultySlider =
|
||||
NodeBuilder.slider(
|
||||
10,
|
||||
computer1Difficulty,
|
||||
(difficulty) -> computer1Difficulty = difficulty);
|
||||
|
||||
final var computerThinkTimeText =
|
||||
NodeBuilder.text(AppContext.getString("computerThinkTime"));
|
||||
final var computerThinkTimeSlider =
|
||||
NodeBuilder.slider(
|
||||
5, computer1ThinkTime, (thinkTime) -> computer1ThinkTime = thinkTime);
|
||||
|
||||
player1Container.addNodes(
|
||||
computerNameText,
|
||||
computerNameSeparator,
|
||||
computerDifficultyText,
|
||||
computerDifficultySlider,
|
||||
computerDifficultySeparator,
|
||||
computerThinkTimeText,
|
||||
computerThinkTimeSlider);
|
||||
}
|
||||
|
||||
if (isConnectionLocal) {
|
||||
final var isPlayer2HumanToggle =
|
||||
NodeBuilder.toggle(
|
||||
AppContext.getString("human"),
|
||||
AppContext.getString("computer"),
|
||||
!isPlayer2Human,
|
||||
(computer) -> {
|
||||
isPlayer2Human = !computer;
|
||||
reload();
|
||||
});
|
||||
|
||||
player2Container.addNodes(isPlayer2HumanToggle);
|
||||
|
||||
if (isPlayer2Human) {
|
||||
final var playerNameText = NodeBuilder.text(AppContext.getString("playerName"));
|
||||
final var playerNameInput =
|
||||
NodeBuilder.input(
|
||||
player2Name,
|
||||
(name) -> {
|
||||
player2Name = name;
|
||||
});
|
||||
|
||||
player2Container.addNodes(playerNameText, playerNameInput);
|
||||
} else {
|
||||
player2Name = "Pism Bot V" + LocalDateTime.now().getSecond();
|
||||
|
||||
final var computerNameText = NodeBuilder.text(player2Name);
|
||||
final var computerNameSeparator = NodeBuilder.separator();
|
||||
|
||||
final var computerDifficultyText =
|
||||
NodeBuilder.text(AppContext.getString("computerDifficulty"));
|
||||
final var computerDifficultySeparator = NodeBuilder.separator();
|
||||
final var computerDifficultySlider =
|
||||
NodeBuilder.slider(
|
||||
10,
|
||||
computer2Difficulty,
|
||||
(difficulty) -> computer2Difficulty = difficulty);
|
||||
|
||||
final var computerThinkTimeText =
|
||||
NodeBuilder.text(AppContext.getString("computerThinkTime"));
|
||||
final var computerThinkTimeSlider =
|
||||
NodeBuilder.slider(
|
||||
5,
|
||||
computer2ThinkTime,
|
||||
(thinkTime) -> computer2ThinkTime = thinkTime);
|
||||
|
||||
player2Container.addNodes(
|
||||
computerNameText,
|
||||
computerNameSeparator,
|
||||
computerDifficultyText,
|
||||
computerDifficultySlider,
|
||||
computerDifficultySeparator,
|
||||
computerThinkTimeText,
|
||||
computerThinkTimeSlider);
|
||||
}
|
||||
} else {
|
||||
final var serverIPText = NodeBuilder.text(AppContext.getString("serverIP"));
|
||||
final var serverIPSeparator = NodeBuilder.separator();
|
||||
final var serverIPInput =
|
||||
NodeBuilder.input(
|
||||
serverIP,
|
||||
(ip) -> {
|
||||
serverIP = ip;
|
||||
});
|
||||
|
||||
final var serverPortText = NodeBuilder.text(AppContext.getString("serverPort"));
|
||||
final var serverPortInput =
|
||||
NodeBuilder.input(
|
||||
serverPort,
|
||||
(port) -> {
|
||||
serverPort = port;
|
||||
});
|
||||
|
||||
player2Container.addNodes(
|
||||
serverIPText,
|
||||
serverIPInput,
|
||||
serverIPSeparator,
|
||||
serverPortText,
|
||||
serverPortInput);
|
||||
}
|
||||
|
||||
final var versusText = NodeBuilder.header("VS");
|
||||
|
||||
final var connectionTypeText =
|
||||
NodeBuilder.text(AppContext.getString("connectionType") + ":");
|
||||
final var connectionTypeToggle =
|
||||
NodeBuilder.toggle(
|
||||
AppContext.getString("local"),
|
||||
AppContext.getString("server"),
|
||||
!isConnectionLocal,
|
||||
(server) -> {
|
||||
isConnectionLocal = !server;
|
||||
reload();
|
||||
});
|
||||
|
||||
final var playButton =
|
||||
NodeBuilder.button(
|
||||
isConnectionLocal
|
||||
? AppContext.getString("start")
|
||||
: AppContext.getString("connect"),
|
||||
() -> {
|
||||
final var information =
|
||||
new GameInformation(
|
||||
new String[] {player1Name, player2Name},
|
||||
new boolean[] {isPlayer1Human, isPlayer2Human},
|
||||
new int[] {computer1Difficulty, computer2Difficulty},
|
||||
new int[] {computer1ThinkTime, computer2ThinkTime},
|
||||
isConnectionLocal,
|
||||
serverIP,
|
||||
serverPort);
|
||||
|
||||
if (isConnectionLocal) {
|
||||
App.activate(new TicTacToeLayer(information));
|
||||
} else {
|
||||
App.activate(new ConnectedLayer(information));
|
||||
}
|
||||
});
|
||||
|
||||
final Container mainContainer = new VerticalContainer(10);
|
||||
final Container playersContainer = new HorizontalContainer(5);
|
||||
final Container connectionTypeContainer = new HorizontalContainer(10);
|
||||
|
||||
mainContainer.addContainer(playersContainer, true);
|
||||
mainContainer.addContainer(connectionTypeContainer, false);
|
||||
mainContainer.addNodes(playButton);
|
||||
|
||||
connectionTypeContainer.addNodes(connectionTypeText, connectionTypeToggle);
|
||||
|
||||
playersContainer.addContainer(player1Container, true);
|
||||
playersContainer.addNodes(versusText);
|
||||
playersContainer.addContainer(player2Container, true);
|
||||
|
||||
final var backButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("back"),
|
||||
() -> {
|
||||
App.activate(new MainLayer());
|
||||
});
|
||||
|
||||
final Container controlContainer = new VerticalContainer(0);
|
||||
controlContainer.addNodes(backButton);
|
||||
|
||||
addContainer(mainContainer, Pos.CENTER, 0, 0, 75, 75);
|
||||
addContainer(controlContainer, Pos.BOTTOM_LEFT, 2, -2, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
package org.toop.app.layer.layers;
|
||||
|
||||
import java.util.Locale;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Slider;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.layer.Container;
|
||||
import org.toop.app.layer.NodeBuilder;
|
||||
import org.toop.app.layer.Popup;
|
||||
import org.toop.app.layer.containers.VerticalContainer;
|
||||
import org.toop.framework.asset.resources.SettingsAsset;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.local.AppContext;
|
||||
import org.toop.local.AppSettings;
|
||||
|
||||
public final class OptionsPopup extends Popup {
|
||||
AppSettings appSettings = new AppSettings();
|
||||
SettingsAsset settings = appSettings.getPath();
|
||||
private boolean isWindowed = !(settings.getFullscreen());
|
||||
|
||||
public OptionsPopup() {
|
||||
super(true, "bg-primary");
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
popAll();
|
||||
|
||||
final var languageHeader = NodeBuilder.header(AppContext.getString("language"));
|
||||
final var languageSeparator = NodeBuilder.separator();
|
||||
|
||||
final var volumeHeader = NodeBuilder.header(AppContext.getString("volume"));
|
||||
final var volumeSeparator = NodeBuilder.separator();
|
||||
|
||||
final var fxVolumeHeader = NodeBuilder.header(AppContext.getString("effectsVolume"));
|
||||
final var fxVolumeSeparator = NodeBuilder.separator();
|
||||
|
||||
final var musicVolumeHeader = NodeBuilder.header(AppContext.getString("musicVolume"));
|
||||
final var musicVolumeSeparator = NodeBuilder.separator();
|
||||
|
||||
final var themeHeader = NodeBuilder.header(AppContext.getString("theme"));
|
||||
final var themeSeparator = NodeBuilder.separator();
|
||||
|
||||
final var layoutSizeHeader = NodeBuilder.header(AppContext.getString("layoutSize"));
|
||||
final var layoutSizeSeparator = NodeBuilder.separator();
|
||||
|
||||
final var optionsContainer = new VerticalContainer(5);
|
||||
optionsContainer.addNodes(languageHeader, languageChoiceBox(), languageSeparator);
|
||||
optionsContainer.addNodes(volumeHeader, volumeSlider(), volumeSeparator);
|
||||
optionsContainer.addNodes(fxVolumeHeader, fxVolumeSlider(), fxVolumeSeparator);
|
||||
optionsContainer.addNodes(musicVolumeHeader, musicVolumeSlider(), musicVolumeSeparator);
|
||||
optionsContainer.addNodes(themeHeader, themeChoiceBox(), themeSeparator);
|
||||
optionsContainer.addNodes(layoutSizeHeader, layoutSizeChoiceBox(), layoutSizeSeparator);
|
||||
optionsContainer.addNodes(fullscreenToggle());
|
||||
|
||||
final Container mainContainer = new VerticalContainer(50, "");
|
||||
mainContainer.addContainer(optionsContainer, true);
|
||||
|
||||
final var backButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("back"),
|
||||
() -> {
|
||||
App.pop();
|
||||
});
|
||||
|
||||
final Container controlContainer = new VerticalContainer(5);
|
||||
controlContainer.addNodes(backButton);
|
||||
|
||||
addContainer(mainContainer, Pos.CENTER, 0, 0, 0, 0);
|
||||
addContainer(controlContainer, Pos.BOTTOM_LEFT, 2, -2, 0, 0);
|
||||
}
|
||||
|
||||
private ChoiceBox<Locale> languageChoiceBox() {
|
||||
assert AppContext.getLocalization() != null;
|
||||
|
||||
final ChoiceBox<Locale> languageChoiceBox =
|
||||
NodeBuilder.choiceBox(
|
||||
(locale) -> {
|
||||
if (locale == AppContext.getLocale()) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings.setLocale(locale.toString());
|
||||
AppContext.setLocale(locale);
|
||||
|
||||
App.reloadAll();
|
||||
});
|
||||
|
||||
languageChoiceBox.setConverter(
|
||||
new javafx.util.StringConverter<>() {
|
||||
@Override
|
||||
public String toString(Locale locale) {
|
||||
return AppContext.getString(locale.getDisplayName().toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
languageChoiceBox.getItems().addAll(AppContext.getLocalization().getAvailableLocales());
|
||||
languageChoiceBox.setValue(AppContext.getLocale());
|
||||
|
||||
return languageChoiceBox;
|
||||
}
|
||||
|
||||
private Slider volumeSlider() {
|
||||
return NodeBuilder.slider(
|
||||
100,
|
||||
settings.getVolume(),
|
||||
(volume) -> {
|
||||
settings.setVolume(volume);
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeVolume(volume.doubleValue()))
|
||||
.asyncPostEvent();
|
||||
});
|
||||
}
|
||||
|
||||
private Slider fxVolumeSlider() {
|
||||
return NodeBuilder.slider(
|
||||
100,
|
||||
settings.getFxVolume(),
|
||||
(volume) -> {
|
||||
settings.setFxVolume(volume);
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeFxVolume(volume.doubleValue()))
|
||||
.asyncPostEvent();
|
||||
});
|
||||
}
|
||||
|
||||
private Slider musicVolumeSlider() {
|
||||
return NodeBuilder.slider(
|
||||
100,
|
||||
settings.getMusicVolume(),
|
||||
(volume) -> {
|
||||
settings.setMusicVolume(volume);
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeMusicVolume(volume.doubleValue()))
|
||||
.asyncPostEvent();
|
||||
});
|
||||
}
|
||||
|
||||
private Label fullscreenToggle() {
|
||||
return NodeBuilder.toggle(
|
||||
AppContext.getString("windowed"),
|
||||
AppContext.getString("fullscreen"),
|
||||
!isWindowed,
|
||||
(fullscreen) -> {
|
||||
isWindowed = !fullscreen;
|
||||
|
||||
settings.setFullscreen(fullscreen);
|
||||
App.setFullscreen(fullscreen);
|
||||
});
|
||||
}
|
||||
|
||||
private ChoiceBox<String> themeChoiceBox() {
|
||||
final ChoiceBox<String> themeChoiceBox =
|
||||
NodeBuilder.choiceBox(
|
||||
(theme) -> {
|
||||
if (theme.equalsIgnoreCase(settings.getTheme())) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings.setTheme(theme);
|
||||
App.setStyle(theme, settings.getLayoutSize());
|
||||
});
|
||||
|
||||
themeChoiceBox.setConverter(
|
||||
new javafx.util.StringConverter<>() {
|
||||
@Override
|
||||
public String toString(String theme) {
|
||||
return AppContext.getString(theme);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
themeChoiceBox.getItems().addAll("dark", "light", "dark-hc", "light-hc");
|
||||
themeChoiceBox.setValue(settings.getTheme());
|
||||
|
||||
return themeChoiceBox;
|
||||
}
|
||||
|
||||
private ChoiceBox<String> layoutSizeChoiceBox() {
|
||||
final ChoiceBox<String> layoutSizeChoiceBox =
|
||||
NodeBuilder.choiceBox(
|
||||
(layoutSize) -> {
|
||||
if (layoutSize.equalsIgnoreCase(settings.getLayoutSize())) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings.setLayoutSize(layoutSize);
|
||||
App.setStyle(settings.getTheme(), layoutSize);
|
||||
});
|
||||
|
||||
layoutSizeChoiceBox.setConverter(
|
||||
new javafx.util.StringConverter<>() {
|
||||
@Override
|
||||
public String toString(String layoutSize) {
|
||||
return AppContext.getString(layoutSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
layoutSizeChoiceBox.getItems().addAll("small", "medium", "large");
|
||||
layoutSizeChoiceBox.setValue(settings.getLayoutSize());
|
||||
|
||||
return layoutSizeChoiceBox;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package org.toop.app.layer.layers;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.layer.Container;
|
||||
import org.toop.app.layer.NodeBuilder;
|
||||
import org.toop.app.layer.Popup;
|
||||
import org.toop.app.layer.containers.HorizontalContainer;
|
||||
import org.toop.app.layer.containers.VerticalContainer;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
public final class QuitPopup extends Popup {
|
||||
public QuitPopup() {
|
||||
super(true);
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
popAll();
|
||||
|
||||
final var sureText = NodeBuilder.header(AppContext.getString("quitSure"));
|
||||
|
||||
final var yesButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("yes"),
|
||||
() -> {
|
||||
App.quit();
|
||||
});
|
||||
|
||||
final var noButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("no"),
|
||||
() -> {
|
||||
App.pop();
|
||||
});
|
||||
|
||||
final Container controlContainer = new HorizontalContainer(30);
|
||||
controlContainer.addNodes(yesButton, noButton);
|
||||
|
||||
final Container mainContainer = new VerticalContainer(30);
|
||||
mainContainer.addNodes(sureText);
|
||||
mainContainer.addContainer(controlContainer, false);
|
||||
|
||||
addContainer(mainContainer, Pos.CENTER, 0, 0, 30, 30);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package org.toop.app.layer.layers.game;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.layer.Container;
|
||||
import org.toop.app.layer.NodeBuilder;
|
||||
import org.toop.app.layer.Popup;
|
||||
import org.toop.app.layer.containers.VerticalContainer;
|
||||
import org.toop.app.layer.layers.MainLayer;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
public class GameFinishedPopup extends Popup {
|
||||
private final boolean isDraw;
|
||||
private final String winner;
|
||||
|
||||
public GameFinishedPopup(boolean isDraw, String winner) {
|
||||
super(true, "bg-popup");
|
||||
|
||||
this.isDraw = isDraw;
|
||||
this.winner = winner;
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
popAll();
|
||||
|
||||
final Container mainContainer = new VerticalContainer(30);
|
||||
|
||||
if (isDraw) {
|
||||
final var drawHeader = NodeBuilder.header(AppContext.getString("drawText"));
|
||||
final var goodGameText = NodeBuilder.text(AppContext.getString("goodGameText"));
|
||||
|
||||
mainContainer.addNodes(drawHeader, goodGameText);
|
||||
} else {
|
||||
final var winHeader =
|
||||
NodeBuilder.header(AppContext.getString("congratulations") + ": " + winner);
|
||||
final var goodGameText = NodeBuilder.text(AppContext.getString("goodGameText"));
|
||||
|
||||
mainContainer.addNodes(winHeader, goodGameText);
|
||||
}
|
||||
|
||||
final var backToMainMenuButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("backToMainMenu"),
|
||||
() -> {
|
||||
App.activate(new MainLayer());
|
||||
});
|
||||
|
||||
mainContainer.addNodes(backToMainMenuButton);
|
||||
|
||||
addContainer(mainContainer, Pos.CENTER, 0, 0, 30, 30);
|
||||
}
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
package org.toop.app.layer.layers.game;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Text;
|
||||
import org.toop.app.App;
|
||||
import org.toop.app.GameInformation;
|
||||
import org.toop.app.canvas.TicTacToeCanvas;
|
||||
import org.toop.app.layer.Container;
|
||||
import org.toop.app.layer.Layer;
|
||||
import org.toop.app.layer.NodeBuilder;
|
||||
import org.toop.app.layer.containers.HorizontalContainer;
|
||||
import org.toop.app.layer.containers.VerticalContainer;
|
||||
import org.toop.app.layer.layers.MainLayer;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.networking.events.NetworkEvents;
|
||||
import org.toop.game.Game;
|
||||
import org.toop.game.tictactoe.TicTacToe;
|
||||
import org.toop.game.tictactoe.TicTacToeAI;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
public final class TicTacToeLayer extends Layer {
|
||||
private TicTacToeCanvas canvas;
|
||||
|
||||
private AtomicReference<TicTacToe> ticTacToe;
|
||||
private TicTacToeAI ticTacToeAI;
|
||||
|
||||
private GameInformation information;
|
||||
|
||||
private final Text currentPlayerNameText;
|
||||
private final Text currentPlayerMoveText;
|
||||
|
||||
private final BlockingQueue<Game.Move> playerMoveQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
// Todo: set these from the server
|
||||
private char currentPlayerMove = Game.EMPTY;
|
||||
private String player2Name = "";
|
||||
|
||||
final AtomicBoolean firstPlayerIsMe = new AtomicBoolean(true);
|
||||
|
||||
public TicTacToeLayer(GameInformation information) {
|
||||
super("bg-primary");
|
||||
|
||||
canvas =
|
||||
new TicTacToeCanvas(
|
||||
Color.LIME,
|
||||
(App.getHeight() / 100) * 75,
|
||||
(App.getHeight() / 100) * 75,
|
||||
(cell) -> {
|
||||
try {
|
||||
if (information.isConnectionLocal()) {
|
||||
if (ticTacToe.get().getCurrentTurn() == 0) {
|
||||
playerMoveQueue.put(new Game.Move(cell, 'X'));
|
||||
} else {
|
||||
playerMoveQueue.put(new Game.Move(cell, 'O'));
|
||||
}
|
||||
} else {
|
||||
if (information.isPlayerHuman()[0]
|
||||
&& currentPlayerMove != Game.EMPTY) {
|
||||
playerMoveQueue.put(
|
||||
new Game.Move(
|
||||
cell, firstPlayerIsMe.get() ? 'X' : 'O'));
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException _) {
|
||||
}
|
||||
});
|
||||
|
||||
ticTacToe = new AtomicReference<>(new TicTacToe());
|
||||
ticTacToeAI = new TicTacToeAI();
|
||||
|
||||
this.information = information;
|
||||
|
||||
if (information.isConnectionLocal()) {
|
||||
new Thread(this::localGameThread).start();
|
||||
}
|
||||
|
||||
currentPlayerNameText = NodeBuilder.header("");
|
||||
currentPlayerMoveText = NodeBuilder.header("");
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
public TicTacToeLayer(GameInformation information, long clientID) {
|
||||
this(information);
|
||||
|
||||
Thread a = new Thread(this::serverGameThread);
|
||||
a.setDaemon(false);
|
||||
a.start();
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
popAll();
|
||||
|
||||
canvas.resize((App.getHeight() / 100) * 75, (App.getHeight() / 100) * 75);
|
||||
|
||||
for (int i = 0; i < ticTacToe.get().board.length; i++) {
|
||||
final char value = ticTacToe.get().board[i];
|
||||
|
||||
if (value == 'X') {
|
||||
canvas.drawX(Color.RED, i);
|
||||
} else if (value == 'O') {
|
||||
canvas.drawO(Color.BLUE, i);
|
||||
}
|
||||
}
|
||||
|
||||
final var backButton =
|
||||
NodeBuilder.button(
|
||||
AppContext.getString("back"),
|
||||
() -> {
|
||||
App.activate(new MainLayer());
|
||||
});
|
||||
|
||||
final Container controlContainer = new VerticalContainer(5);
|
||||
controlContainer.addNodes(backButton);
|
||||
|
||||
final Container informationContainer = new HorizontalContainer(15);
|
||||
informationContainer.addNodes(currentPlayerNameText, currentPlayerMoveText);
|
||||
|
||||
addContainer(controlContainer, Pos.BOTTOM_LEFT, 2, -2, 0, 0);
|
||||
addContainer(informationContainer, Pos.TOP_LEFT, 2, 2, 0, 0);
|
||||
addGameCanvas(canvas, Pos.CENTER, 0, 0);
|
||||
}
|
||||
|
||||
private int compurterDifficultyToDepth(int maxDifficulty, int difficulty) {
|
||||
return (int) (((float) maxDifficulty / difficulty) * 9);
|
||||
}
|
||||
|
||||
private void localGameThread() {
|
||||
boolean running = true;
|
||||
|
||||
while (running) {
|
||||
final int currentPlayer = ticTacToe.get().getCurrentTurn();
|
||||
|
||||
currentPlayerNameText.setText(information.playerName()[currentPlayer]);
|
||||
currentPlayerMoveText.setText(ticTacToe.get().getCurrentTurn() == 0 ? "X" : "O");
|
||||
|
||||
Game.Move move = null;
|
||||
|
||||
if (information.isPlayerHuman()[currentPlayer]) {
|
||||
try {
|
||||
final Game.Move wants = playerMoveQueue.take();
|
||||
final Game.Move[] legalMoves = ticTacToe.get().getLegalMoves();
|
||||
|
||||
for (final Game.Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == wants.position()
|
||||
&& legalMove.value() == wants.value()) {
|
||||
move = wants;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException _) {
|
||||
}
|
||||
} else {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
move =
|
||||
ticTacToeAI.findBestMove(
|
||||
ticTacToe.get(),
|
||||
compurterDifficultyToDepth(
|
||||
10, information.computerDifficulty()[currentPlayer]));
|
||||
|
||||
if (information.computerThinkTime()[currentPlayer] > 0) {
|
||||
final long elapsedTime = System.currentTimeMillis() - start;
|
||||
final long sleepTime =
|
||||
information.computerThinkTime()[currentPlayer] * 1000L - elapsedTime;
|
||||
|
||||
try {
|
||||
Thread.sleep(sleepTime);
|
||||
} catch (InterruptedException _) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (move == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Game.State state = ticTacToe.get().play(move);
|
||||
|
||||
if (move.value() == 'X') {
|
||||
canvas.drawX(Color.RED, move.position());
|
||||
} else if (move.value() == 'O') {
|
||||
canvas.drawO(Color.BLUE, move.position());
|
||||
}
|
||||
|
||||
if (state != Game.State.NORMAL) {
|
||||
if (state == Game.State.WIN) {
|
||||
App.push(
|
||||
new GameFinishedPopup(
|
||||
false,
|
||||
information.playerName()[ticTacToe.get().getCurrentTurn()]));
|
||||
} else if (state == Game.State.DRAW) {
|
||||
App.push(new GameFinishedPopup(true, ""));
|
||||
}
|
||||
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void serverGameThread() {
|
||||
new EventFlow()
|
||||
.listen(this::handleServerGameStart) // <-----------
|
||||
.listen(this::yourTurnResponse)
|
||||
.listen(this::onMoveResponse)
|
||||
.listen(this::handleReceivedMessage);
|
||||
}
|
||||
|
||||
private void handleServerGameStart(NetworkEvents.GameMatchResponse resp) {
|
||||
// Meneer Bas de Jong. Dit functie wordt niet aangeroepen als je de challenger bent.
|
||||
// Ik heb veel dingen geprobeert. FUCKING veel dingen. Hij doet het niet.
|
||||
// Ik heb zelfs in jou code gekeken en unsubscribeAfterSuccess op false gezet. (zie
|
||||
// ConnectedLayer).
|
||||
// Alle andere functies worden wel gecalt. Behalve dit.
|
||||
|
||||
// Ben jij gehandicapt of ik? Want het moet 1 van de 2 zijn. Ik ben dit al 2 uur aan het
|
||||
// debuggen.
|
||||
// Ik ga nu slapen (04:46).
|
||||
|
||||
// ⠀⠀⠀⠀⠀⠀⣀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⢀⣴⣿⣿⠿⣟⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⢸⣏⡏⠀⠀⠀⢣⢻⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⢸⣟⠧⠤⠤⠔⠋⠀⢿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⠀⣿⡆⠀⠀⠀⠀⠀⠸⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⠀⠘⣿⡀⢀⣶⠤⠒⠀⢻⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⠀⠀⢹⣧⠀⠀⠀⠀⠀⠈⢿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⠀⠀⠀⣿⡆⠀⠀⠀⠀⠀⠈⢿⣆⣠⣤⣤⣤⣤⣴⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⠀⢀⣾⢿⢿⠀⠀⠀⢀⣀⣀⠘⣿⠋⠁⠀⠙⢇⠀⠀⠙⢿⣦⡀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⢀⣾⢇⡞⠘⣧⠀⢖⡭⠞⢛⡄⠘⣆⠀⠀⠀⠈⢧⠀⠀⠀⠙⢿⣄⠀⠀⠀⠀
|
||||
// ⠀⠀⣠⣿⣛⣥⠤⠤⢿⡄⠀⠀⠈⠉⠀⠀⠹⡄⠀⠀⠀⠈⢧⠀⠀⠀⠈⠻⣦⠀⠀⠀
|
||||
// ⠀⣼⡟⡱⠛⠙⠀⠀⠘⢷⡀⠀⠀⠀⠀⠀⠀⠹⡀⠀⠀⠀⠈⣧⠀⠀⠀⠀⠹⣧⡀⠀
|
||||
// ⢸⡏⢠⠃⠀⠀⠀⠀⠀⠀⢳⡀⠀⠀⠀⠀⠀⠀⢳⡀⠀⠀⠀⠘⣧⠀⠀⠀⠀⠸⣷⡀
|
||||
// ⠸⣧⠘⡇⠀⠀⠀⠀⠀⠀⠀⢳⡀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⢹⡇⠀⠀⠀⠀⣿⠇
|
||||
// ⠀⣿⡄⢳⠀⠀⠀⠀⠀⠀⠀⠈⣷⠀⠀⠀⠀⠀⠀⠈⠆⠀⠀⠀⠀⠀⠀⠀⠀⣼⡟⠀
|
||||
// ⠀⢹⡇⠘⣇⠀⠀⠀⠀⠀⠀⠰⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡄⠀⣼⡟⠀⠀
|
||||
// ⠀⢸⡇⠀⢹⡆⠀⠀⠀⠀⠀⠀⠙⠁⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⢳⣼⠟⠀⠀⠀
|
||||
// ⠀⠸⣧⣀⠀⢳⡀⠀⠀⠀⠀⠀⠀⠀⡄⠀⠀⠀⠀⠀⠀⠀⢃⠀⢀⣴⡿⠁⠀⠀⠀⠀
|
||||
// ⠀⠀⠈⠙⢷⣄⢳⡀⠀⠀⠀⠀⠀⠀⢳⡀⠀⠀⠀⠀⠀⣠⡿⠟⠛⠉⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⠀⠈⠻⢿⣷⣦⣄⣀⣀⣠⣤⠾⠷⣦⣤⣤⡶⠟⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
// ⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||
|
||||
player2Name = resp.opponent();
|
||||
System.out.println(player2Name);
|
||||
|
||||
currentPlayerMoveText.setText("X");
|
||||
|
||||
if (!resp.playerToMove().equalsIgnoreCase(resp.opponent())) {
|
||||
currentPlayerNameText.setText(information.playerName()[0]);
|
||||
firstPlayerIsMe.set(true);
|
||||
|
||||
System.out.printf("I am starting: My client id is %d\n", resp.clientId());
|
||||
} else {
|
||||
currentPlayerNameText.setText(player2Name);
|
||||
firstPlayerIsMe.set(false);
|
||||
|
||||
System.out.printf("I am NOT starting: My client id is %d\n", resp.clientId());
|
||||
}
|
||||
}
|
||||
|
||||
private void onMoveResponse(NetworkEvents.GameMoveResponse resp) {
|
||||
char playerChar;
|
||||
|
||||
if (!resp.player().equalsIgnoreCase(player2Name)) {
|
||||
playerChar = firstPlayerIsMe.get() ? 'X' : 'O';
|
||||
} else {
|
||||
playerChar = firstPlayerIsMe.get() ? 'O' : 'X';
|
||||
}
|
||||
|
||||
final Game.Move move = new Game.Move(Integer.parseInt(resp.move()), playerChar);
|
||||
final Game.State state = ticTacToe.get().play(move);
|
||||
|
||||
if (state
|
||||
!= Game.State.NORMAL) { // todo differentiate between future draw guaranteed and is
|
||||
// currently a draw
|
||||
if (state == Game.State.WIN) {
|
||||
App.push(
|
||||
new GameFinishedPopup(
|
||||
false, information.playerName()[ticTacToe.get().getCurrentTurn()]));
|
||||
} else if (state == Game.State.DRAW) {
|
||||
App.push(new GameFinishedPopup(true, ""));
|
||||
}
|
||||
}
|
||||
|
||||
if (move.value() == 'X') {
|
||||
canvas.drawX(Color.RED, move.position());
|
||||
} else if (move.value() == 'O') {
|
||||
canvas.drawO(Color.BLUE, move.position());
|
||||
}
|
||||
|
||||
currentPlayerNameText.setText(
|
||||
ticTacToe.get().getCurrentTurn() == (firstPlayerIsMe.get() ? 0 : 1)
|
||||
? information.playerName()[0]
|
||||
: player2Name);
|
||||
currentPlayerMoveText.setText(ticTacToe.get().getCurrentTurn() == 0 ? "X" : "O");
|
||||
}
|
||||
|
||||
private void yourTurnResponse(NetworkEvents.YourTurnResponse response) {
|
||||
int position = -1;
|
||||
|
||||
if (information.isPlayerHuman()[0]) {
|
||||
try {
|
||||
position = playerMoveQueue.take().position();
|
||||
} catch (InterruptedException _) {
|
||||
}
|
||||
} else {
|
||||
final Game.Move move =
|
||||
ticTacToeAI.findBestMove(
|
||||
ticTacToe.get(),
|
||||
compurterDifficultyToDepth(10, information.computerDifficulty()[0]));
|
||||
|
||||
position = move.position();
|
||||
}
|
||||
|
||||
new EventFlow()
|
||||
.addPostEvent(new NetworkEvents.SendMove(response.clientId(), (short) position))
|
||||
.postEvent();
|
||||
}
|
||||
|
||||
private void handleReceivedMessage(NetworkEvents.ReceivedMessage msg) {
|
||||
System.out.println("Received Message: " + msg.message()); // todo add chat window
|
||||
}
|
||||
}
|
||||
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,19 +1,34 @@
|
||||
package org.toop.local;
|
||||
|
||||
import java.util.Locale;
|
||||
import org.toop.framework.asset.ResourceManager;
|
||||
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||
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 final LocalizationAsset localization = ResourceManager.get("localization");
|
||||
private static Locale locale = Locale.forLanguageTag("en");
|
||||
|
||||
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() {
|
||||
@@ -22,6 +37,31 @@ public class AppContext {
|
||||
|
||||
public static String getString(String key) {
|
||||
assert localization != null;
|
||||
return localization.getString(key, locale);
|
||||
|
||||
// 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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +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;
|
||||
import org.toop.app.App;
|
||||
import org.toop.framework.asset.resources.SettingsAsset;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.framework.settings.Settings;
|
||||
|
||||
public class AppSettings {
|
||||
private static SettingsAsset settingsAsset;
|
||||
|
||||
private SettingsAsset settingsAsset;
|
||||
public static void applySettings() {
|
||||
settingsAsset = getPath();
|
||||
if (!settingsAsset.isLoaded()) {
|
||||
settingsAsset.load();
|
||||
}
|
||||
|
||||
public void applySettings() {
|
||||
SettingsAsset settings = getPath();
|
||||
if (!settings.isLoaded()) {
|
||||
settings.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();
|
||||
}
|
||||
Settings settingsData = settings.getContent();
|
||||
|
||||
AppContext.setLocale(Locale.of(settingsData.locale));
|
||||
App.setFullscreen(settingsData.fullScreen);
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.volume))
|
||||
.asyncPostEvent();
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeFxVolume(settingsData.fxVolume))
|
||||
.asyncPostEvent();
|
||||
new EventFlow()
|
||||
.addPostEvent(new AudioEvents.ChangeMusicVolume(settingsData.musicVolume))
|
||||
.asyncPostEvent();
|
||||
App.setStyle(settingsAsset.getTheme(), settingsAsset.getLayoutSize());
|
||||
}
|
||||
|
||||
public SettingsAsset getPath() {
|
||||
if (this.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);
|
||||
}
|
||||
return this.settingsAsset;
|
||||
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/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,52 +1,88 @@
|
||||
accept=\u0642\u0628\u0648\u0644
|
||||
ai=\u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0635\u0646\u0627\u0639\u064a
|
||||
appTitle=\u0645\u062e\u062a\u0627\u0631 \u0623\u0644\u0639\u0627\u0628 ISY
|
||||
back=\u0631\u062c\u0648\u0639
|
||||
backToMainMenu=\u0627\u0644\u0639\u0648\u062F\u0629 \u0625\u0644\u0649 \u0627\u0644\u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629
|
||||
computer=\u0627\u0644\u062d\u0627\u0633\u0648\u0628
|
||||
computerDifficulty=\u0635\u0639\u0648\u0628\u0629 \u0627\u0644\u062d\u0627\u0633\u0648\u0628
|
||||
computerThinkTime=\u0632\u0645\u0646 \u062a\u0641\u0643\u064a\u0631 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631
|
||||
congratulations=\u0645\u0628\u0631\u0648\u0643
|
||||
connect=\u0627\u062a\u0635\u0644
|
||||
connectionType=\u0646\u0648\u0639 \u0627\u0644\u0627\u062A\u0635\u0627\u0644
|
||||
credits=\u0627\u0644\u0634\u0643\u0631 \u0648\u0627\u0644\u062a\u0642\u062f\u064a\u0631
|
||||
dark-hc=\u063A\u0627\u0645\u0642 (\u062A\u0646\u0627\u0642\u0636 \u0639\u0627\u0644\u064D)
|
||||
dark=\u063A\u0627\u0645\u0642
|
||||
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
|
||||
drawText=\u0627\u0646\u062A\u0647\u062A \u0627\u0644\u0644\u0639\u0628\u0629 \u0628\u062A\u0639\u0627\u062F\u0644
|
||||
effectsVolume=\u062d\u062c\u0645 \u0627\u0644\u062a\u0623\u062b\u064a\u0631\u0627\u062a
|
||||
musicVolume=Music Volume (translate me)
|
||||
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
|
||||
goodGameText=\u0644\u0639\u0628\u0629 \u0631\u0627\u0626\u0639\u0629. \u0623\u062D\u0633\u0646\u062A.
|
||||
human=\u0627\u0644\u0625\u0646\u0633\u0627\u0646
|
||||
language=\u0627\u0644\u0644\u063a\u0629
|
||||
large=\u0643\u0628\u064A\u0631
|
||||
layoutSize=\u062D\u062C\u0645 \u0627\u0644\u062A\u0635\u0645\u064A\u0645
|
||||
light-hc=\u0641\u0627\u062A\u062D (\u062A\u0646\u0627\u0642\u0636 \u0639\u0627\u0644\u064D)
|
||||
light=\u0641\u0627\u062A\u062D
|
||||
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\u0648\u0645\u064a\u0645 \u0627\u0644\u0644\u063a\u0629
|
||||
medium=\u0645\u062A\u0648\u0633\u0637
|
||||
mergeCommander=\u0642\u0627\u0626\u062f \u0627\u0644\u062f\u0645\u062c
|
||||
moralSupport=\u062f\u0639\u0645 \u0645\u0639\u0646\u0648\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=\u0627\u0644\u062e\u064a\u0627\u0631\u0627\u062a
|
||||
othello=\u0623\u0648\u062a\u064a\u0644\u0648
|
||||
playerName=\u0627\u0633\u0645 \u0627\u0644\u0644\u0627\u0639\u0628
|
||||
productOwner=\u0645\u0627\u0644\u0643 \u0627\u0644\u0645\u0646\u062a\u062c
|
||||
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
|
||||
quitSure=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f\u061f
|
||||
scrumMaster=\u0645\u062f\u064a\u0631 \u0627\u0644\u0633\u0643\u0631\u0645
|
||||
server=\u062e\u0627\u062f\u0645
|
||||
serverIP=IP \u0627\u0644\u062e\u0627\u062f\u0645
|
||||
serverPort=\u0645\u0646\u0641\u0630 \u0627\u0644\u062e\u0627\u062f\u0645
|
||||
small=\u0635\u063A\u064A\u0631
|
||||
start=\u0627\u0628\u062f\u0623
|
||||
theme=\u0627\u0644\u0645\u0648\u0636\u0648\u0639
|
||||
tictactoe=\u062a\u064a\u0643 \u062a\u0627\u0643 \u062a\u0648
|
||||
volume=\u0627\u0644\u062d\u062c\u0645 \u0627\u0644\u0631\u0626\u064a\u0633\u064a
|
||||
windowed=\u0646\u0627\u0641\u0630\u064a
|
||||
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)
|
||||
|
||||
@@ -1,52 +1,90 @@
|
||||
accept=Akzeptieren
|
||||
ai=K\u00fcnstliche Intelligenz
|
||||
appTitle=ISY Spieleauswahl
|
||||
app-title=ISY Spiele-Auswahl
|
||||
are-you-sure=Sind Sie sicher?
|
||||
back=Zur\u00fcck
|
||||
backToMainMenu=Zur\u00FCck zum Hauptmen\u00FC
|
||||
cancel=Abbrechen
|
||||
challenge=Herausforderung
|
||||
computer-difficulty=Computer Schwierigkeit
|
||||
computer-think-time=Computer Denkzeit
|
||||
computer=Computer
|
||||
computerDifficulty=Computerschwierigkeit
|
||||
computerThinkTime=Computer Denkzeit
|
||||
congratulations=Gl\u00FCckwunsch
|
||||
connect=Verbinden
|
||||
connectionType=Verbindungstyp
|
||||
connect4=Connect 4
|
||||
|
||||
credits=Credits
|
||||
dark-hc=Dunkel (Hoher Kontrast)
|
||||
dark=Dunkel
|
||||
deny=Ablehnen
|
||||
developers=Entwickler
|
||||
drawText=Das Spiel endete unentschieden
|
||||
effectsVolume=Effektlautst\u00e4rke
|
||||
musicVolume=Music Volume (translate me)
|
||||
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
|
||||
goodGameText=Gutes Spiel. Gut gespielt.
|
||||
human=Mensch
|
||||
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
|
||||
layoutSize=Layout-Gr\u00F6\u00DFe
|
||||
light-hc=Hell (Hoher Kontrast)
|
||||
large=Gro\u00df
|
||||
layout-size=Layout-Gr\u00f6\u00dfe
|
||||
light=Hell
|
||||
local=Lokal
|
||||
localization=Lokalisierung
|
||||
master-volume=Gesamtlautst\u00e4rke
|
||||
medium=Mittel
|
||||
mergeCommander=Merge-Kommandant
|
||||
moralSupport=Mentale Unterst\u00fctzung
|
||||
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
|
||||
othello=Othello
|
||||
playerName=Spielername
|
||||
productOwner=Produktverantwortlicher
|
||||
play=Spielen
|
||||
player-name=Spielername
|
||||
player=Spieler
|
||||
please-enter-your-name=Bitte geben Sie Ihren Namen ein
|
||||
port=Port
|
||||
product-owner=Produktverantwortlicher
|
||||
quit=Beenden
|
||||
quitSure=Bist du dir sicher?
|
||||
scrumMaster=Scrum Master
|
||||
server=Server
|
||||
serverIP=Server-IP
|
||||
serverPort=Server-Port
|
||||
reversi=Reversi
|
||||
scrum-master=Scrum Master
|
||||
send=Senden
|
||||
server-information=Serverinformationen
|
||||
small=Klein
|
||||
start=Start
|
||||
style=Stil
|
||||
the-game-ended-in-a-draw=Das Spiel endete unentschieden
|
||||
theme=Thema
|
||||
tictactoe=Tic Tac Toe
|
||||
volume=Hauptlautst<EFBFBD>rke
|
||||
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?
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,56 +1,92 @@
|
||||
accept=Accept
|
||||
ai=Artificial Intelligence
|
||||
appTitle=ISY Games Selector
|
||||
app-title=ISY Games Selector
|
||||
are-you-sure=Are you sure?
|
||||
back=Back
|
||||
backToMainMenu=Back to main menu
|
||||
challengeText=You were challenged by
|
||||
cancel=Cancel
|
||||
challenge=Challenge
|
||||
computer-difficulty=Computer difficulty
|
||||
computer-think-time=Computer think time
|
||||
computer=Computer
|
||||
computerDifficulty=Computer Difficulty
|
||||
computerThinkTime=Computer Think Time
|
||||
congratulations=Congratulations
|
||||
connect=Connect
|
||||
connectionType=Connection Type
|
||||
credits=Credits
|
||||
dark=Dark
|
||||
dark-hc=Dark (High Contrast)
|
||||
deny=Deny
|
||||
developers=Developers
|
||||
drawText=The game ended in a draw
|
||||
effectsVolume=Effects Volume
|
||||
musicVolume=Music Volume
|
||||
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
|
||||
gameIsText=To a game of
|
||||
goodGameText=Good game. Well played.
|
||||
human=Human
|
||||
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
|
||||
layoutSize=Layout Size
|
||||
layout-size=Layout Size
|
||||
light=Light
|
||||
light-hc=Light (High Contrast)
|
||||
local=Local
|
||||
localization=Localization
|
||||
master-volume=Master Volume
|
||||
medium=Medium
|
||||
mergeCommander=Merge Commander
|
||||
moralSupport=Moral Support
|
||||
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
|
||||
othello=Othello
|
||||
playerName=Player Name
|
||||
productOwner=Product Owner
|
||||
play=Play
|
||||
player-name=Player name
|
||||
player=Player
|
||||
please-enter-your-name=Please enter your name
|
||||
port=Port
|
||||
product-owner=Product Owner
|
||||
quit=Quit
|
||||
quitSure=Are you sure?
|
||||
scrumMaster=Scrum Master
|
||||
server=Server
|
||||
serverIP=Server IP
|
||||
serverPort=Server Port
|
||||
reversi=Reversi
|
||||
scrum-master=Scrum Master
|
||||
send=Send
|
||||
server-information=Server information
|
||||
small=Small
|
||||
start=Start
|
||||
style=Style
|
||||
the-game-ended-in-a-draw=The game ended in a draw
|
||||
theme=Theme
|
||||
tictactoe=Tic Tac Toe
|
||||
volume=Master Volume
|
||||
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)
|
||||
|
||||
@@ -1,52 +1,90 @@
|
||||
accept=Aceptar
|
||||
ai=Inteligencia Artificial
|
||||
appTitle=Selector de Juegos ISY
|
||||
app-title=Selector de Juegos ISY
|
||||
are-you-sure=\u00bfEst\u00e1s seguro?
|
||||
back=Atr\u00e1s
|
||||
backToMainMenu=Volver al men\u00FA principal
|
||||
cancel=Cancelar
|
||||
challenge=Desaf\u00edo
|
||||
computer-difficulty=Dificultad del ordenador
|
||||
computer-think-time=Tiempo de pensamiento del ordenador
|
||||
computer=Ordenador
|
||||
computerDifficulty=Dificultad del Ordenador
|
||||
computerThinkTime=Tiempo de pensamiento de la computadora
|
||||
congratulations=Felicitaciones
|
||||
connect=Conectar
|
||||
connectionType=Tipo de conexi\u00F3n
|
||||
connect4=Connect 4
|
||||
|
||||
credits=Cr\u00e9ditos
|
||||
dark-hc=Oscuro (Alto Contraste)
|
||||
dark=Oscuro
|
||||
deny=Denegar
|
||||
developers=Desarrolladores
|
||||
drawText=El juego termin\u00F3 en empate
|
||||
effectsVolume=Volumen de efectos
|
||||
musicVolume=Music Volume (translate me)
|
||||
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
|
||||
goodGameText=Buen juego. Bien jugado.
|
||||
human=Humano
|
||||
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
|
||||
layoutSize=Tama\u00F1o del dise\u00F1o
|
||||
light-hc=Claro (Alto Contraste)
|
||||
layout-size=Tama\u00f1o de dise\u00f1o
|
||||
light=Claro
|
||||
local=Local
|
||||
localization=Localizaci\u00f3n
|
||||
master-volume=Volumen maestro
|
||||
medium=Mediano
|
||||
mergeCommander=Comandante de Merge
|
||||
moralSupport=Apoyo moral
|
||||
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
|
||||
othello=Othello
|
||||
playerName=Nombre del Jugador
|
||||
productOwner=Propietario del Producto
|
||||
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
|
||||
quitSure=\u00BFAst\u00e1s seguro?
|
||||
scrumMaster=Scrum Master
|
||||
server=Servidor
|
||||
serverIP=Servidor-IP
|
||||
serverPort=Servidor-puerto
|
||||
small=Peque\u00F1o
|
||||
start=Iniciar
|
||||
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
|
||||
tictactoe=Tres en Raya
|
||||
volume=Volumen principal
|
||||
windowed=Ventana
|
||||
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
|
||||
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Ar\u00e1bigo)
|
||||
chinese=\u4e2d\u6587 (Chino)
|
||||
|
||||
@@ -1,52 +1,89 @@
|
||||
accept=Accepter
|
||||
ai=Intelligence Artificielle
|
||||
appTitle=S\u00e9lecteur de Jeux ISY
|
||||
app-title=S\u00c9LECTEUR DE JEUX ISY
|
||||
are-you-sure=\u00cates-vous s\u00fbr ?
|
||||
back=Retour
|
||||
backToMainMenu=Retour au menu principal
|
||||
cancel=Annuler
|
||||
challenge=D\u00e9fi
|
||||
computer-difficulty=Difficult\u00e9 de l'ordinateur
|
||||
computer-think-time=Temps de r\u00e9flexion de l'ordinateur
|
||||
computer=Ordinateur
|
||||
computerDifficulty=Difficult\u00e9 de l'Ordinateur
|
||||
computerThinkTime=Temps de r\u00e9flexion de l'ordinateur
|
||||
congratulations=F\u00E9licitations
|
||||
connect=Connecter
|
||||
connectionType=Type de connexion
|
||||
connect=Connexion
|
||||
connect4=Connect 4
|
||||
|
||||
credits=Cr\u00e9dits
|
||||
dark-hc=Sombre (Contraste \u00E9lev\u00E9)
|
||||
dark=Sombre
|
||||
deny=Refuser
|
||||
developers=D\u00e9veloppeurs
|
||||
drawText=La partie s'est termin\u00E9e par un match nul
|
||||
effectsVolume=Volume des effets
|
||||
musicVolume=Music Volume (translate me)
|
||||
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
|
||||
goodGameText=Bien jou\u00E9. Bonne partie.
|
||||
human=Humain
|
||||
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
|
||||
layoutSize=Taille de la disposition
|
||||
light-hc=Clair (Contraste \u00E9lev\u00E9)
|
||||
layout-size=Format de l'affichage
|
||||
light=Clair
|
||||
local=Local
|
||||
localization=Localisation
|
||||
localization=Traduction
|
||||
master-volume=Volume principal
|
||||
medium=Moyen
|
||||
mergeCommander=Commandant de Merge
|
||||
moralSupport=Soutien moral
|
||||
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
|
||||
othello=Othello
|
||||
playerName=Nom du joueur
|
||||
productOwner=Responsable du produit
|
||||
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
|
||||
quitSure=Es-tu s\u00fbr ?
|
||||
scrumMaster=Scrum Master
|
||||
server=Serveur
|
||||
serverIP=Serveur-IP
|
||||
serverPort=Serveur-Port
|
||||
reversi=Reversi
|
||||
scrum-master=Scrum Master
|
||||
send=Envoyer
|
||||
server-information=Informations du serveur
|
||||
small=Petit
|
||||
start=D\u00e9marrer
|
||||
theme=Th\u00E8me
|
||||
tictactoe=Morpion
|
||||
volume=Volume principal
|
||||
windowed=Fen\u00eatre
|
||||
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
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabe)
|
||||
chinese=\u4e2d\u6587 (Chinois)
|
||||
|
||||
@@ -1,52 +1,89 @@
|
||||
ai=\u092a\u094d\u0930\u0924\u093f\u092a\u094d\u0930\u0923\u093e\u0924\u094d\u092e\u093e\u0928 \u092a\u094d\u0930\u092c\u094d\u0939\u093e\u0935\u0924\u094d\u0924\u093e
|
||||
appTitle=ISY \u0917\u0947\u092e \u0938\u0947\u0932\u0947\u0915\u094d\u091f\u0930
|
||||
back=\u092a\u093f\u091a\u093e\u0932
|
||||
backToMainMenu=\u092E\u0947\u0928 \u092E\u0947\u0928\u0942 \u092A\u0930 \u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0902
|
||||
computer=\u0915\u092e\u092a\u094d\u092f\u0942\u091f\u0930
|
||||
computerDifficulty=\u0915\u092e\u092a\u094d\u092f\u0942\u091f\u0930 \u092a\u094d\u0930\u092f\u093e\u0938
|
||||
computerThinkTime=\u0915\u0902\u092a\u094d\u092f\u0942\u091f\u0930 \u0915\u0940 \u092a\u0930 \u092b\u0930 \u0938\u092e\u092f
|
||||
congratulations=\u092C\u0927\u093E\u0908
|
||||
connect=\u091c\u0942\u0921\u094d\u0921 \u0915\u0930\u0947\u0902
|
||||
connectionType=\u0915\u0928\u0947\u0915\u094D\u0936\u0928 \u0915\u093E \u092A\u094D\u0930\u0915\u093E\u0930
|
||||
credits=\u0916\u094d\u092f\u093e\u0924\u0947
|
||||
dark-hc=\u0915\u093E\u0932\u093E (\u090A\u091A\u094D\u091A \u0915\u0949\u0928\u094D\u091F\u094D\u0930\u093E\u0938\u094D\u091F)
|
||||
dark=\u0915\u093E\u0932\u093E
|
||||
developers=\u0935\u093f\u0915\u0938\u093f\u0915\u0930
|
||||
drawText=\u0916\u0947\u0932 \u091F\u0940\u091A \u092A\u0930 \u0916\u0924\u094D\u092E \u0939\u094B \u0917\u092F\u0940
|
||||
effectsVolume=\u092a\u0631\u094d\u092a\u093e\u0935 \u0935\u094b\u0932\u094d\u092e
|
||||
musicVolume=Music Volume (translate me)
|
||||
fullscreen=\u092a\u0942\u0930\u094d\u0923 \u0938\u0915\u0940\u0928\u093e
|
||||
goodGameText=\u0905\u091A\u094D\u091B\u0940 \u0916\u0947\u0932 \u0925\u0940\u0964 \u091B\u0940 \u0916\u0942\u092C \u0916\u0947\u0932\u093E.
|
||||
human=\u092e\u093e\u0928\u0935
|
||||
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\u0921\u093C\u093E
|
||||
layoutSize=\u0930\u0942\u092A\u0930\u0947\u0916 \u0915\u093E \u0906\u0915\u093E\u0930
|
||||
light-hc=\u091A\u094D\u092E\u092C\u0940\u0932\u093E (\u090A\u091A\u094D\u091A \u0915\u0949\u0928\u094D\u091F\u094D\u0930\u093E\u0938\u094D\u091F)
|
||||
light=\u091A\u094D\u092E\u092C\u0940\u0932\u093E
|
||||
local=\u0938\u094d\u0925\u093e\u0928\u093f\u092f
|
||||
localization=\u0938\u094d\u0925\u093e\u0928\u093f\u092f\u0915\u0930\u0923
|
||||
medium=\u092E\u0927\u094D\u092F\u092E
|
||||
mergeCommander=\u092e\u0930\u094d\u091c \u0915\u092e\u0902\u0921\u0930
|
||||
moralSupport=\u0928\u094d\u092e\u093e\u0928\u093f\u0915 \u0938\u092e\u0930\u094d\u0925\u0928
|
||||
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
|
||||
othello=\u0913\u0925\u0940\u0932\u094b
|
||||
playerName=\u0915\u0941\u0930\u093e\u0930\u0940 \u0928\u093e\u092e
|
||||
productOwner=\u0906\u092f\u0947\u0915\u093e \u092e\u093e\u0932\u093f\u0915
|
||||
quit=\u0938\u094e\u091c\u094d
|
||||
quitSure=\u0915\u094d\u092f\u093e \u0915\u094d\u092f\u093e \u091f\u0940\u091f \u0939\u0948\u0902?
|
||||
scrumMaster=\u0938\u094d\u0915\u094d\u0930\u0941\u092e \u092e\u093e\u0938\u094d\u091f\u0930
|
||||
server=\u0938\u0930\u094d\u0935\u0930
|
||||
serverIP=\u0938\u0930\u094d\u0935\u0930 IP
|
||||
serverPort=\u0938\u0930\u094d\u0935\u0930 \u092a\u094b\u0930\u094d\u091f
|
||||
small=\u091B\u094B\u091F\u093E
|
||||
start=\u092b\u093f\u0930\u0942
|
||||
theme=\u0925\u0940\u092E
|
||||
tictactoe=\u091f\u093f\u0915 \u091f\u0948\u0915 \u091f\u094b
|
||||
volume=\u092e\u0941\u0916\u094d\u092f \u0906\u0935\u093e\u091c
|
||||
windowed=\u0915\u094d\u0930\u094d\u0939 \u092e\u0947\u0902
|
||||
yes=\u0939\u093e\u0907
|
||||
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)
|
||||
|
||||
@@ -1,52 +1,88 @@
|
||||
accept=Accetta
|
||||
ai=Intelligenza Artificiale
|
||||
appTitle=Selettore di Giochi ISY
|
||||
app-title=Selettore di Giochi ISY
|
||||
are-you-sure=Sei sicuro?
|
||||
back=Indietro
|
||||
backToMainMenu=Ritorna al menu principale
|
||||
cancel=Annulla
|
||||
challenge=Sfida
|
||||
computer-difficulty=Difficolt\u00e0 del computer
|
||||
computer-think-time=Tempo di riflessione del computer
|
||||
computer=Computer
|
||||
computerDifficulty=Difficolt\u00e0 del computer
|
||||
computerThinkTime=Tempo di pensiero del computer
|
||||
congratulations=Congratulazioni
|
||||
connect=Connetti
|
||||
connectionType=Tipo di connessione
|
||||
connect4=Connect 4
|
||||
credits=Crediti
|
||||
dark-hc=Scuro (Alto Contrasto)
|
||||
dark=Scuro
|
||||
deny=Nega
|
||||
developers=Sviluppatori
|
||||
drawText=La partita \u00E8 terminata in parit\u00E0
|
||||
effectsVolume=Volume effetti
|
||||
musicVolume=Music Volume (translate me)
|
||||
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
|
||||
goodGameText=Bel gioco. Ben giocato.
|
||||
human=Umano
|
||||
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
|
||||
layoutSize=Dimensione Layout
|
||||
light-hc=Chiaro (Alto Contrasto)
|
||||
layout-size=Dimensione layout
|
||||
light=Chiaro
|
||||
local=Locale
|
||||
localization=Localizzazione
|
||||
master-volume=Volume principale
|
||||
medium=Medio
|
||||
mergeCommander=Comandante di Merge
|
||||
moralSupport=Supporto morale
|
||||
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
|
||||
othello=Othello
|
||||
playerName=Nome del giocatore
|
||||
productOwner=Proprietario del prodotto
|
||||
quit=Uscire
|
||||
quitSure=Sei sicuro?
|
||||
scrumMaster=Scrum Master
|
||||
server=Server
|
||||
serverIP=Server-IP
|
||||
serverPort=Porta del server
|
||||
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
|
||||
start=Inizia
|
||||
style=Stile
|
||||
the-game-ended-in-a-draw=La partita \u00e8 terminata in parit\u00e0
|
||||
theme=Tema
|
||||
tictactoe=Tic Tac Toe
|
||||
volume=Volume principale
|
||||
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
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabo)
|
||||
chinese=\u4e2d\u6587 (Cinese)
|
||||
|
||||
@@ -1,52 +1,88 @@
|
||||
ai=\u4eba\u5de5\u77e5\u80fd
|
||||
appTitle=ISY \u30b2\u30fc\u30e0\u30bb\u30ec\u30af\u30bf\u30fc
|
||||
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
|
||||
backToMainMenu=\u30E1\u30A4\u30F3\u30E1\u30CB\u30E5\u30FC\u306B\u623B\u308B
|
||||
computer=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc
|
||||
computerDifficulty=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc\u96e3\u6613\u5ea6
|
||||
computerThinkTime=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u306e\u8003\u3048\u6642\u9593
|
||||
congratulations=\u304A\u3081\u3067\u3068\u3046\u3054\u3056\u3044\u307E\u3059
|
||||
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
|
||||
connectionType=\u63A5\u7D9A\u30BF\u30A4\u30D7
|
||||
connect4=Connect 4
|
||||
credits=\u30af\u30ec\u30b8\u30c3\u30c8
|
||||
dark-hc=\u30C0\u30FC\u30AF (\u9AD8\u30B3\u30F3\u30C8\u30E9\u30B9\u30C8)
|
||||
dark=\u30C0\u30FC\u30AF
|
||||
dark=\u30c0\u30fc\u30af
|
||||
deny=\u62d2\u5426
|
||||
developers=\u958b\u767a\u8005
|
||||
drawText=\u30B2\u30FC\u30E0\u306F\u5E73\u7B49\u306B\u7D42\u4E86\u3057\u307E\u3057\u305F
|
||||
effectsVolume=\u30a8\u30d5\u30a7\u30af\u30c8\u30dc\u30ea\u30e5\u30fc\u30e0
|
||||
musicVolume=Music Volume (translate me)
|
||||
fullscreen=\u5168\u753b\u9762
|
||||
goodGameText=\u3044\u3044\u30B2\u30FC\u30E0\u3067\u3057\u305F\u3002\u3088\u304F\u6226\u3044\u307E\u3057\u305F\u3002
|
||||
human=\u4eba\u9593
|
||||
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
|
||||
layoutSize=\u30EC\u30A4\u30A2\u30A6\u30C8\u30B5\u30A4\u30BA
|
||||
light-hc=\u30E9\u30A4\u30C8 (\u9AD8\u30B3\u30F3\u30C8\u30E9\u30B9\u30C8)
|
||||
light=\u30E9\u30A4\u30C8
|
||||
local=\u5730\u57df
|
||||
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
|
||||
medium=\u4E2D
|
||||
mergeCommander=\u30de\u30fc\u30b8\u30b3\u30de\u30f3\u30c0\u30fc
|
||||
moralSupport=\u6c17\u529b\u652f\u63f4
|
||||
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
|
||||
othello=\u30aa\u30bb\u30ed
|
||||
playerName=\u30d7\u30ec\u30a4\u30e4\u30fc\u540d
|
||||
productOwner=\u30d7\u30ed\u30c0\u30af\u30c8\u30aa\u30fc\u30ca\u30fc
|
||||
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
|
||||
quitSure=\u672c\u5f53\u306b\u7d42\u4e86\u3057\u307e\u3059\u304b\uff1f
|
||||
scrumMaster=\u30b9\u30af\u30e9\u30e0\u30de\u30b9\u30bf\u30fc
|
||||
server=\u30b5\u30fc\u30d0\u30fc
|
||||
serverIP=\u30b5\u30fc\u30d0\u30fc IP
|
||||
serverPort=\u30b5\u30fc\u30d0\u30fc \u30dd\u30fc\u30c8
|
||||
small=\u5C0F
|
||||
start=\u59cb\u307e\u308a
|
||||
theme=\u30C6\u30FC\u30DE
|
||||
tictactoe=\u30bf\u30a4\u30af\u30bf\u30c3\u30c8\u30c8\u30a6
|
||||
volume=\u30de\u30b9\u30bf\u30fc\u30dc\u30ea\u30e5\u30fc\u30e0
|
||||
windowed=\u30a6\u30a3\u30f3\u30c9\u30a6
|
||||
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)
|
||||
|
||||
@@ -1,52 +1,88 @@
|
||||
ai=\uc778\uacf5 \uc9c0\ub2a5
|
||||
appTitle=ISY \uac8c\uc784 \uc120\ud0dd\uae30
|
||||
back=\ub4a4\ub85c
|
||||
backToMainMenu=\uBA54\uC778 \uBA54\uB274\uB85C \uB3CC\uC544\uAC00\uAE30
|
||||
computer=\uce74\ud14c\uae4c
|
||||
computerDifficulty=\uce74\ud14c\uae4c \ub2e8\uacc4
|
||||
computerThinkTime=\uc870\ub9ac\ud558\ub294 \uc2dc\uac04
|
||||
congratulations=\uCD95\uD558\uD569\uB2C8\uB2E4
|
||||
connect=\uc5f0\uacb0
|
||||
connectionType=\uC5F0\uACB0 \uC720\uD615
|
||||
credits=\uac10\uc0ac
|
||||
dark-hc=\uC5B4\uB460 (\uACE0 \uB300\uBE44)
|
||||
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
|
||||
developers=\uac1c\ubc1c\uc790
|
||||
drawText=\uAC8C\uC784\uC740 \uBB34\uC2B9\uBD84\uC73C\uB85C \uB05D\uB0AC\uC2B5\uB2C8\uB2E4
|
||||
effectsVolume=\ud654\uac70 \ubc84\uc804
|
||||
musicVolume=Music Volume (translate me)
|
||||
fullscreen=\uc804\uccb4 \ud654\uba74
|
||||
goodGameText=\uC88B\uC740 \uAC8C\uC784\uC774\uC600\uC2B5\uB2C8\uB2E4. \uC798 \uD50C\uB808\uC774\uD588\uC2B5\uB2C8\uB2E4.
|
||||
human=\uc778\uac04
|
||||
language=\uc5b8\uc5b4
|
||||
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
|
||||
layoutSize=\uB808\uC774\uC544\uC6C3 \uD06C\uAE30
|
||||
light-hc=\uBC1D\uC74C (\uACE0 \uB300\uBE44)
|
||||
light=\uBC1D\uC74C
|
||||
local=\ub85c\uceec
|
||||
localization=\uc5b8\uc5b4\ud654
|
||||
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
|
||||
mergeCommander=\uba54\uc9c0 \ucea0\ub9ac\ub354
|
||||
moralSupport=\uc815\uc2e0\uc801 \uc9c0\uc6d0
|
||||
no=\uc544\ub2c8\uc624
|
||||
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
|
||||
othello=\uc624\ud14c\ub85c
|
||||
playerName=\ud50c\ub808\uc774\uc5b4 \uc774\ub984
|
||||
productOwner=\uc81c\ud488 \uad00\ub9ac\uc790
|
||||
quit=\uc885\ub8cc
|
||||
quitSure=\uc815\ub9d0 \uc885\ub8cc\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?
|
||||
scrumMaster=\uc2a4\ud06c\ub7fc \ub9c8\uc2a4\ud130
|
||||
server=\uc11c\ubc84
|
||||
serverIP=\uc11c\ubc84 IP
|
||||
serverPort=\uc11c\ubc84 \ud3ec\ud2b8
|
||||
small=\uC791\uC74C
|
||||
start=\uc2dc\uc791
|
||||
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
|
||||
tictactoe=\ud2f0\ud06c\ud0d0\ud1a0
|
||||
volume=\ub9c8\uc2a4\ud130 \ubcfc\ub80c
|
||||
windowed=\ucc3d \ubaa8\ub4dc
|
||||
yes=\ub124
|
||||
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)
|
||||
|
||||
@@ -1,52 +1,88 @@
|
||||
accept=Accepteren
|
||||
ai=Kunstmatige Intelligentie
|
||||
appTitle=ISY Spel Kiezer
|
||||
app-title=ISY Spel Kiezer
|
||||
are-you-sure=Weet je het zeker?
|
||||
back=Terug
|
||||
backToMainMenu=Terug naar hoofdmenu
|
||||
cancel=Annuleren
|
||||
challenge=Uitdaging
|
||||
computer-difficulty=Computermoeilijkheid
|
||||
computer-think-time=Denktijd computer
|
||||
computer=Computer
|
||||
computerDifficulty=Computermoeilijkheid
|
||||
computerThinkTime=Computer Denk Tijd
|
||||
congratulations=Gefeliciteerd
|
||||
connect=Verbinden
|
||||
connectionType=Verbindingstype
|
||||
credits=Credits
|
||||
dark-hc=Donker (Hoog Contrast)
|
||||
dark=Donker
|
||||
deny=Weigeren
|
||||
developers=Ontwikkelaars
|
||||
drawText=Het spel eindigde in een gelijkspel
|
||||
effectsVolume=Effecten Volume
|
||||
musicVolume=Music Volume (translate me)
|
||||
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
|
||||
goodGameText=Goed gespeeld. Mooie wedstrijd.
|
||||
human=Mens
|
||||
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
|
||||
layoutSize=Lay-outgrootte
|
||||
light-hc=Licht (Hoog Contrast)
|
||||
layout-size=Lay-outgrootte
|
||||
light=Licht
|
||||
local=Lokaal
|
||||
localization=Lokalisatie
|
||||
medium=Middel
|
||||
mergeCommander=Merge-commandant
|
||||
moralSupport=Moraalsteun
|
||||
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
|
||||
othello=Othello
|
||||
playerName=Spelernaam
|
||||
productOwner=Producteigenaar
|
||||
quit=Afsluiten
|
||||
quitSure=Weet je het zeker?
|
||||
scrumMaster=Scrum Master
|
||||
server=Server
|
||||
serverIP=Server-IP
|
||||
serverPort=Serverpoort
|
||||
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
|
||||
start=Start
|
||||
style=Stijl
|
||||
the-game-ended-in-a-draw=Het spel eindigde in een gelijkspel
|
||||
theme=Thema
|
||||
tictactoe=Boter Kaas en Eieren
|
||||
volume=Hoofdvolume
|
||||
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
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabisch)
|
||||
chinese=\u4e2d\u6587 (Chinees)
|
||||
|
||||
@@ -1,52 +1,88 @@
|
||||
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
|
||||
appTitle=ISY \u0412\u044b\u0431\u043e\u0440 \u0438\u0433\u0440
|
||||
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
|
||||
backToMainMenu=\u041D\u0430\u0437\u0430\u0434 \u0432 \u0433\u043B\u0430\u0432\u043D\u043E\u0435 \u043C\u0435\u043D\u044E
|
||||
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
|
||||
computerDifficulty=\u0421\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430
|
||||
computerThinkTime=\u0412\u0440\u0435\u043c\u044f \u043e\u0431\u0434\u0443\u043c\u044b \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430
|
||||
congratulations=\u041F\u043E\u0437\u0434\u0440\u0430\u0432\u043B\u044F\u0435\u043C
|
||||
connect=\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f
|
||||
connectionType=\u0442\u0438\u043F \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F
|
||||
credits=\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u043d\u043e\u0441\u0442\u0438
|
||||
dark-hc=\u0442\u0451\u043C\u043D\u044B\u0439 (\u0432\u044B\u0441\u043E\u043A\u0438\u0439 \u043A\u043E\u043D\u0442\u0440\u0430\u0441\u0442)
|
||||
dark=\u0442\u0451\u043C\u043D\u044B\u0439
|
||||
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
|
||||
drawText=\u0418\u0433\u0440\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C \u043D\u0438\u0447\u044C\u0435\u0439
|
||||
effectsVolume=\u042d\u0444\u0444\u0435\u043a\u0442\u044b \u0433\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c
|
||||
musicVolume=Music Volume (translate me)
|
||||
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
|
||||
goodGameText=\u0425\u043E\u0440\u043E\u0448\u0430\u044F \u0438\u0433\u0440\u0430. \u0425\u043E\u0440\u043E\u0448\u043E \u0441\u044B\u0433\u0440\u0430\u043D\u043E.
|
||||
human=\u0427\u0435\u043b\u043e\u0432\u0435\u043a
|
||||
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=\u0431\u043E\u043B\u044C\u0448\u043E\u0439
|
||||
layoutSize=\u0440\u0430\u0437\u043C\u0435\u0440 \u043C\u0430\u043A\u0435\u0442\u0430
|
||||
light-hc=\u0441\u0432\u0435\u0442\u043B\u044B\u0439 (\u0432\u044B\u0441\u043E\u043A\u0438\u0439 \u043A\u043E\u043D\u0442\u0440\u0430\u0441\u0442)
|
||||
light=\u0441\u0432\u0435\u0442\u043B\u044B\u0439
|
||||
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
|
||||
medium=\u0441\u0440\u0435\u0434\u043D\u0438\u0439
|
||||
mergeCommander=\u041a\u043e\u043c\u0430\u043d\u0434\u0435\u0440 \u0441\u043b\u0438\u044f\u043d\u0438\u044f
|
||||
moralSupport=\u041c\u043e\u0440\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430
|
||||
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
|
||||
othello=\u041e\u0442\u0435\u043b\u043b\u043e
|
||||
playerName=\u0418\u043c\u044f \u0438\u0433\u0440\u043e\u043a\u0430
|
||||
productOwner=\u0412\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430
|
||||
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
|
||||
quitSure=\u0423\u0432\u0435\u0440\u0435\u043d\u044b \u043b\u0438?
|
||||
scrumMaster=\u041c\u0430\u0441\u0442\u0435\u0440 Scrum
|
||||
server=\u0421\u0435\u0440\u0432\u0435\u0440
|
||||
serverIP=\u0418\u043f\u0440\u0435\u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430
|
||||
serverPort=\u041f\u043e\u0440\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430
|
||||
small=\u043C\u0430\u043B\u0435\u043D\u044C\u043A\u0438\u0439
|
||||
start=\u0421\u0442\u0430\u0440\u0442
|
||||
theme=\u0442\u0435\u043C\u0430
|
||||
tictactoe=\u041a\u0440\u0435\u0441\u0442\u0438\u043a\u0438
|
||||
volume=\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0433\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c
|
||||
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)
|
||||
|
||||
@@ -1,52 +1,88 @@
|
||||
accept=\u63a5\u53d7
|
||||
ai=\u4eba\u5de5\u667a\u80fd
|
||||
appTitle=ISY \u6e38\u620f\u9009\u62e9\u5668
|
||||
app-title=ISY \u6e38\u620f\u9009\u62e9\u5668
|
||||
are-you-sure=\u60a8\u786e\u5b9a\u5417\uff1f
|
||||
back=\u8fd4\u56de
|
||||
backToMainMenu=\u8FD4\u56DE\u4E3B\u83DC\u5355
|
||||
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
|
||||
computerDifficulty=\u8ba1\u7b97\u673a\u96be\u5ea6
|
||||
computerThinkTime=\u7535\u8111\u8003\u616e\u65f6\u95f4
|
||||
congratulations=\u606D\u559C
|
||||
connect=\u8fde\u63a5
|
||||
connectionType=\u8FDE\u63A5\u7C7B\u578B
|
||||
credits=\u6b23\u8d4f
|
||||
dark-hc=\u6697 (\u9AD8\u5BF9\u6BD4)
|
||||
dark=\u6697
|
||||
connect4=Connect 4
|
||||
credits=\u81f4\u8c22
|
||||
dark=\u6697\u8272
|
||||
deny=\u62d2\u7edd
|
||||
developers=\u5f00\u53d1\u8005
|
||||
drawText=\u6E38\u620F\u4EE5\u5E73\u5C40\u7ED3\u675F
|
||||
effectsVolume=\u6548\u679c\u91cf
|
||||
musicVolume=Music Volume (translate me)
|
||||
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
|
||||
goodGameText=\u6E38\u620F\u5F88\u597D. \u8868\u73B0\u4F18\u79C0.
|
||||
human=\u4eba
|
||||
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
|
||||
layoutSize=\u5E03\u5C40\u5927\u5C0F
|
||||
light-hc=\u4EAE (\u9AD8\u5BF9\u6BD4)
|
||||
light=\u4EAE
|
||||
layout-size=\u5e03\u5c40\u5927\u5c0f
|
||||
light=\u4eae\u8272
|
||||
local=\u672c\u5730
|
||||
localization=\u6d88\u606f\u5c55\u793a / \u672c\u5730\u5316
|
||||
medium=\u4E2D
|
||||
mergeCommander=Merge \u63a7\u4e3b
|
||||
moralSupport=\u795e\u7cbe\u652f\u6301
|
||||
no=\u5426
|
||||
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
|
||||
othello=Othello
|
||||
playerName=\u73a9\u5bb6\u540d\u79f0
|
||||
productOwner=\u54c1\u76d8\u4ea7\u54c1\u4eba
|
||||
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
|
||||
quitSure=\u4f60\u786e\u5b9a\u5417?
|
||||
scrumMaster=Scrum \u4f1a\u5458
|
||||
server=\u670d\u52a1\u5668
|
||||
serverIP=\u670d\u52a1\u5668 IP
|
||||
serverPort=\u670d\u52a1\u5668 \u7aef\u53e3
|
||||
small=\u5C0F
|
||||
start=\u5f00\u59cb
|
||||
theme=\u4E3B\u9898
|
||||
tictactoe=Tic Tac Toe
|
||||
volume=\u4e3b\u97f3\u91cf
|
||||
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
|
||||
|
||||
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u963f\u62c9\u4f2f\u8bed)
|
||||
chinese=\u4e2d\u6587
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
/* ----------------------------
|
||||
.background
|
||||
----------------------------- */
|
||||
.bg-primary {
|
||||
-fx-background-color: #0a0a0a;
|
||||
}
|
||||
|
||||
.bg-secondary {
|
||||
-fx-background-color: #1a1a1a;
|
||||
}
|
||||
|
||||
.bg-popup {
|
||||
-fx-background-color: #0a0a0acc;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.button
|
||||
----------------------------- */
|
||||
.button {
|
||||
/* Layout */
|
||||
-fx-padding: 10 20;
|
||||
-fx-background-radius: 6;
|
||||
-fx-cursor: hand;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #1a1a1a;
|
||||
-fx-text-fill: #ffffff;
|
||||
-fx-border-color: #ffffff;
|
||||
-fx-border-width: 1;
|
||||
|
||||
/* Effects */
|
||||
-fx-effect: dropshadow(gaussian, #00000099, 4, 0, 0, 1);
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
-fx-background-color: #2a2a2a;
|
||||
-fx-border-color: #00ff00;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.choice-box
|
||||
----------------------------- */
|
||||
.choice-box {
|
||||
/* Layout */
|
||||
-fx-padding: 6;
|
||||
-fx-background-radius: 4;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #1a1a1a;
|
||||
-fx-border-color: #ffffff;
|
||||
-fx-border-width: 1;
|
||||
-fx-mark-color: #ffffff;
|
||||
}
|
||||
|
||||
.choice-box:hover {
|
||||
-fx-border-color: #00ff00;
|
||||
}
|
||||
|
||||
.choice-box:focused {
|
||||
-fx-border-color: #00cc66;
|
||||
}
|
||||
|
||||
.choice-box .label {
|
||||
-fx-text-fill: #ffffff;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.choice-box popup styling
|
||||
----------------------------- */
|
||||
.choice-box .context-menu {
|
||||
/* Layout */
|
||||
-fx-padding: 4;
|
||||
-fx-background-radius: 4;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #1a1a1a;
|
||||
-fx-border-color: #ffffff;
|
||||
-fx-border-width: 1;
|
||||
}
|
||||
|
||||
.choice-box .menu-item {
|
||||
/* Layout */
|
||||
-fx-padding: 6 12;
|
||||
}
|
||||
|
||||
.choice-box .menu-item .label {
|
||||
-fx-text-fill: #ffffff;
|
||||
}
|
||||
|
||||
.choice-box .menu-item:hover {
|
||||
-fx-background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
.choice-box .menu-item:focused {
|
||||
-fx-background-color: #00ff00;
|
||||
-fx-text-fill: #000000;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.container
|
||||
----------------------------- */
|
||||
.container {
|
||||
/* Layout */
|
||||
-fx-padding: 10;
|
||||
-fx-alignment: center;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #1a1a1a;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.input
|
||||
----------------------------- */
|
||||
.input {
|
||||
/* Layout */
|
||||
-fx-padding: 8;
|
||||
-fx-background-radius: 4;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #1a1a1a;
|
||||
-fx-text-fill: #ffffff;
|
||||
-fx-border-color: #ffffff;
|
||||
-fx-border-width: 1;
|
||||
}
|
||||
|
||||
.input:hover {
|
||||
-fx-border-color: #00ff00;
|
||||
}
|
||||
|
||||
.input:focused {
|
||||
-fx-border-color: #00cc66;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.separator
|
||||
----------------------------- */
|
||||
.separator {
|
||||
/* Layout */
|
||||
-fx-padding: 10 0;
|
||||
}
|
||||
|
||||
.separator .line {
|
||||
/* Color */
|
||||
-fx-border-color: #ffffff;
|
||||
-fx-border-width: 0 0 1 0;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.slider
|
||||
----------------------------- */
|
||||
.slider {
|
||||
/* Layout */
|
||||
-fx-padding: 6 0;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.slider .track {
|
||||
/* Color */
|
||||
-fx-background-color: linear-gradient(to left, #00ff00, #ff0000);
|
||||
-fx-background-insets: 0;
|
||||
-fx-background-radius: 2;
|
||||
-fx-pref-height: 4;
|
||||
}
|
||||
|
||||
.slider .thumb {
|
||||
/* Color */
|
||||
-fx-background-color: #ffffff;
|
||||
-fx-background-radius: 50%;
|
||||
|
||||
/* Effects */
|
||||
-fx-effect: dropshadow(gaussian, #000000aa, 4, 0, 0, 1);
|
||||
}
|
||||
|
||||
.slider .thumb:hover {
|
||||
-fx-scale-x: 1.2;
|
||||
-fx-scale-y: 1.2;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.text-header
|
||||
----------------------------- */
|
||||
.text-header {
|
||||
-fx-fill: #ffffff;
|
||||
-fx-text-fill: #ffffff;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.text-normal
|
||||
----------------------------- */
|
||||
.text-normal {
|
||||
-fx-fill: #f0f0f0;
|
||||
-fx-text-fill: #f0f0f0;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.toggle-button
|
||||
----------------------------- */
|
||||
.toggle {
|
||||
/* Layout */
|
||||
-fx-padding: 8 16;
|
||||
-fx-background-radius: 6;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #1f1f1f;
|
||||
-fx-text-fill: #ffffff;
|
||||
-fx-border-color: #ffffff;
|
||||
}
|
||||
|
||||
.toggle:hover {
|
||||
-fx-background-color: #00ff00;
|
||||
-fx-text-fill: #000000;
|
||||
-fx-border-color: #00ff00;
|
||||
}
|
||||
@@ -1,215 +1,199 @@
|
||||
/* ----------------------------
|
||||
.background
|
||||
----------------------------- */
|
||||
.bg-primary {
|
||||
-fx-background-color: #181818;
|
||||
-fx-background-color: linear-gradient(to bottom, #2a3a45, #1c2730);
|
||||
}
|
||||
|
||||
.bg-secondary {
|
||||
-fx-background-color: #2a2a2a;
|
||||
-fx-background-color: linear-gradient(to bottom, #3b4a57, #2a3742);
|
||||
}
|
||||
|
||||
.bg-popup {
|
||||
-fx-background-color: #1818187f;
|
||||
-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
|
||||
----------------------------- */
|
||||
.button {
|
||||
/* Layout */
|
||||
-fx-padding: 10 20;
|
||||
-fx-background-radius: 6;
|
||||
-fx-background-color: linear-gradient(to bottom, #1f5e20, #2e7d2e);
|
||||
-fx-background-radius: 8;
|
||||
-fx-border-color: #3caf3f;
|
||||
-fx-cursor: hand;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #2a2a2a;
|
||||
-fx-text-fill: #f0f0f0;
|
||||
-fx-border-color: #3a3a3a;
|
||||
-fx-border-width: 1;
|
||||
|
||||
/* Effects */
|
||||
-fx-effect: dropshadow(gaussian, #0000004d, 4, 0, 0, 1);
|
||||
-fx-effect: dropshadow(gaussian, #3caf3fdd, 6, 0, 0, 2);
|
||||
-fx-text-fill: #e0f2e9;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
-fx-background-color: #3a3a3a;
|
||||
-fx-border-color: #4caf50;
|
||||
-fx-background-color: linear-gradient(to bottom, #44a044, #57b257);
|
||||
-fx-border-color: #2f7d2f;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.choice-box
|
||||
----------------------------- */
|
||||
.choice-box {
|
||||
/* Layout */
|
||||
-fx-padding: 6;
|
||||
-fx-background-radius: 4;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #2a2a2a;
|
||||
-fx-border-color: #444444;
|
||||
-fx-border-width: 1;
|
||||
-fx-mark-color: #f0f0f0;
|
||||
.combo-box {
|
||||
-fx-background-color: linear-gradient(to bottom, #3c5155, #2a3a3e);
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-color: #3caf3f;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
.choice-box:hover {
|
||||
-fx-border-color: #4caf50;
|
||||
.combo-box:hover {
|
||||
-fx-border-color: #55a755;
|
||||
}
|
||||
|
||||
.choice-box:focused {
|
||||
-fx-border-color: #81c784;
|
||||
.combo-box:focused {
|
||||
-fx-border-color: #88cc88;
|
||||
-fx-effect: dropshadow(gaussian, #88cc8899, 5, 0, 0, 1);
|
||||
}
|
||||
|
||||
.choice-box .label {
|
||||
-fx-text-fill: #f0f0f0;
|
||||
.combo-box .arrow,
|
||||
.combo-box .arrow-button {
|
||||
-fx-background-color: transparent;
|
||||
-fx-border-color: transparent;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.choice-box popup styling
|
||||
----------------------------- */
|
||||
.choice-box .context-menu {
|
||||
/* Layout */
|
||||
-fx-padding: 4;
|
||||
-fx-background-radius: 4;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #2a2a2a;
|
||||
-fx-border-color: #444444;
|
||||
-fx-border-width: 1;
|
||||
.combo-box .list-cell {
|
||||
-fx-background-color: transparent;
|
||||
-fx-text-fill: #a8d0a8;
|
||||
}
|
||||
|
||||
.choice-box .menu-item {
|
||||
/* Layout */
|
||||
-fx-padding: 6 12;
|
||||
.combo-box .list-view {
|
||||
-fx-background-color: #264233;
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-color: #3caf3f;
|
||||
}
|
||||
|
||||
.choice-box .menu-item .label {
|
||||
-fx-text-fill: #dddddd;
|
||||
.combo-box-popup .list-cell {
|
||||
-fx-text-fill: #a8d0a8;
|
||||
}
|
||||
|
||||
.choice-box .menu-item:hover {
|
||||
-fx-background-color: #3a3a3a;
|
||||
.combo-box-popup .list-cell:hover {
|
||||
-fx-background-color: #44a044;
|
||||
}
|
||||
|
||||
.choice-box .menu-item:focused {
|
||||
-fx-background-color: #4caf50;
|
||||
-fx-text-fill: #ffffff;
|
||||
.combo-box-popup .list-cell:selected {
|
||||
-fx-background-color: #2e7d2e;
|
||||
-fx-text-fill: #e0f2e9;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.container
|
||||
----------------------------- */
|
||||
.container {
|
||||
/* Layout */
|
||||
-fx-padding: 10;
|
||||
-fx-alignment: center;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.input
|
||||
----------------------------- */
|
||||
.input {
|
||||
/* Layout */
|
||||
-fx-padding: 8;
|
||||
-fx-background-radius: 4;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #2a2a2a;
|
||||
-fx-text-fill: #f0f0f0;
|
||||
-fx-border-color: #444444;
|
||||
-fx-border-width: 1;
|
||||
-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: #4caf50;
|
||||
-fx-border-color: #55a755;
|
||||
}
|
||||
|
||||
.input:focused {
|
||||
-fx-border-color: #81c784;
|
||||
-fx-border-color: #88cc88;
|
||||
-fx-effect: dropshadow(gaussian, #88cc8899, 5, 0, 0, 1);
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.separator
|
||||
----------------------------- */
|
||||
.separator {
|
||||
/* Layout */
|
||||
-fx-padding: 10 0;
|
||||
.my-turn {
|
||||
-fx-fill: #e05656;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.separator .line {
|
||||
/* Color */
|
||||
-fx-border-color: #3a3a3a;
|
||||
-fx-border-width: 0 0 1 0;
|
||||
-fx-border-color: #55a755;
|
||||
-fx-opacity: 1;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.slider
|
||||
----------------------------- */
|
||||
.slider {
|
||||
/* Layout */
|
||||
-fx-padding: 6 0;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.slider .track {
|
||||
/* Color */
|
||||
-fx-background-color: linear-gradient(to left, #4caf50, #f44336);
|
||||
-fx-background-insets: 0;
|
||||
-fx-background-radius: 2;
|
||||
-fx-pref-height: 4;
|
||||
}
|
||||
|
||||
.slider .thumb {
|
||||
/* Color */
|
||||
-fx-background-color: #f0f0f0;
|
||||
-fx-background-color: linear-gradient(to bottom, #2e7d2e, #44a044);
|
||||
-fx-background-radius: 50%;
|
||||
|
||||
/* Effects */
|
||||
-fx-effect: dropshadow(gaussian, #00000066, 4, 0, 0, 1);
|
||||
-fx-effect: dropshadow(gaussian, #3caf3fdd, 5, 0, 0, 1);
|
||||
}
|
||||
|
||||
.slider .thumb:hover {
|
||||
-fx-scale-x: 1.2;
|
||||
-fx-scale-y: 1.2;
|
||||
-fx-scale-x: 1.15;
|
||||
-fx-scale-y: 1.15;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.text-header
|
||||
----------------------------- */
|
||||
.text-header {
|
||||
-fx-fill: #f0f0f0;
|
||||
-fx-text-fill: #f0f0f0;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.text-normal
|
||||
----------------------------- */
|
||||
.text-normal {
|
||||
-fx-fill: #dddddd;
|
||||
-fx-text-fill: #dddddd;
|
||||
}
|
||||
|
||||
/* ----------------------------
|
||||
.toggle-button
|
||||
----------------------------- */
|
||||
.toggle {
|
||||
/* Layout */
|
||||
-fx-padding: 8 16;
|
||||
.slider .track {
|
||||
-fx-background-color: linear-gradient(to left, #57b257, #e05c5c);
|
||||
-fx-background-insets: 0;
|
||||
-fx-background-radius: 6;
|
||||
|
||||
/* Color */
|
||||
-fx-background-color: #333333;
|
||||
-fx-text-fill: #cccccc;
|
||||
-fx-border-color: #4a4a4a;
|
||||
}
|
||||
|
||||
.toggle:hover {
|
||||
-fx-background-color: #4caf50;
|
||||
-fx-text-fill: #ffffff;
|
||||
-fx-border-color: #4caf50;
|
||||
.text {
|
||||
-fx-fill: #a8d0a8;
|
||||
-fx-font-weight: normal;
|
||||
-fx-text-fill: #a8d0a8;
|
||||
}
|
||||
|
||||
.header {
|
||||
-fx-fill: #88cc88;
|
||||
-fx-font-weight: bold;
|
||||
-fx-text-fill: #88cc88;
|
||||
}
|
||||
42
app/src/main/resources/assets/style/general.css
Normal file
@@ -0,0 +1,42 @@
|
||||
.combo-box .list-cell {
|
||||
-fx-alignment: CENTER;
|
||||
-fx-padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
-fx-alignment: TOP_CENTER;
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.scroll,
|
||||
.scroll .viewport {
|
||||
-fx-background-color: transparent;
|
||||
-fx-border-color: transparent;
|
||||
}
|
||||
|
||||
.scroll .scroll-bar .decrement-arrow,
|
||||
.scroll .scroll-bar .decrement-button,
|
||||
.scroll .scroll-bar .increment-arrow,
|
||||
.scroll .scroll-bar .increment-button {
|
||||
-fx-padding: 0;
|
||||
-fx-pref-height: 0;
|
||||
-fx-pref-width: 0;
|
||||
-fx-shape: "";
|
||||
}
|
||||
|
||||
.scroll .scroll-bar .thumb {
|
||||
-fx-background-color: #888;
|
||||
-fx-background-insets: 0;
|
||||
-fx-background-radius: 1px;
|
||||
}
|
||||
|
||||
.scroll .scroll-bar:horizontal,
|
||||
.scroll .scroll-bar:vertical {
|
||||
-fx-pref-height: 4px;
|
||||
-fx-pref-width: 4px;
|
||||
}
|
||||
|
||||
.header,
|
||||
.text {
|
||||
-fx-font-family: "Arial";
|
||||
}
|
||||
199
app/src/main/resources/assets/style/high-contrast.css
Normal file
@@ -0,0 +1,199 @@
|
||||
.bg-primary {
|
||||
-fx-background-color: linear-gradient(to bottom, #121b22, #0a0f14);
|
||||
}
|
||||
|
||||
.bg-secondary {
|
||||
-fx-background-color: linear-gradient(to bottom, #1a2b35, #0d181f);
|
||||
}
|
||||
|
||||
.bg-popup {
|
||||
-fx-background-color: rgba(10, 20, 30, 0.95);
|
||||
-fx-background-radius: 8;
|
||||
-fx-effect: dropshadow(gaussian, #1f6a22ff, 10, 0, 0, 3);
|
||||
}
|
||||
|
||||
.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, #1b7a1b, #2da32d);
|
||||
-fx-background-radius: 8;
|
||||
-fx-border-color: #28a428;
|
||||
-fx-cursor: hand;
|
||||
-fx-effect: dropshadow(gaussian, #28a428ff, 8, 0, 0, 3);
|
||||
-fx-text-fill: #e0ffe0;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
-fx-background-color: linear-gradient(to bottom, #45d045, #60e060);
|
||||
-fx-border-color: #1c841c;
|
||||
}
|
||||
|
||||
.combo-box {
|
||||
-fx-background-color: linear-gradient(to bottom, #26473b, #1a2e25);
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-color: #28a428;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
|
||||
.combo-box:hover {
|
||||
-fx-border-color: #52c352;
|
||||
}
|
||||
|
||||
.combo-box:focused {
|
||||
-fx-border-color: #70e070;
|
||||
-fx-effect: dropshadow(gaussian, #70e070cc, 6, 0, 0, 2);
|
||||
}
|
||||
|
||||
.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: #a8f0a8;
|
||||
}
|
||||
|
||||
.combo-box .list-view {
|
||||
-fx-background-color: #16321f;
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-color: #28a428;
|
||||
}
|
||||
|
||||
.combo-box-popup .list-cell {
|
||||
-fx-text-fill: #a8f0a8;
|
||||
}
|
||||
|
||||
.combo-box-popup .list-cell:hover {
|
||||
-fx-background-color: #45d045;
|
||||
}
|
||||
|
||||
.combo-box-popup .list-cell:selected {
|
||||
-fx-background-color: #2da32d;
|
||||
-fx-text-fill: #f0fff0;
|
||||
}
|
||||
|
||||
.input {
|
||||
-fx-background-color: linear-gradient(to bottom, #15331a, #0e2b15);
|
||||
-fx-background-radius: 6;
|
||||
-fx-border-color: #28a428;
|
||||
-fx-text-fill: #a8f0a8;
|
||||
-fx-font-weight: normal;
|
||||
}
|
||||
|
||||
.input:hover {
|
||||
-fx-border-color: #52c352;
|
||||
}
|
||||
|
||||
.input:focused {
|
||||
-fx-border-color: #70e070;
|
||||
-fx-effect: dropshadow(gaussian, #70e070cc, 6, 0, 0, 2);
|
||||
}
|
||||
|
||||
.my-turn {
|
||||
-fx-fill: #ff4b4b;
|
||||
-fx-font-weight: bold;
|
||||
}
|
||||
|
||||
.separator .line {
|
||||
-fx-border-color: #52c352;
|
||||
-fx-opacity: 1;
|
||||
}
|
||||
|
||||
.slider {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.slider .thumb {
|
||||
-fx-background-color: linear-gradient(to bottom, #2da32d, #45d045);
|
||||
-fx-background-radius: 50%;
|
||||
-fx-effect: dropshadow(gaussian, #28a428ff, 6, 0, 0, 2);
|
||||
}
|
||||
|
||||
.slider .thumb:hover {
|
||||
-fx-scale-x: 1.15;
|
||||
-fx-scale-y: 1.15;
|
||||
}
|
||||
|
||||
.slider .track {
|
||||
-fx-background-color: linear-gradient(to left, #60e060, #ff5555);
|
||||
-fx-background-insets: 0;
|
||||
-fx-background-radius: 6;
|
||||
}
|
||||
|
||||
.text {
|
||||
-fx-fill: #a8f0a8;
|
||||
-fx-font-weight: normal;
|
||||
-fx-text-fill: #a8f0a8;
|
||||
}
|
||||
|
||||
.header {
|
||||
-fx-fill: #70e070;
|
||||
-fx-font-weight: bold;
|
||||
-fx-text-fill: #70e070;
|
||||
}
|
||||