259 Commits

Author SHA1 Message Date
michiel301b
da27399dda i think timer fixed it but idk 2025-11-28 22:04:55 +01:00
lieght
c98edc37a6 Added documentation 2025-11-28 20:08:13 +01:00
lieght
c21f254234 Refactored switch statement 2025-11-28 20:05:08 +01:00
lieght
fd85a73608 Removed unused imports 2025-11-28 19:36:16 +01:00
lieght
ea7a5e11ba Refactored nextScreen runnable 2025-11-28 19:35:31 +01:00
lieght
164708dcf5 Added button to continue and start game. Refactors 2025-11-28 19:26:15 +01:00
lieght
eb5e69a59c Tutorial images now use ImageAsset.java 2025-11-28 16:50:34 +01:00
ramollia
b3c9f89f99 Merge remote-tracking branch 'origin/Tutorials' into Tutorials 2025-11-28 14:00:46 +01:00
ramollia
6b619604ec added a pop button 2025-11-28 14:00:26 +01:00
lieght
1ec1c0d13d Fixed garbage code 2025-11-28 13:59:11 +01:00
lieght
0ab071693f Removed views 2025-11-28 12:09:40 +01:00
Bas Antonius de Jong
1a11827ba3 Merge pull request #261 from 2OOP/Tutorials
merge tutorials to dev branch
2025-11-28 11:56:42 +01:00
ramollia
a2d651cd7d Merge remote-tracking branch 'refs/remotes/origin/Development' into Tutorials
# Conflicts:
#	app/src/main/java/org/toop/app/game/Connect4Game.java
2025-11-28 11:51:46 +01:00
0cb025edb9 Changed the way turns are being stored in TurnBasedGame. 2025-11-27 18:37:34 +01:00
6ea94fe658 Fixed compilation errors 2025-11-27 17:42:39 +01:00
tichohidding
ef5c1ce6e3 Merge pull request #241 from 2OOP/Widgets
Widgets into development
2025-11-27 17:19:30 +01:00
tichohidding
8c01c7fa7a Merge branch 'Development' into Widgets 2025-11-27 17:19:17 +01:00
Ticho Hidding
72dd78137b Merge remote-tracking branch 'origin/Development' into Development 2025-11-27 15:50:36 +01:00
71c918e9ee Squashed commit of the following:
commit a517f2f302baa89f8ef59946a31c7bb59c56770f
Author: Stef <stbuwalda@gmail.com>
Date:   Thu Nov 27 15:43:43 2025 +0100

    Make it so the game shows "Waiting on ... to make their move". Styling isn't done but it is easier to see who's turn it is. There is a lot of structuring to do in the previous code...
2025-11-27 15:45:31 +01:00
Ticho Hidding
81f4d307a2 fixed turn skip bug
fixed end score bug
now only shows legal and highlight moves when human
2025-11-27 15:41:09 +01:00
Ticho Hidding
710438ec1b resizable true 2025-11-27 14:07:39 +01:00
michiel
c14b66e892 rest van de tutorials toegevoegd 2025-11-27 11:42:38 +01:00
michiel301b
8c69453506 started a basis for the tutorials, tic tac toe is almost done with some general stuff still to do. 2025-11-26 22:03:06 +01:00
Bas de Jong
a6b835bddf Removed no more needed comments 2025-11-20 11:41:44 +01:00
Bas de Jong
ca11151381 Functional code, is now object orientated 2025-11-06 15:32:15 +01:00
ramollia
fa4e1ad5e3 widget system almost complete 2025-11-03 12:47:56 +01:00
Ticho Hidding
295c61c7eb added some comments and made some methods a bit more readable 2025-11-01 15:12:09 +01:00
ramollia
1c9af58264 half done with the widget system 2025-10-31 17:33:19 +01:00
6dc05e7123 Made connect4 public method private 2025-10-29 20:09:39 +01:00
d1a9f94ee0 Fixed warning "Warning:(27, 12) Copy constructor does not copy field 'mostRecentlyFlippedPieces'", removed unused field 2025-10-29 20:04:50 +01:00
edfb4ffe51 Changed checkForEarlyDraw so it doesn't need a game as input. 2025-10-29 20:03:07 +01:00
be31de4660 Reversi: made method private 2025-10-29 19:51:09 +01:00
ea30e20585 Privated methods that didn't have to be public 2025-10-29 18:05:01 +01:00
d7e370536e Applied encapsulation principle to TurnBasedBame.java 2025-10-29 17:37:21 +01:00
6811890531 Removed unused imports 2025-10-29 17:29:28 +01:00
5da0a02cc8 Refactored Game to follow encapsulation principle 2025-10-29 17:28:43 +01:00
50713c5021 Turned Abstract Method for AI into interface 2025-10-29 15:01:58 +01:00
d17edf7c4a Renamed Interface Playtable to IPlayable 2025-10-29 14:52:19 +01:00
84e257c17c Removed unused imports 2025-10-29 14:50:40 +01:00
925c848fda Moved the Move record into it's own file, seperated from Game 2025-10-29 14:49:43 +01:00
13bac113b7 Turned abstract methods into an interface 2025-10-29 14:37:31 +01:00
068337e01b Removed unused import 2025-10-29 14:27:51 +01:00
44d8ffbef2 Made the GameState enum it's own file and fixed imports 2025-10-29 14:26:41 +01:00
Ticho Hidding
ff611724e7 Merge remote-tracking branch 'origin/Development' into Development 2025-10-29 14:06:23 +01:00
Ticho Hidding
7f36d7f244 cool onhover effect for reversi 2025-10-29 14:06:05 +01:00
eda85ea888 Removed unused import and unused parameter 2025-10-29 13:51:56 +01:00
f026a4fec6 Manually fallback to the fallback locale when a ResourceBundle is missing a resource key. Fallsback to "MISSING RESOUREC" if it's not present in the fallback. 2025-10-29 13:49:50 +01:00
Bas de Jong
b84255e00e Added replace to reduce boiler plate code 2025-10-28 15:23:36 +01:00
Bas de Jong
84c17d185b Fixes for garbage code by Omar 2025-10-28 14:37:15 +01:00
michiel
3776167299 iets met timing verkeerd temporary fix 2025-10-28 14:23:53 +01:00
ramollia
48ed6df6b4 started working on the widget system 2025-10-28 12:59:15 +01:00
michiel
2428048bd5 updated music ma,es 2025-10-28 12:53:10 +01:00
michiel
1440190ac3 kleine ui fix 2025-10-28 12:30:48 +01:00
ramollia
3a51434f91 Merge remote-tracking branch 'origin/Development' into Development 2025-10-28 11:14:22 +01:00
ramollia
5b20909f80 moved score out of game 2025-10-28 11:13:56 +01:00
michiel
00b5f9dced mainview false for sendchallengeview 2025-10-28 11:10:17 +01:00
michiel
188a5e8a45 can now go to last using previous and being at the first song 2025-10-28 10:53:02 +01:00
ramollia
0638a38fc1 moved score out of game 2025-10-28 09:53:33 +01:00
ramollia
75fb865dad Merge branch 'Demo3' into Development 2025-10-28 09:16:22 +01:00
ramollia
2cda94e4db canvas changes 2025-10-28 09:13:09 +01:00
ramollia
d6f3bb2185 Merge remote-tracking branch 'origin/Demo3' into Demo3 2025-10-27 17:22:35 +01:00
ramollia
95d7ea5e1d Merge branch 'OtherGames' into Demo3 2025-10-27 17:22:07 +01:00
Ticho Hidding
6fb248bec4 spam minder v2 2025-10-27 17:21:50 +01:00
ramollia
7b5c188280 Merge remote-tracking branch 'origin/OtherGames' into OtherGames 2025-10-27 17:21:32 +01:00
ramollia
1c2736ac75 fixed setgamelabels 2025-10-27 17:21:04 +01:00
Ticho Hidding
caa812217f spam minder 2025-10-27 17:20:22 +01:00
Ticho Hidding
c115fb91af tourney ready 2025-10-27 17:14:36 +01:00
Ticho Hidding
b506afdade can start game from playerlist screen 2025-10-27 14:57:15 +01:00
michiel
59cc64ada7 fixed tests 2025-10-27 14:20:20 +01:00
Ticho Hidding
bd096df2c2 Merge remote-tracking branch 'origin/AudioDisplay' into OtherGames 2025-10-27 13:56:07 +01:00
Ticho Hidding
dfd3934b96 Merge branch 'Development' into OtherGames 2025-10-27 13:53:06 +01:00
michiel
2f7f2955c1 Merge remote-tracking branch 'origin/AudioDisplay' into Development 2025-10-27 10:00:49 +01:00
ramollia
fb8acbe228 add simple flip animations and fixed(?) server somewhat 2025-10-25 17:37:50 +02:00
michiel301b
be40ee0187 Made it so that it indicates with the play/pause button if its paused or played 2025-10-24 13:28:59 +02:00
michiel301b
0c536b0f9b Toegevoegd:
-Play Button + CSS + Events
-Previous Button + CSS + Events
-Changed interface for AudioResource to include a pause button which works really well with mediaplayer, however now SoundEffectAsset has an unnessescary pause
2025-10-24 13:22:42 +02:00
lieght
c85ab38142 Merge remote-tracking branch 'origin/185-networkingeventlistener' into Development 2025-10-21 20:43:21 +02:00
Ticho Hidding
c3f764f33d connect4 with minimax AI 2025-10-19 22:01:33 +02:00
Ticho Hidding
df493a5eba new reversi test (both players no legal moves) 2025-10-19 13:06:46 +02:00
Ticho Hidding
0447f7b0fe added method for sorting the flipped pieces by distance to Move.position 2025-10-19 02:18:11 +02:00
lieght
b1589032be test fix 2025-10-17 20:22:27 +02:00
lieght
55989ab8ce Merge remote-tracking branch 'origin/UI' into AudioDisplay 2025-10-17 20:13:05 +02:00
lieght
443f2da97d Merge remote-tracking branch 'origin/UI' into 185-networkingeventlistener 2025-10-17 20:12:41 +02:00
lieght
8f047cd7b5 Faster event schedule for PlayingMusic event 2025-10-17 19:51:49 +02:00
lieght
bb2630f3d5 Small event fix 2025-10-17 19:46:03 +02:00
michiel
f44bf6bd02 Tiny fix when natural skip 2025-10-16 14:00:40 +02:00
Bas de Jong
3a120803e3 Fixes for garbage code by Omar 2025-10-16 13:59:24 +02:00
michiel
6e35067c18 Skip Button 2025-10-16 13:37:01 +02:00
michiel
30f797022c Skip Button 2025-10-16 13:35:41 +02:00
lieght
abc173a1ee Merge remote-tracking branch 'origin/AudioDisplay' into AudioDisplay 2025-10-16 00:57:01 +02:00
lieght
3784cd790e Clips now also return positional information 2025-10-16 00:56:46 +02:00
michiel301b
f44c3932dc Basis Audio Display toegevoegd + standaard CSS toegevoegd
Kan nu zien hoe lang de song duurt, hoe lang ie al bezig is met draaien en de titel (-.mp3)
2025-10-16 00:45:29 +02:00
lieght
975207a6de Nuke everything on close. 2025-10-16 00:37:20 +02:00
lieght
545e830b3c Updated timings 2025-10-15 23:54:17 +02:00
lieght
977e9bb102 Updated test. 2025-10-15 23:24:21 +02:00
lieght
69bc55dc26 Polling music event, fires every 1 second 2025-10-15 23:21:00 +02:00
michiel301b
62e2b71ece begin van audio display 2025-10-15 22:58:25 +02:00
lieght
cf9dbef882 Correct client creation and user polling 2025-10-15 21:36:46 +02:00
Bas Antonius de Jong
09f3dc4e3e Merge pull request #186 from 2OOP/UI
Update UI for networking
2025-10-15 21:06:31 +02:00
lieght
6ae5f1c2d2 Merge remote-tracking branch 'origin/UI' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/App.java
#	app/src/main/java/org/toop/app/layer/layers/MainLayer.java
#	app/src/main/java/org/toop/app/layer/layers/OptionsPopup.java
#	app/src/main/java/org/toop/app/layer/layers/game/TicTacToeLayer.java
#	app/src/main/java/org/toop/local/AppSettings.java
2025-10-15 21:05:33 +02:00
lieght
b30420616a Merge remote-tracking branch 'origin/185-networkingeventlistener' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/App.java
#	app/src/main/java/org/toop/app/layer/layers/ConnectedLayer.java
#	app/src/main/java/org/toop/app/layer/layers/MainLayer.java
#	app/src/main/java/org/toop/app/layer/layers/OptionsPopup.java
#	app/src/main/java/org/toop/app/layer/layers/game/TicTacToeLayer.java
#	app/src/main/java/org/toop/local/AppSettings.java
2025-10-15 21:05:01 +02:00
lieght
1134649197 Documentation 2025-10-15 20:11:43 +02:00
lieght
5beebf9663 Quick fix for closing connection. 2025-10-15 19:08:18 +02:00
lieght
798005de2c Refactor to make Events easier to work with. 2025-10-15 19:05:09 +02:00
ramollia
e71369f7ff visual update 2025-10-15 16:46:19 +02:00
ramollia
56ebe1347c add: server chat box 2025-10-15 16:13:42 +02:00
ramollia
7f8ed029b9 add: reversi game 2025-10-15 15:22:19 +02:00
lieght
bc6182e29a Fixed event bug 2025-10-15 03:26:19 +02:00
lieght
dc81d9c3ca Added exceptions. Added reconnect attempts and changeable address 2025-10-15 02:58:14 +02:00
ramollia
2c8db95ba7 Merge remote-tracking branch 'origin/Reversi' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/App.java
#	app/src/main/java/org/toop/app/canvas/GameCanvas.java
#	app/src/main/java/org/toop/app/layer/layers/MainLayer.java
#	app/src/main/java/org/toop/app/layer/layers/OptionsPopup.java
#	app/src/main/java/org/toop/app/layer/layers/game/TicTacToeLayer.java
#	app/src/main/java/org/toop/local/AppSettings.java
#	app/src/main/resources/assets/localization/localization_ar.properties
#	app/src/main/resources/assets/localization/localization_de.properties
#	app/src/main/resources/assets/localization/localization_en.properties
#	app/src/main/resources/assets/localization/localization_es.properties
#	app/src/main/resources/assets/localization/localization_fr.properties
#	app/src/main/resources/assets/localization/localization_hi.properties
#	app/src/main/resources/assets/localization/localization_it.properties
#	app/src/main/resources/assets/localization/localization_ja.properties
#	app/src/main/resources/assets/localization/localization_ko.properties
#	app/src/main/resources/assets/localization/localization_nl.properties
#	app/src/main/resources/assets/localization/localization_ru.properties
#	app/src/main/resources/assets/localization/localization_zh.properties
2025-10-15 00:39:14 +02:00
ramollia
1f64a2dfd0 fixed merge conflicts 2025-10-15 00:26:27 +02:00
ramollia
0a6c2487bd Merge remote-tracking branch 'origin/UI' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/App.java
#	app/src/main/java/org/toop/app/GameInformation.java
#	app/src/main/java/org/toop/app/canvas/GameCanvas.java
#	app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java
#	app/src/main/java/org/toop/app/layer/Container.java
#	app/src/main/java/org/toop/app/layer/Layer.java
#	app/src/main/java/org/toop/app/layer/NodeBuilder.java
#	app/src/main/java/org/toop/app/layer/Popup.java
#	app/src/main/java/org/toop/app/layer/containers/HorizontalContainer.java
#	app/src/main/java/org/toop/app/layer/containers/VerticalContainer.java
#	app/src/main/java/org/toop/app/layer/layers/ConnectedLayer.java
#	app/src/main/java/org/toop/app/layer/layers/CreditsPopup.java
#	app/src/main/java/org/toop/app/layer/layers/MainLayer.java
#	app/src/main/java/org/toop/app/layer/layers/MultiplayerLayer.java
#	app/src/main/java/org/toop/app/layer/layers/OptionsPopup.java
#	app/src/main/java/org/toop/app/layer/layers/QuitPopup.java
#	app/src/main/java/org/toop/app/layer/layers/game/GameFinishedPopup.java
#	app/src/main/java/org/toop/app/layer/layers/game/TicTacToeLayer.java
#	app/src/main/java/org/toop/local/AppSettings.java
2025-10-15 00:17:17 +02:00
ramollia
e382cf95f2 gui refactor 2025-10-15 00:14:39 +02:00
lieght
14e6785c6f Some better docs. 2025-10-15 00:01:41 +02:00
lieght
444a81abc3 Improved API for dependency injection 2025-10-14 23:44:45 +02:00
lieght
d0676d9363 Forgot to remove 2025-10-14 23:27:52 +02:00
lieght
8f7e78efb5 Reworked NetworkingClientManager into SRP model. 2025-10-14 23:27:12 +02:00
lieght
cb7e3298fd Added shuffling on user request 2025-10-14 19:57:07 +02:00
michiel
c09f0eb1f9 punk toegevoegd 2025-10-14 14:18:52 +02:00
michiel
a3203dd78e Merge remote-tracking branch 'origin/Reversi' into Reversi 2025-10-14 13:40:00 +02:00
michiel
efbab12b10 Tests toegevoegd 2025-10-14 13:39:22 +02:00
Ticho Hidding
8e823b4108 getLegalMoves logic seems fixed //todo write better tests 2025-10-14 13:34:47 +02:00
3165ff33b3 Tests for SoundEffectManager 2025-10-14 13:21:17 +02:00
Ticho Hidding
81abeef843 commit ofzo 2025-10-14 13:12:45 +02:00
Ticho Hidding
be26db953e Merge remote-tracking branch 'origin/Development' into Reversi
# Conflicts:
#	app/src/main/java/org/toop/app/canvas/GameCanvas.java
#	app/src/main/java/org/toop/app/layer/layers/MainLayer.java
#	game/src/main/java/org/toop/game/Game.java
#	game/src/main/java/org/toop/game/othello/Othello.java
#	game/src/main/java/org/toop/game/othello/OthelloAI.java
2025-10-14 11:25:46 +02:00
Ticho Hidding
76c7e44447 Merge remote-tracking branch 'origin/Development' into Reversi 2025-10-14 11:07:10 +02:00
Ticho Hidding
d9f6c7ee74 commit 2025-10-14 11:06:41 +02:00
Bas de Jong
0e3165ed98 Added linelistener to SoundEffectAsset 2025-10-13 13:45:16 +02:00
lieght
4bcf70d4dc Removed ResourceManager from AudioManagers 2025-10-13 02:47:34 +02:00
lieght
fcc0b9d0dd SoundEffectManager now generic 2025-10-13 02:27:04 +02:00
lieght
cdc34b432e Changed pom to be correct.
Fixed SnowflakeGenerator not making unique ids.
Changed naming for event implementation.
Automated id getter for events.
Added Error-Prone to all modules.
Added parents to all modules.
Added processors module.
2025-10-13 02:06:12 +02:00
Bas Antonius de Jong
00daf37244 Merge pull request #175 from 2OOP/166-audiomanager-opslitsen-om-single-responsibility-principle-te-volgen
166 audiomanager opslitsen om single responsibility principle te volgen Done
2025-10-12 20:44:57 +02:00
lieght
bab11b64a5 Merge remote-tracking branch 'origin/166-audiomanager-opslitsen-om-single-responsibility-principle-te-volgen' into 166-audiomanager-opslitsen-om-single-responsibility-principle-te-volgen 2025-10-12 20:42:09 +02:00
lieght
4b60fa88ee Moved restrictedAPI to future release 2025-10-12 20:41:56 +02:00
lieght
f3316145e7 Finished todo's 2025-10-12 20:41:54 +02:00
lieght
53a72cc340 Moved restrictedAPI to future release 2025-10-12 20:41:10 +02:00
lieght
081fbda7b1 Merge remote-tracking branch 'origin/166-audiomanager-opslitsen-om-single-responsibility-principle-te-volgen' into 166-audiomanager-opslitsen-om-single-responsibility-principle-te-volgen
# Conflicts:
#	framework/src/main/java/org/toop/framework/audio/MusicManager.java
2025-10-12 20:37:23 +02:00
lieght
d051e3e603 Finished todo's 2025-10-12 20:36:28 +02:00
Bas de Jong
5317c42c81 Removed no more needed code. 2025-10-12 07:20:28 +02:00
Bas de Jong
6085f6ebe2 Small fixes. 2025-10-12 07:19:27 +02:00
Bas de Jong
ea6264e519 Added ErrorProne for potential bugs. Fixed potential bugs. 2025-10-12 07:14:26 +02:00
lieght
e3bce3889e Renamed VolumeTypes to VolumeControl. Made it thread safe. Added docs to VolumeControl and co.
removed .updateAllVolumes() in favor of auto updating inside enum instead
2025-10-12 02:20:30 +02:00
lieght
b050e06ceb Minor changes in API design 2025-10-12 01:56:06 +02:00
lieght
7631a10838 Renamed VOLUME to MASTERVOLUME for better naming 2025-10-12 01:02:58 +02:00
lieght
ca25338971 Fixed grammer and spelling mistakes 2025-10-12 00:55:02 +02:00
lieght
42e03e0878 Removed file no longer in use 2025-10-12 00:52:02 +02:00
lieght
9b81ee1e65 Added ability to remove a manager from VolumeTypes 2025-10-12 00:39:16 +02:00
lieght
a4b0f890da Merge remote-tracking branch 'origin/166-audiomanager-opslitsen-om-single-responsibility-principle-te-volgen' into 166-audiomanager-opslitsen-om-single-responsibility-principle-te-volgen 2025-10-12 00:37:21 +02:00
lieght
a766b85a75 Fixed AudioVolumemanager, all volumes calculations are now made in VolumeTypes enum 2025-10-12 00:37:02 +02:00
Stef
34ccddaea5 Hotfix for loading clip volume issue (#174) 2025-10-12 00:04:59 +02:00
lieght
73a2fe3da2 Unit tests for MusicManager.java 2025-10-11 23:08:28 +02:00
Stef
d958b9730a Split SoundEffectManager from AudioManager. (#171)
Clips no longer create a new clip instance each time they are played.  A singular clip is made for each resource and is opened/closed when loaded/unloaded. When a clip is played that is already playing it'll stop playback and start again. Clip volume handling isn't done very well.
2025-10-11 23:00:06 +02:00
Bas de Jong
9749d3eee8 Added more flexible dependency injection to MusicManager for unittesting. Moved to event driven design for less complex code and lower runtime complexity. 2025-10-11 20:45:57 +02:00
Bas de Jong
1ecdb9a555 Made all of the updated classes more generic for better flexibility in unittesting 2025-10-11 19:31:55 +02:00
lieght
b101734fd7 Reworked to now use better defined generics and easier to use API. Added AudioResource to be used in changing volume 2025-10-11 06:09:13 +02:00
lieght
123ecc7d3a Working state. Split AudioManager into 3 different branches for easier testing and srp 2025-10-11 04:50:49 +02:00
Ticho Hidding
c1f7a093ef Moves flip dots. all tests pass. can play reversi local. 2025-10-11 00:51:46 +02:00
Ticho Hidding
5dda85248e legal moves now get highlighted in red 2025-10-09 15:27:58 +02:00
Ticho Hidding
5a3490af2e start to reversi logic 2025-10-08 17:27:50 +02:00
Bas de Jong
7f3d858320 AppSettings now also get loaded into the assetmanager 2025-10-08 00:14:40 +02:00
Bas de Jong
e9dfbbd150 Renamed asset folder to resource, made resourceLoader more robust. Completed some TODO's, formatting 2025-10-07 23:54:33 +02:00
Bas de Jong
72e322675e Fixed bugs and oversights 2025-10-07 22:39:47 +02:00
Bas de Jong
ed3cb902e4 Fixed wrong test 2025-10-07 19:55:23 +02:00
Bas de Jong
3c385e27b0 Formatting 2025-10-07 19:47:45 +02:00
Bas de Jong
783cfd22e1 Updated .gitignore 2025-10-07 19:46:14 +02:00
Bas de Jong
16a5b1ce2f Merge remote-tracking branch '2OOP/main' into Development
# Conflicts:
#	.idea/compiler.xml
#	.idea/misc.xml
#	app/src/main/java/org/toop/Main.java
2025-10-07 19:40:55 +02:00
Bas de Jong
6bfa8868bf Moved import 2025-10-07 19:36:42 +02:00
Bas de Jong
748f72352f Merge remote-tracking branch 'origin/Development' into UI 2025-10-07 19:36:14 +02:00
ramollia
e12e48b4fb fast server connection 2025-10-07 12:40:12 +02:00
michiel
a302f0d24d added a song 2025-10-07 12:35:54 +02:00
ramollia
3d9914c927 add: missing localization 2025-10-07 12:08:01 +02:00
Stef
3af182b986 Add a music volume slider (#135) 2025-10-07 11:47:57 +02:00
Stef
58269e917a Split AudioVolumeManager from SoundManager (#134) 2025-10-07 09:45:59 +02:00
ramollia
172b26ed51 ... 2025-10-07 04:46:45 +02:00
ramollia
78aef47bc0 fix: effects volume translation 2025-10-06 23:36:25 +02:00
ramollia
ea8de7881f Merge remote-tracking branch 'origin/UI' into UI
# Conflicts:
#	app/src/main/resources/assets/localization/localization_ka.properties
2025-10-06 23:26:07 +02:00
ramollia
e6fa522f39 add: ai think time.
remove: georgian language pack
2025-10-06 23:25:48 +02:00
Bas de Jong
6d7a8e4c50 Refactored code 2025-10-06 23:10:07 +02:00
Bas de Jong
c6c1c110f7 var to string 2025-10-06 23:04:11 +02:00
Bas de Jong
046a59e915 Added clickable players 2025-10-06 22:59:18 +02:00
Bas de Jong
501b411e34 Merge remote-tracking branch 'origin/UI' into UI 2025-10-06 22:27:27 +02:00
Bas de Jong
95c4a2fc8e finished fx audio volume 2025-10-06 22:27:14 +02:00
ramollia
ce02fc2b88 add: online player list 2025-10-06 22:16:23 +02:00
ramollia
f525fc7ffc add: missing localization 2025-10-06 21:49:35 +02:00
ramollia
1bf3f00322 add: win screen 2025-10-06 21:46:38 +02:00
ramollia
525adfdd04 translated: connection type 2025-10-06 21:15:43 +02:00
ramollia
fcdd4a8fc1 Merge remote-tracking branch 'origin/UI' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/layer/layers/MultiplayerLayer.java
#	app/src/main/java/org/toop/app/layer/layers/game/TicTacToeLayer.java
2025-10-06 21:09:23 +02:00
ramollia
acc9972c80 redesign. add: themes and text size 2025-10-06 21:08:36 +02:00
Bas de Jong
5097e371f3 Added sendChallenge 2025-10-06 20:02:14 +02:00
Bas de Jong
98755b6bed Added connectedLayer with a playerList 2025-10-06 19:52:31 +02:00
Stef
0d771088e1 Merge pull request #129
* Sound data is now stored in memory as a byte[]
2025-10-06 19:08:46 +02:00
Stef
43c577ef17 Volume slider affects clips (#127) 2025-10-06 18:51:04 +02:00
Ticho Hidding
017673452b Merge remote-tracking branch 'origin/UI' into UI 2025-10-06 15:03:55 +02:00
Ticho Hidding
b8488c7289 small fix v2 2025-10-06 15:03:37 +02:00
ramollia
cfde1f8d7f update: style 2025-10-06 11:43:09 +02:00
Ticho Hidding
9144cb453e small fix 2025-10-06 02:34:48 +02:00
Ticho Hidding
20a7fd7a3e serverThread added. cant test cus server doesnt allow "MOVE <int>" 2025-10-06 01:36:58 +02:00
ramollia
33255d5ee6 update: java version 2025-10-05 20:08:43 +02:00
ramollia
ada778fe71 Merge remote-tracking branch 'origin/UI' into UI 2025-10-05 20:07:47 +02:00
ramollia
ab7494616b fix: issues 2025-10-05 20:07:36 +02:00
lieght
08bfb97399 Wip OnlineGameState 2025-10-05 19:55:29 +02:00
ramollia
062fe2e8bc Merge remote-tracking branch 'origin/UI' into UI 2025-10-05 18:24:25 +02:00
ramollia
b903e9b3c4 setup for server thread 2025-10-05 18:24:15 +02:00
Ticho Hidding
a40d30fec7 Merge remote-tracking branch 'origin/UI' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/GameType.java
#	app/src/main/java/org/toop/app/layer/layers/GameLayer.java
2025-10-05 18:22:10 +02:00
Ticho Hidding
98bff669e9 start van match.java. allemaal events 2025-10-05 18:21:28 +02:00
lieght
c2d320ea97 Merge remote-tracking branch 'origin/UI' into UI 2025-10-05 17:52:45 +02:00
ramollia
9ee6bf3067 Merge remote-tracking branch 'origin/UI' into UI 2025-10-05 17:52:40 +02:00
lieght
2198b8a8d9 Fixes gets 2025-10-05 17:52:32 +02:00
ramollia
7e3f13491d fix: some things 2025-10-05 17:52:29 +02:00
lieght
d28fd90b84 Merge remote-tracking branch 'origin/UI' into UI 2025-10-05 17:38:16 +02:00
lieght
b8336ce3d2 Added throw exception 2025-10-05 17:38:01 +02:00
ramollia
b5ac747f77 Merge remote-tracking branch 'origin/UI' into UI 2025-10-05 17:28:46 +02:00
ramollia
369df7a0d1 save locale 2025-10-05 17:28:33 +02:00
lieght
06464945bd Sane default for audio. 2025-10-05 17:23:05 +02:00
lieght
1bab3e12a5 Fixed garbage code. 2025-10-05 17:21:31 +02:00
ramollia
a50c1a8d0d broken merge 2025-10-05 17:18:33 +02:00
ramollia
f780309572 Merge remote-tracking branch 'origin/Settings' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/App.java
#	app/src/main/java/org/toop/app/layer/layers/OptionsLayer.java
#	framework/src/main/java/org/toop/framework/audio/SoundManager.java
2025-10-05 17:03:09 +02:00
ramollia
2362333d46 add: some more languages 2025-10-05 16:59:37 +02:00
lieght
0ab0cd75ba Fixed audio not getting correct volume at settings loading. Added back background music 2025-10-05 01:51:29 +02:00
ramollia
043b789da1 readd: localization 2025-10-04 22:57:12 +02:00
michiel
d7d6a49b98 settings 2025-10-04 22:33:46 +02:00
ramollia
39fa2edb3a add: credits layer 2025-10-04 20:25:59 +02:00
ramollia
e7d606f08e add: options layer 2025-10-04 19:26:30 +02:00
ramollia
db6231c6d0 add: fullscreen option 2025-10-04 18:18:53 +02:00
ramollia
cd2f3c312e start: options 2025-10-04 16:59:28 +02:00
ramollia
2eeca4e418 finish: multiplayer layer 2025-10-04 16:54:58 +02:00
ramollia
4daa379011 remove: addCanvas 2025-10-04 16:30:50 +02:00
ramollia
ba4173f029 add: separators 2025-10-04 16:24:27 +02:00
ramollia
af0db24b0a add: sliders
change: formatting
2025-10-04 15:56:07 +02:00
ramollia
732abedba5 sorry michiel 2025-10-04 15:18:34 +02:00
ramollia
fe6b050702 Merge remote-tracking branch 'origin/UI' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/menu/CreditsMenu.java
#	app/src/main/java/org/toop/app/menu/MainMenu.java
#	app/src/main/java/org/toop/app/menu/OptionsMenu.java
2025-10-04 15:16:39 +02:00
ramollia
b3feab7cb3 change things 2025-10-04 15:16:07 +02:00
ramollia
87a5b301c7 change: layout stuff 2025-10-04 13:52:04 +02:00
ramollia
8fc7f606f9 change: toggles 2025-10-03 23:16:47 +02:00
ramollia
fae5b8bcda added: toggle 2025-10-03 22:34:26 +02:00
ramollia
ac6de04e68 changed how the layer background uses css 2025-10-03 21:44:32 +02:00
michiel
d9a93f24fb credits toegevoegd 2025-10-03 21:44:06 +02:00
ramollia
754c8fea2e started working on the game selection layer 2025-10-03 21:31:42 +02:00
ramollia
82f8d00625 started the great ui redesign 2025-10-03 20:38:50 +02:00
lieght
56a1afe1cd "Fixed double sound bug" 2025-10-03 18:34:48 +02:00
lieght
796c3a2bc6 Added forgotten sound effects 2025-10-03 18:31:13 +02:00
lieght
dd192692bd Working sound effect for clicking, bug when using audio volume changer (changes some sounds to be wrong) 2025-10-03 17:12:50 +02:00
lieght
5a200a8a70 Working audio rocker in settings menu. 2025-10-03 04:42:48 +02:00
lieght
83130806a8 Changed bundled resources to use static base name instead.
Added options menu with selectable language.

Created checkbox for setting fullscreen.

Refactored code to functions
2025-10-03 04:15:36 +02:00
lieght
a5513bf87b Merge remote-tracking branch 'origin/121-settings-menu' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/menu/OptionsMenu.java
#	app/src/main/resources/assets/localization/localization_de.properties
#	app/src/main/resources/assets/localization/localization_en_US.properties
#	app/src/main/resources/assets/localization/localization_es.properties
#	app/src/main/resources/assets/localization/localization_fr.properties
#	app/src/main/resources/assets/localization/localization_it.properties
#	app/src/main/resources/assets/localization/localization_nl.properties
#	app/src/main/resources/assets/localization/localization_zh.properties
2025-10-03 03:25:20 +02:00
lieght
547ea55300 Changed bundled resources to use static base name instead.
Added options menu with selectable language
2025-10-03 03:19:38 +02:00
Ticho Hidding
3471ae54a5 small merge fixes 2025-10-03 02:46:48 +02:00
Ticho Hidding
c020269f6e Merge remote-tracking branch 'origin/UI' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/App.java
#	app/src/main/java/org/toop/app/menu/MainMenu.java
#	app/src/main/java/org/toop/app/menu/game/GameMenu.java
2025-10-03 02:43:39 +02:00
Ticho Hidding
f037412e9a Change language buttons added. Made UI update all text on language change 2025-10-03 02:37:38 +02:00
ramollia
5e1d53e96b tiny portion of refactoring 2025-10-03 01:41:11 +02:00
ramollia
8ac76dd17f Merge remote-tracking branch 'origin/UI' into UI 2025-10-03 01:34:15 +02:00
ramollia
efca808e1c small amount of refactoring. might break everything :). 2025-10-03 01:33:49 +02:00
Bas Antonius de Jong
dd230ad515 Merge pull request #122 from 2OOP/UI
Feature merge
2025-10-03 01:19:45 +02:00
lieght
1dd345a290 Merge remote-tracking branch 'origin/Development' into UI
# Conflicts:
#	app/src/main/java/org/toop/app/App.java
#	app/src/main/java/org/toop/app/menu/MainMenu.java
2025-10-03 01:18:18 +02:00
lieght
e48df5df15 More gitignore 2025-10-03 00:58:57 +02:00
lieght
ef550f353d Pom fixes 2025-10-02 22:07:51 +02:00
Bas Antonius de Jong
a6bd2495ab UI (#107)
* added localization options
//todo add all the strings

* broken push

* merge to UI

* broken push

* Alpha rebase complete, added asset loader for UI branch

* merge to UI

* UI now uses assetmanager

* added NL and EN for all strings currently in UI

* fix small merge error

* Removed no more needed files.

* JDK25

* Removed files no longer in use

* Removed need for manual typecast

* Added ability to load in BundledResource for localization

* Docs and easy font loading. Added interfaces for PreloadResource's

* added German, French, Spanish, Italian and Mandarin Chinese

---------

Co-authored-by: Ticho Hidding <tichohidding@gmail.com>
Co-authored-by: ramollia <@>
2025-10-02 19:34:10 +02:00
Bas Antonius de Jong
477afa142b UI (#106)
* added localization options
//todo add all the strings

* broken push

* merge to UI

* broken push

* Alpha rebase complete, added asset loader for UI branch

* merge to UI

* UI now uses assetmanager

* added NL and EN for all strings currently in UI

* fix small merge error

* Removed no more needed files.

* JDK25

* Removed files no longer in use

* Removed need for manual typecast

* Added ability to load in BundledResource for localization

* Docs and easy font loading. Added interfaces for PreloadResource's

* added German, French, Spanish, Italian and Mandarin Chinese

---------

Co-authored-by: Ticho Hidding <tichohidding@gmail.com>
Co-authored-by: ramollia <@>
2025-10-02 19:25:21 +02:00
Bas Antonius de Jong
d5735be2db Update git (#81)
* new ignore

* Delete .idea/misc.xml

* Delete .idea/compiler.xml

---------

Co-authored-by: Stef <stbuwalda@gmail.com>
2025-09-30 12:07:12 +02:00
Bas Antonius de Jong
f37928307c Update Main.java (#74)
* Update Main.java

* Updated main to be generic.
2025-09-29 13:52:48 +02:00
208 changed files with 10849 additions and 3237 deletions

10
.gitignore vendored
View File

@@ -47,6 +47,9 @@ shelf/
*.iml
*.ipr
*.iws
misc.xml
uiDesigner.xml
##############################
## Eclipse
@@ -75,6 +78,8 @@ dist/
nbdist/
nbactions.xml
nb-configuration.xml
misc.xml
compiler.xml
##############################
## Visual Studio Code
@@ -102,3 +107,8 @@ newgamesver-release-V1.jar
server.properties
gameserver.log.*
gameserver.log
##############################
## JPackage
##############################
jpackage-input

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

22
.idea/compiler.xml generated
View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="pism_framework" />
<module name="pism_game" />
<module name="pism_app" />
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="pism_app" options="" />
<module name="pism_framework" options="" />
<module name="pism_game" options="" />
</option>
</component>
</project>

View File

@@ -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
View File

@@ -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>

View File

@@ -2,7 +2,8 @@
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,java.lang.foreign.Arena,ofAuto,java.lang.foreign.Arena,global,org.toop.framework.audio.AudioPlayer,play" />
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,java.lang.foreign.Arena,ofAuto,java.lang.foreign.Arena,global,org.toop.framework.audio.AudioPlayer,play,java.util.Map,remove,java.util.concurrent.Executors,newSingleThreadScheduledExecutor" />
</inspection_tool>
<inspection_tool class="WriteOnlyObject" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

19
.idea/misc.xml generated
View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<list size="1">
<item index="0" class="java.lang.String" itemvalue="com.google.common.eventbus.Subscribe" />
</list>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ResourceBundleManager">
<custom-resource-bundle>
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization.properties" />
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_de.properties" />
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_es.properties" />
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_fr.properties" />
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_it.properties" />
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_nl.properties" />
<file value="file://$PROJECT_DIR$/app/src/main/resources/assets/localization/Localization_zh.properties" />
<base-name>localization</base-name>
</custom-resource-bundle>
</component>
</project>

View File

@@ -1,15 +1,20 @@
<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>
<main-class>org.toop.Main</main-class>
<maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>25</maven.compiler.target>
<maven.compiler.release>25</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@@ -19,25 +24,41 @@
<artifactId>spotless-maven-plugin</artifactId>
<version>2.46.1</version>
</dependency>
<dependency>
<groupId>org.toop</groupId>
<artifactId>pism_framework</artifactId>
<version>0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.toop</groupId>
<artifactId>pism_game</artifactId>
<version>0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</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>
@@ -68,6 +89,7 @@
<mainClass>org.toop.Main</mainClass>
</transformer>
</transformers>
<finalName>pism</finalName>
</configuration>
</execution>
</executions>
@@ -107,6 +129,56 @@
</java>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<showWarnings>true</showWarnings>
<fork>true</fork>
<executable>${java.home}/bin/javac</executable>
<source>25</source>
<target>25</target>
<release>25</release>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
<arg>
-Xplugin:ErrorProne \
</arg>
<!-- TODO-->
<!-- -Xep:RestrictedApi:ERROR \-->
<!-- -XepOpt:RestrictedApi:annotation=org.toop.annotations.TestsOnly \-->
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
<arg>-XDcompilePolicy=simple</arg>
<arg>--should-stop=ifError=FLOW</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>2.42.0</version>
</path>
</annotationProcessorPaths>
</configuration>
<dependencies>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>2.42.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

View File

@@ -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) {
initSystems();
App.run(args);
}
static void main(String[] args) {
initSystems();
App.run(args);
}
private static void initSystems() {
ResourceManager.loadAssets(new ResourceLoader("app/src/main/resources/assets"));
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();
}
private static void initSystems() throws NetworkingInitializationException {
ResourceManager.loadAssets(new ResourceLoader("app/src/main/resources/assets"));
new Thread(NetworkingClientManager::new).start();
new Thread(SoundManager::new).start();
}
}

View File

@@ -1,114 +1,113 @@
package org.toop.app;
import org.toop.app.menu.MainMenu;
import org.toop.app.menu.Menu;
import org.toop.app.widget.WidgetContainer;
import org.toop.app.widget.display.SongDisplay;
import org.toop.app.widget.popup.QuitPopup;
import org.toop.app.widget.view.MainView;
import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.resource.ResourceManager;
import org.toop.framework.resource.resources.CssAsset;
import org.toop.local.AppContext;
import org.toop.local.AppSettings;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import org.toop.framework.asset.ResourceManager;
import org.toop.framework.asset.resources.CssAsset;
import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow;
public final class App extends Application {
private static Stage stage;
private static StackPane root;
private static Scene scene;
private static int width;
private static int height;
private static int height;
private static int width;
private static boolean isQuitting;
private static class QuitMenu extends Menu {
public QuitMenu() {
final Region background = createBackground("quit_background");
final Text sure = createText("Are you sure?");
final Button yes = createButton("Yes", () -> { stage.close(); });
final Button no = createButton("No", () -> { pop(); isQuitting = false; });
final HBox buttons = new HBox(50, yes, no);
buttons.setAlignment(Pos.CENTER);
final VBox box = new VBox(35, sure, buttons);
box.getStyleClass().add("quit_box");
box.setAlignment(Pos.CENTER);
box.setMaxWidth(350);
box.setMaxHeight(200);
pane = new StackPane(background, box);
pane.getStylesheets().add(ResourceManager.get(CssAsset.class, "quit.css").getUrl());
}
}
public static void run(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
final StackPane root = new StackPane(new MainMenu().getPane());
final StackPane root = WidgetContainer.setup();
final Scene scene = new Scene(root);
scene.getStylesheets().add(((CssAsset) ResourceManager.get("app.css")).getUrl());
stage.setTitle("pism");
stage.setMinWidth(1080);
stage.setMinHeight(720);
stage.setTitle(AppContext.getString("app-title"));
stage.titleProperty().bind(AppContext.bindToKey("app-title"));
stage.setWidth(1080);
stage.setHeight(720);
scene.getRoot();
stage.setMinWidth(1080);
stage.setMinHeight(720);
stage.setOnCloseRequest(event -> {
event.consume();
if (!isQuitting) {
quitPopup();
}
startQuit();
});
stage.setScene(scene);
stage.setResizable(false);
stage.setResizable(true);
stage.show();
App.stage = stage;
App.root = root;
App.scene = scene;
App.width = (int)stage.getWidth();
App.height = (int)stage.getHeight();
new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
new EventFlow().addPostEvent(new AudioEvents.ChangeVolume(0.1)).asyncPostEvent();
App.isQuitting = false;
AppSettings.applySettings();
new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
WidgetContainer.add(Pos.CENTER, new MainView());
WidgetContainer.add(Pos.BOTTOM_RIGHT, new SongDisplay());
}
public static void quitPopup() {
public static void startQuit() {
if (isQuitting) {
return;
}
WidgetContainer.add(Pos.CENTER, new QuitPopup());
isQuitting = true;
push(new QuitMenu());
}
public static void activate(Menu menu) {
pop();
push(menu);
public static void stopQuit() {
isQuitting = false;
}
public static void push(Menu menu) {
root.getChildren().addLast(menu.getPane());
public static void quit() {
stage.close();
System.exit(0); // TODO: This is like dropping a nuke
}
public static void pop() {
root.getChildren().removeLast();
public static void setFullscreen(boolean fullscreen) {
stage.setFullScreen(fullscreen);
width = (int)stage.getWidth();
height = (int)stage.getHeight();
}
public static int getWidth() { return width; }
public static int getHeight() { return height; }
public static void setStyle(String theme, String layoutSize) {
scene.getStylesheets().clear();
scene.getStylesheets().add(ResourceManager.<CssAsset>get("general.css").getUrl());
scene.getStylesheets().add(ResourceManager.<CssAsset>get(theme + ".css").getUrl());
scene.getStylesheets().add(ResourceManager.<CssAsset>get(layoutSize + ".css").getUrl());
}
public static int getWidth() {
return width;
}
public static int getHeight() {
return height;
}
}

View File

@@ -0,0 +1,56 @@
package org.toop.app;
public class GameInformation {
public enum Type {
TICTACTOE(2, 5),
REVERSI(2, 10),
CONNECT4(2, 7),
BATTLESHIP(2, 5);
private final int playerCount;
private final int maxDepth;
Type(int playerCount, int maxDepth) {
this.playerCount = playerCount;
this.maxDepth = maxDepth;
}
public int getPlayerCount() {
return playerCount;
}
public int getMaxDepth() {
return maxDepth;
}
public String getTypeToString() {
String name = this.name();
return switch (name) {
case "TICTACTOE" -> "TicTacToe";
case "REVERSI" -> "Reversi";
case "CONNECT4" -> "Connect4";
case "BATTLESHIP" -> "Battleship";
default -> name;
};
}
}
public static class Player {
public String name = "";
public boolean isHuman = true;
public int computerDifficulty = 1;
public int computerThinkTime = 1;
}
public final Type type;
public final Player[] players;
public GameInformation(Type type) {
this.type = type;
players = new Player[type.getPlayerCount()];
for (int i = 0; i < players.length; i++) {
players[i] = new Player();
}
}
}

View File

@@ -1,21 +0,0 @@
package org.toop.app;
public enum GameType {
TICTACTOE, REVERSI;
public static String toName(GameType type) {
return switch (type) {
case TICTACTOE -> "Tic Tac Toe";
case REVERSI -> "Reversi";
};
}
public static GameType toType(String name) {
return switch (name) {
case "Tic Tac Toe" -> TICTACTOE;
case "Reversi" -> REVERSI;
default -> TICTACTOE;
};
}
}

View 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;
}
}

View 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);
}
}

View File

@@ -0,0 +1,215 @@
package org.toop.app.canvas;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseButton;
import javafx.scene.paint.Color;
import javafx.util.Duration;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
public abstract class GameCanvas {
protected record Cell(float x, float y, float width, float height) {
public boolean isInside(double x, double y) {
return x >= this.x && x <= this.x + width &&
y >= this.y && y <= this.y + height;
}
}
protected final Canvas canvas;
protected final GraphicsContext graphics;
protected final Color color;
protected final Color backgroundColor;
protected final int width;
protected final int height;
protected final int rowSize;
protected final int columnSize;
protected final int gapSize;
protected final boolean edges;
protected final Cell[] cells;
protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer<Integer> onCellClicked, Consumer<Integer> newCellEntered) {
canvas = new Canvas(width, height);
graphics = canvas.getGraphicsContext2D();
this.color = color;
this.backgroundColor = backgroundColor;
this.width = width;
this.height = height;
this.rowSize = rowSize;
this.columnSize = columnSize;
this.gapSize = gapSize;
this.edges = edges;
cells = new Cell[rowSize * columnSize];
final float cellWidth = ((float) width - gapSize * rowSize - gapSize) / rowSize;
final float cellHeight = ((float) height - gapSize * columnSize - gapSize) / columnSize;
for (int y = 0; y < columnSize; y++) {
final float startY = y * cellHeight + y * gapSize + gapSize;
for (int x = 0; x < rowSize; x++) {
final float startX = x * cellWidth + x * gapSize + gapSize;
cells[x + y * rowSize] = new Cell(startX, startY, cellWidth, cellHeight);
}
}
canvas.setOnMouseClicked(event -> {
if (event.getButton() != MouseButton.PRIMARY) {
return;
}
final int column = (int) ((event.getX() / this.width) * rowSize);
final int row = (int) ((event.getY() / this.height) * columnSize);
final Cell cell = cells[column + row * rowSize];
if (cell.isInside(event.getX(), event.getY())) {
event.consume();
onCellClicked.accept(column + row * rowSize);
}
});
render();
}
private void render() {
graphics.setFill(backgroundColor);
graphics.fillRect(0, 0, width, height);
graphics.setFill(color);
for (int x = 0; x < rowSize - 1; x++) {
final float start = cells[x].x + cells[x].width;
graphics.fillRect(start, gapSize, gapSize, height - gapSize * 2);
}
for (int y = 0; y < columnSize - 1; y++) {
final float start = cells[y * rowSize].y + cells[y * rowSize].height;
graphics.fillRect(gapSize, start, width - gapSize * 2, gapSize);
}
if (edges) {
graphics.fillRect(0, 0, width, gapSize);
graphics.fillRect(0, 0, gapSize, height);
graphics.fillRect(width - gapSize, 0, gapSize, height);
graphics.fillRect(0, height - gapSize, width, gapSize);
}
}
public void fill(Color color, int cell) {
final float x = cells[cell].x();
final float y = cells[cell].y();
final float width = cells[cell].width();
final float height = cells[cell].height();
graphics.setFill(color);
graphics.fillRect(x, y, width, height);
}
public void clear(int cell) {
final float x = cells[cell].x();
final float y = cells[cell].y();
final float width = cells[cell].width();
final float height = cells[cell].height();
graphics.clearRect(x, y, width, height);
graphics.setFill(backgroundColor);
graphics.fillRect(x, y, width, height);
}
public void clearAll() {
for (int i = 0; i < cells.length; i++) {
clear(i);
}
}
public void drawDot(Color color, int cell) {
final float x = cells[cell].x() + gapSize;
final float y = cells[cell].y() + gapSize;
final float width = cells[cell].width() - gapSize * 2;
final float height = cells[cell].height() - gapSize * 2;
graphics.setFill(color);
graphics.fillOval(x, y, width, height);
}
public void drawInnerDot(Color color, int cell, boolean slightlyBigger) {
final float x = cells[cell].x() + gapSize;
final float y = cells[cell].y() + gapSize;
float multiplier = slightlyBigger?1.4f:1.5f;
final float width = (cells[cell].width() - gapSize * 2)/multiplier;
final float height = (cells[cell].height() - gapSize * 2)/multiplier;
float offset = slightlyBigger?5f:4f;
graphics.setFill(color);
graphics.fillOval(x + width/offset, y + height/offset, width, height);
}
private void drawDotScaled(Color color, int cell, double scale) {
final float cx = cells[cell].x() + gapSize;
final float cy = cells[cell].y() + gapSize;
final float fullWidth = cells[cell].width() - gapSize * 2;
final float height = cells[cell].height() - gapSize * 2;
final float scaledWidth = (float)(fullWidth * scale);
final float offsetX = (fullWidth - scaledWidth) / 2;
graphics.setFill(color);
graphics.fillOval(cx + offsetX, cy, scaledWidth, height);
}
public Timeline flipDot(Color fromColor, Color toColor, int cell) {
final int steps = 60;
final long duration = 250;
final double interval = duration / (double) steps;
final Timeline timeline = new Timeline();
for (int i = 0; i <= steps; i++) {
final double t = i / (double) steps;
final KeyFrame keyFrame = new KeyFrame(Duration.millis(i * interval),
_ -> {
clear(cell);
final double scale = t <= 0.5 ? 1 - 2 * t : 2 * t - 1;
final Color currentColor = t < 0.5 ? fromColor : toColor;
drawDotScaled(currentColor, cell, scale);
}
);
timeline.getKeyFrames().add(keyFrame);
}
return timeline;
}
public Canvas getCanvas() {
return canvas;
}
}

View 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);
}
}

View File

@@ -0,0 +1,38 @@
package org.toop.app.canvas;
import javafx.scene.paint.Color;
import java.util.function.Consumer;
public final class TicTacToeCanvas extends GameCanvas {
public TicTacToeCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
super(color, Color.TRANSPARENT, width, height, 3, 3, 30, false, onCellClicked,null);
}
public void drawX(Color color, int cell) {
graphics.setStroke(color);
graphics.setLineWidth(gapSize);
final float x = cells[cell].x() + gapSize;
final float y = cells[cell].y() + gapSize;
final float width = cells[cell].width() - gapSize * 2;
final float height = cells[cell].height() - gapSize * 2;
graphics.strokeLine(x, y, x + width, y + height);
graphics.strokeLine(x + width, y, x, y + height);
}
public void drawO(Color color, int cell) {
graphics.setStroke(color);
graphics.setLineWidth(gapSize);
final float x = cells[cell].x() + gapSize;
final float y = cells[cell].y() + gapSize;
final float width = cells[cell].width() - gapSize * 2;
final float height = cells[cell].height() - gapSize * 2;
graphics.strokeOval(x, y, width, height);
}
}

View 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();
}

View 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);
}
}

View 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);
}
}
}
}

View 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);
}
}

View 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);
}
}
}
}

View File

@@ -1,14 +0,0 @@
package org.toop.app.menu;
import org.toop.framework.asset.ResourceManager;
import org.toop.framework.asset.resources.LocalizationAsset;
import org.toop.local.AppContext;
import java.util.Locale;
public final class CreditsMenu extends Menu {
private Locale currentLocale = AppContext.getLocale();
private LocalizationAsset loc = ResourceManager.get("localization.properties");
public CreditsMenu() {
}
}

View File

@@ -1,33 +0,0 @@
package org.toop.app.menu;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import org.toop.app.GameType;
public class GameSelectMenu extends Menu {
public GameSelectMenu(GameType type) {
final Region background = createBackground();
final ComboBox<String> selectedGame = new ComboBox<>();
selectedGame.getItems().add(GameType.toName(GameType.TICTACTOE));
selectedGame.getItems().add(GameType.toName(GameType.REVERSI));
selectedGame.setValue(GameType.toName(type));
final ComboBox<String> selectedMode = new ComboBox<>();
selectedMode.getItems().add("Local");
selectedMode.getItems().add("Online");
selectedMode.setValue("Local");
final HBox selectedContainer = new HBox(10, selectedGame, selectedMode);
final TextField serverIpField = new TextField();
serverIpField.setPromptText("Enter here your server ip address");
VBox box = new VBox(selectedContainer, serverIpField);
pane = new StackPane(background, box);
}
}

View File

@@ -1,37 +0,0 @@
package org.toop.app.menu;
import org.toop.app.App;
import org.toop.app.GameType;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.layout.*;
import org.toop.app.menu.game.TicTacToeMenu;
import org.toop.game.tictactoe.TicTacToe;
public final class MainMenu extends Menu {
public MainMenu() {
final Region background = createBackground();
final Button tictactoe = createButton("Tic Tac Toe", () -> { App.activate(new TicTacToeMenu(new TicTacToe("player 1", true, "player 2", true))); });
final Button reversi = createButton("Reversi", () -> { App.activate(new GameSelectMenu(GameType.REVERSI)); });
final VBox gamesBox = new VBox(10, tictactoe, reversi);
gamesBox.setAlignment(Pos.TOP_LEFT);
gamesBox.setPickOnBounds(false);
gamesBox.setTranslateY(50);
gamesBox.setTranslateX(25);
final Button credits = createButton("Credits", () -> { App.push(new CreditsMenu()); });
final Button options = createButton("Options", () -> { App.push(new OptionsMenu()); });
final Button quit = createButton("Quit", () -> { App.quitPopup(); });
final VBox controlBox = new VBox(10, credits, options, quit);
controlBox.setAlignment(Pos.BOTTOM_LEFT);
controlBox.setPickOnBounds(false);
controlBox.setTranslateY(-50);
controlBox.setTranslateX(25);
pane = new StackPane(background, gamesBox, controlBox);
}
}

View File

@@ -1,47 +0,0 @@
package org.toop.app.menu;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.text.Text;
public abstract class Menu {
protected Pane pane;
public Pane getPane() { return pane; }
public Region createBackground(String css) {
final Region background = new Region();
background.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
background.getStyleClass().add(css);
return background;
}
public Region createBackground() {
return createBackground("background");
}
public Text createText(String css, String x) {
final Text text = new Text(x);
text.getStyleClass().add(css);
return text;
}
public Text createText(String x) {
return createText("text", x);
}
public Button createButton(String css, String x, Runnable runnable) {
final Button button = new Button(x);
button.setOnAction(_ -> runnable.run());
button.getStyleClass().add(css);
return button;
}
public Button createButton(String x, Runnable runnable) {
return createButton("button", x, runnable);
}
}

View File

@@ -1,14 +0,0 @@
package org.toop.app.menu;
import org.toop.framework.asset.ResourceManager;
import org.toop.framework.asset.resources.LocalizationAsset;
import org.toop.local.AppContext;
import java.util.Locale;
public final class OptionsMenu extends Menu {
private Locale currentLocale = AppContext.getLocale();
private LocalizationAsset loc = ResourceManager.get("localization.properties");
public OptionsMenu() {
}
}

View File

@@ -1,99 +0,0 @@
package org.toop.app.menu.game;
import javafx.geometry.Pos;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import org.toop.app.App;
import org.toop.app.menu.MainMenu;
import org.toop.app.menu.Menu;
public abstract class GameMenu extends Menu {
protected final class Cell {
public float x;
public float y;
public float width;
public float height;
public Cell(float x, float y, float width, float height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public boolean check(float x, float y) {
return x >= this.x && y >= this.y && x <= this.x + width && y <= this.y + height;
}
}
protected final int size;
protected final Canvas canvas;
protected final GraphicsContext graphics;
protected final int rows;
protected final int columns;
protected final int gapSize;
protected final Cell[] cells;
protected GameMenu(int rows, int columns, int gapSize) {
final int size = Math.min(App.getWidth(), App.getHeight()) / 5 * 4;
final Canvas canvas = new Canvas(size, size);
final GraphicsContext graphics = canvas.getGraphicsContext2D();
this.size = size;
this.canvas = canvas;
this.graphics = graphics;
this.rows = rows;
this.columns = columns;
this.gapSize = gapSize;
cells = new Cell[rows * columns];
final float cellWidth = ((float)size - (rows - 1) * gapSize) / rows;
final float cellHeight = ((float)size - (columns - 1) * gapSize) / rows;
for (int y = 0; y < columns; y++) {
final float startY = y * cellHeight + y * gapSize;
for (int x = 0; x < rows; x++) {
final float startX = x * cellWidth + x * gapSize;
cells[y * rows + x] = new Cell(startX, startY, cellWidth, cellHeight);
}
}
final Region background = createBackground();
final Text player1 = createText("player_1", "Player 1");
final Text player2 = createText("player_2", "Player 2");
final HBox playersContainer = new HBox(100, player1, player2);
playersContainer.setAlignment(Pos.TOP_CENTER);
playersContainer.setPickOnBounds(false);
playersContainer.setTranslateY(50);
final Button hint = createButton("Hint", () -> {});
final Button back = createButton("Back", () -> { App.activate(new MainMenu()); });
final VBox controlContainer = new VBox(hint, back);
StackPane.setAlignment(controlContainer, Pos.BOTTOM_LEFT);
controlContainer.setPickOnBounds(false);
pane = new StackPane(background, canvas, playersContainer, controlContainer);
}
}

View File

@@ -1,133 +0,0 @@
package org.toop.app.menu.game;
import javafx.scene.paint.Color;
import org.toop.game.Game;
import org.toop.game.Player;
import org.toop.game.tictactoe.TicTacToe;
import org.toop.game.tictactoe.TicTacToeAI;
import javax.management.RuntimeErrorException;
import java.util.concurrent.*;
public final class TicTacToeMenu extends GameMenu {
private final TicTacToe game;
private final TicTacToeAI ai;
// private final ExecutorService executor = Executors.newFixedThreadPool(1);
private final BlockingQueue<Game.Move> moveQueue = new LinkedBlockingQueue<>();
public TicTacToeMenu(TicTacToe game) {
super(3, 3, 10);
graphics.setFill(Color.CYAN);
for (int x = 1; x < rows; x++) {
graphics.fillRect(cells[x].x - gapSize, 0, gapSize, size);
}
for (int y = 1; y < columns; y++) {
graphics.fillRect(0, cells[y * rows].y - gapSize, size, gapSize);
}
this.game = game;
ai = new TicTacToeAI();
canvas.setOnMouseClicked(event -> {
for (int i = 0; i < cells.length; i++) {
if (cells[i].check((float) event.getX(), (float) event.getY())) {
final Game.Move move = new Game.Move(i, game.getCurrentPlayer().values()[0]);
play(move);
}
}
});
new Thread(this::gameThread).start();
}
private void play(Game.Move move) {
final Game.Move[] legalMoves = game.getLegalMoves();
boolean isLegal = false;
for (final Game.Move legalMove : legalMoves) {
if (legalMove.position() == move.position() && legalMove.value() == move.value()) {
isLegal = true;
break;
}
}
if (!isLegal) {
return;
}
try { moveQueue.put(move); }
catch (InterruptedException _) {}
}
private void placeX(int cell) {
graphics.setStroke(Color.ORANGERED);
graphics.setLineWidth(gapSize);
final float x = cells[cell].x + gapSize;
final float y = cells[cell].y + gapSize;
final float width = cells[cell].width - gapSize * 2;
final float height = cells[cell].height - gapSize * 2;
graphics.strokeLine(x, y, x + width, y + height);
graphics.strokeLine(x + width, y, x, y + height);
}
private void placeO(int cell) {
graphics.setStroke(Color.DEEPSKYBLUE);
graphics.setLineWidth(gapSize);
final float x = cells[cell].x + gapSize;
final float y = cells[cell].y + gapSize;
final float width = cells[cell].width - gapSize * 2;
final float height = cells[cell].height - gapSize * 2;
graphics.strokeOval(x, y, width, height);
}
private void gameThread() {
boolean running = true;
while(running) {
final Player currentPlayer = game.getCurrentPlayer();
try {
Game.Move move;
if (!currentPlayer.isAI()) {
try { move = moveQueue.take(); }
catch (InterruptedException _) { return; }
} else {
move = ai.findBestMove(game, 9);
}
assert move != null;
final Game.State state = game.play(move);
if (move.value() == 'X') {
placeX(move.position());
} else {
placeO(move.position());
}
switch (state) {
case NORMAL: break;
case DRAW:
case LOSE:
case WIN:
running = false;
break;
}
} catch (RuntimeException e) {
return;
}
}
}
}

View 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;
}
}

View File

@@ -0,0 +1,5 @@
package org.toop.app.widget;
public interface Updatable {
void update();
}

View 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();
}
}

View 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;
});
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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));
}
}

View 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;
}
}

View File

@@ -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()
)
);
}
}

View 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);
}
}

View File

@@ -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);
}
}

View 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();
});
}
}

View File

@@ -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()
)
);
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View 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();
}
}

View 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);
}
}

View File

@@ -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
));
}
}

View 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
));
}
}

View 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
));
}
}

View 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
));
}
}

View 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()
);
}
}

View 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);
}
});
}
}

View File

@@ -1,14 +1,67 @@
package org.toop.local;
import java.util.Locale;
import java.util.MissingResourceException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.framework.resource.ResourceManager;
import org.toop.framework.resource.resources.LocalizationAsset;
import java.util.Locale;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
public class AppContext {
private static Locale currentLocale = Locale.getDefault();
private static final LocalizationAsset localization = ResourceManager.get("localization");
private static Locale locale = Locale.forLanguageTag("en");
public static void setCurrentLocale(Locale locale) {
currentLocale = locale;
private static final ObjectProperty<Locale> localeProperty = new SimpleObjectProperty<>(locale);
private static final Logger logger = LogManager.getLogger(AppContext.class);
public static LocalizationAsset getLocalization() {
return localization;
}
public static void setLocale(Locale locale) {
AppContext.locale = locale;
localeProperty.set(locale);
}
public static Locale getLocale() {
return currentLocale;
return locale;
}
public static String getString(String key) {
assert localization != null;
// TODO: Gebruik ResourceBundle.getBundle() zodat de fallback automatisch gaat.
// Hiervoor zou de assetManager aangepast moeten worden.
try{ // Main return
return localization.getString(key, locale);
}
catch (MissingResourceException e) {
logger.error("Missing resource key: {}, in bundle: {}. ", key, locale, e);
}
try{ // Fallback return
return localization.getString(key, localization.getFallback());
}
catch (MissingResourceException e) {
logger.error("Missing resource key: {}, in default bundle!", key, e);
}
// Default return
return "MISSING RESOURCE";
}
public static StringBinding bindToKey(String key) {
return Bindings.createStringBinding(
() -> localization.getString(key, locale),
localeProperty
);
}
}

View File

@@ -0,0 +1,108 @@
package org.toop.local;
import org.toop.app.App;
import org.toop.framework.audio.VolumeControl;
import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.resource.ResourceManager;
import org.toop.framework.resource.ResourceMeta;
import org.toop.framework.resource.resources.SettingsAsset;
import org.toop.framework.settings.Settings;
import java.io.File;
import java.util.Locale;
public class AppSettings {
private static SettingsAsset settingsAsset;
public static void applySettings() {
settingsAsset = getPath();
if (!settingsAsset.isLoaded()) {
settingsAsset.load();
}
checkSettings();
Settings settingsData = settingsAsset.getContent();
AppContext.setLocale(Locale.of(settingsData.locale));
App.setFullscreen(settingsData.fullScreen);
new EventFlow()
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.volume, VolumeControl.MASTERVOLUME))
.asyncPostEvent();
new EventFlow()
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.fxVolume, VolumeControl.FX))
.asyncPostEvent();
new EventFlow()
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.musicVolume, VolumeControl.MUSIC))
.asyncPostEvent();
App.setStyle(settingsAsset.getTheme(), settingsAsset.getLayoutSize());
}
public static SettingsAsset getPath() {
if (settingsAsset == null) {
String os = System.getProperty("os.name").toLowerCase();
String basePath;
if (os.contains("win")) {
basePath = System.getenv("APPDATA");
if (basePath == null) {
basePath = System.getProperty("user.home");
}
} else if (os.contains("mac")) {
basePath = System.getProperty("user.home") + "/Library/Application Support";
} else {
basePath = System.getProperty("user.home") + "/.config";
}
File settingsFile =
new File(basePath + File.separator + "ISY1" + File.separator + "settings.json");
// this.settingsAsset = new SettingsAsset(settingsFile);
ResourceManager.addAsset(new ResourceMeta<>("settings.json", new SettingsAsset(settingsFile)));
}
return ResourceManager.get("settings.json");
}
public static SettingsAsset getSettings() {
return settingsAsset;
}
public static void checkSettings() {
Settings s = settingsAsset.getContent();
boolean changed = false;
if (s.showTutorials == null) {
settingsAsset.setTutorialFlag(true);
changed = true;
}
if (s.firstReversi == null) {
settingsAsset.setFirstReversi(true);
changed = true;
}
if (s.firstTTT == null) {
settingsAsset.setFirstTTT(true);
changed = true;
}
if (s.firstConnect4 == null) {
settingsAsset.setFirstConnect4(true);
changed = true;
}
if (changed) {
getSettings().save();
}
}
public static void doDefaultSettings() {
settingsAsset.setFirstConnect4(true);
settingsAsset.setFirstTTT(true);
settingsAsset.setFirstReversi(true);
settingsAsset.setLocale("en");
settingsAsset.setTheme("dark");
settingsAsset.setFullscreen(false);
settingsAsset.setVolume(100);
settingsAsset.setFxVolume(20);
settingsAsset.setMusicVolume(15);
settingsAsset.setTutorialFlag(true);
settingsAsset.setLayoutSize("medium");
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1,17 +0,0 @@
# Window title
windowTitle=ISY Games Selector
# Main Menu buttons
mainMenuSelectTicTacToe=Tic Tac Toe
mainMenuSelectReversi=Reversi
mainMenuSelectSudoku=Sudoku
mainMenuSelectBattleship=Battleship
mainMenuSelectOther=Other
mainMenuSelectCredits=Credits
mainMenuSelectOptions=Options
mainMenuSelectQuit=Quit
# Quit Menu text and buttons
quitMenuTextSure=Are you sure?
quitMenuButtonYes=Yes
quitMenuButtonNo=No

View File

@@ -0,0 +1,99 @@
accept=\u0642\u0628\u0648\u0644
ai=\u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0635\u0646\u0627\u0639\u064a
app-title=\u0645\u062e\u062a\u0627\u0631 \u0627\u0644\u0643\u0627\u0645 \u0627\u0644\u0645\u062e\u062a\u0627\u0631
are-you-sure=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f?
back=\u0627\u0644\u0631\u062c\u0648\u0639
cancel=\u0625\u0644\u063a\u0627\u0621
challenge=\u062a\u062d\u062f\u064a
connect4=Connect 4
computer-difficulty=\u0635\u0639\u0648\u0628 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631
computer-think-time=\u0648\u0642\u062a \u062a\u0641\u0643\u064a\u0631 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631
computer=\u0643\u0645\u0628\u064a\u0648\u062a\u0631
connect=\u0627\u062a\u0635\u0627\u0644
credits=\u0627\u0644\u0645\u0633\u0627\u0647\u0645\u0629
dark=\u0638\u0644\u0627\u0645
deny=\u0631\u0641\u0636
developers=\u0627\u0644\u0645\u0637\u0648\u0631\u0648\u0646
disconnect=\u0641\u0635\u0644 \u0627\u0644\u0627\u062a\u0635\u0627\u0644
effects-volume=\u0635\u0648\u062a \u0627\u0644\u062a\u0623\u062b\u064a\u0631\u0627\u062a
enter-the-server-ip=\u0623\u062f\u062e\u0644 \u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0633\u064a\u0631\u0641\u0631
enter-the-server-port=\u0623\u062f\u062e\u0644 \u0645\u0646\u0641\u0630 \u0627\u0644\u0633\u064a\u0631\u0641\u0631
enter-your-name=\u0623\u062f\u062e\u0644 \u0627\u0633\u0645\u0643
error=\u062e\u0637\u0623
exit=\u062e\u0631\u0648\u062c
forfeit=\u0627\u0633\u062a\u0643\u0644\u0627\u0644
fullscreen=\u0643\u0627\u0645\u0644 \u0627\u0644\u0634\u0627\u0634\u0629
game-over=\u0627\u0646\u062a\u0647\u062a \u0627\u0644\u0644\u0639\u0628\u0629
general=\u0639\u0627\u0645
high-contrast=\u062A\u0628\u0627\u0646\u064A\u0629 \u0639\u0627\u0644\u064A
invalid-username=\u0627\u0633\u0645 \u063a\u064a\u0631 \u0635\u062d\u064a\u062d
ip-address=\u0639\u0646\u0648\u0627\u0646 IP
is-not-a-valid-ip-address=\u0644\u064a\u0633 \u0639\u0646\u0648\u0627\u0646 IP \u0635\u062d\u064a\u062d
is-not-a-valid-port=\u0644\u064a\u0633 \u0645\u0646\u0641\u0630 \u0635\u062d\u064a\u062d
language=\u0644\u063a\u0629
large=\u0633\u064a\u0631
layout-size=\u062d\u062c\u0645 \u0627\u0644\u062a\u0635\u0645\u064a\u0645
light=\u0636\u0624\u0621
local=\u0645\u062d\u0644\u064a
localization=\u062a\u0639\u0631\u064a\u0628 \u0627\u0644\u0644\u063a\u0629
master-volume=\u0635\u0648\u062a \u0627\u0644\u0645\u0633\u062a\u0648\u0649
medium=\u0645\u062a\u0648\u0633\u0637
merge-commander=Merge Commander
moral-support=\u062f\u0639\u0645 \u0623\u0639\u0635\u0627\u0628\u064a
music-volume=\u0635\u0648\u062a \u0627\u0644\u0645\u0648\u0633\u064a\u0642\u0649
name=\u0627\u0633\u0645
never=\u0644\u0627\u060c \u0644\u0627 \u0623\u0631\u064A\u062F \u0623\u0646 \u0623\u0631\u0649 \u0623\u064A \u062F\u0631\u0648\u0633 \u0639\u0644\u0649 \u0627\u0644\u0625\u0637\u0644\u0627\u0642.
no=\u0644\u0627
ok=\u0645\u0648\u0627\u0641\u0642
online=\u0645\u062a\u0635\u0644
opengl=OpenGL
options=\u062e\u064a\u0627\u0631\u0627\u062a
play=\u0644\u0639\u0628
player-name=\u0627\u0633\u0645 \u0627\u0644\u0644\u0627\u0639\u0628
player=\u0644\u0627\u0639\u0628
please-enter-your-name=\u064a\u0631\u062c\u0649 \u0623\u062f\u062e\u0644 \u0627\u0633\u0645\u0643
port=\u0645\u0646\u0641\u0630
product-owner=\u0635\u0627\u062d\u0628 \u0627\u0644\u0645\u0646\u062a\u062c
quit=\u062e\u0631\u0648\u062c
reversi=\u0631\u064a\u0641\u0631\u0633\u064a
scrum-master=Scrum Master
send=\u0625\u0631\u0633\u0627\u0644
server-information=\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u0633\u064a\u0631\u0641\u0631
small=\u0635\u063a\u064a\u0631
style=\u0623\u0633\u0644\u0648\u0628
the-game-ended-in-a-draw=\u0627\u0646\u062a\u0647\u062a \u0627\u0644\u0644\u0639\u0628\u0629 \u0628\u062a\u0639\u0627\u062f\u0644
theme=\u0645\u0648\u0636\u0648\u0639
tic-tac-toe=\u062a\u064a\u0643 \u062a\u0627\u0643 \u062a\u0648
tictactoe1 =\u0645\u0631\u062d\u0628\u064b\u0627 \u0628\u0643 \u0641\u064a \u0644\u0639\u0628\u0629 \u0625\u0643\u0633-\u0623\u0648! \u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0642\u064a\u0627\u0645 \u0628\u062d\u0631\u0643\u062a\u0643 \u0628\u0627\u0644\u0646\u0642\u0631 \u0639\u0644\u0649 \u0623\u064a \u0645\u0646 \u0627\u0644\u0645\u0631\u0628\u0639\u0627\u062a \u0627\u0644\u062a\u0633\u0639\u0629 \u0639\u0644\u0649 \u0627\u0644\u0644\u0648\u062d\u0629. \u0627\u0644\u0645\u062b\u0627\u0644 \u0623\u0639\u0644\u0627\u0647:
tictactoe2 =\u064a\u0641\u0648\u0632 \u0627\u0644\u0644\u0627\u0639\u0628 \u0639\u0646\u062f\u0645\u0627 \u064a\u062d\u0635\u0644 \u0639\u0644\u0649 \u062b\u0644\u0627\u062b \u0642\u0637\u0639 \u0645\u062a\u062a\u0627\u0644\u064a\u0629 ? \u0623\u0641\u0642\u064a\u064b\u0627 \u0623\u0648 \u0639\u0645\u0648\u062f\u064a\u064b\u0627 \u0623\u0648 \u0642\u0637\u0631\u064a\u064b\u0627. \u0641\u064a \u0627\u0644\u0645\u062b\u0627\u0644 \u0623\u0639\u0644\u0627\u0647\u060c \u064a\u0641\u0648\u0632 \u0627\u0644\u0644\u0627\u0639\u0628 \u0628\u0635\u0641 \u0642\u0637\u0631\u064a \u0645\u0646 \u062b\u0644\u0627\u062b \u0642\u0637\u0639
to-a-game-of=\u0625\u0644\u0649 \u0644\u0639\u0628\u0629 \u0645\u0646
tutorial=\u0647\u0644 \u062a\u0631\u064a\u062f \u0645\u0634\u0627\u0647\u062f\u0629 \u062f\u0644\u064a\u0644 \u0644\u0647\u0630\u0627 \u0627\u0644\u0644\u0639\u0628\u0629\u061f
volume=\u0635\u0648\u062a
windowed=\u0641\u064a \u0646\u0641\u0630\u0629
yes=\u0646\u0639\u0645
you-lost-against=\u0623\u0646\u062a \u062e\u0633\u0631\u062a \u0636\u062f
you-were-challenged-by=\u062a\u062d\u062f\u064a\u062a \u0645\u0646
you-win=\u0623\u0646\u062a \u062a\u0641\u0648\u0632
>=>
<=<
connect4.1=\u0645\u0631\u062d\u0628\u0627 \u0628\u0643 \u0641\u064a \u0644\u0639\u0628\u0629 Connect 4! \u064a\u0645\u0643\u0646\u0643 \u062a\u0633\u0645\u064a\u0629 \u0627\u0644\u0644\u0639\u0628 \u0645\u0646 \u0637\u0631\u0641 \u0645\u0646 \u0627\u0644\u0639\u0645\u0648\u062f\u0627\u062a. \u0633\u064a\u062a\u0645 \u0648\u0636\u0639 \u0627\u0644\u0644\u062d\u0629 \u0627\u0644\u0623\u0642\u0644 \u0641\u064a \u062a\u0644\u0643 \u0627\u0644\u0639\u0645\u0648\u062f\u0629 \u0627\u0644\u0645\u0644\u0623\u0629 \u0627\u0644\u062a\u064a \u0644\u064a\u0633\u062a\u0645\u0644\u0623 \u0627\u0644\u0645\u0644\u0623\u0629.
connect4.2=\u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0641\u0648\u0632 \u0628\u0647\u0632\u0645 \u0623\u0631\u062c\u0639 \u0645\u0646 \u0627\u0644\u0642\u0637\u0639 \u0627\u0644\u0641\u064a \u0627\u0644\u0623\u0641\u0642 \u0623\u0648 \u0627\u0644\u0645\u064a\u0646 \u0623\u0648 \u0623\u0641\u0642 \u0639\u0644\u0649 \u0627\u0644\u0645\u0644\u0623\u0629!
reversi1=\u0645\u0631\u062d\u0628\u0627 \u0628\u0643 \u0641\u064a \u0644\u0639\u0628\u0629 Reversi! \u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0644\u0639\u0628 \u0628\u0627\u0644\u0646\u0642\u0631 \u0639\u0644\u0649 \u0623\u064a \u0646\u0642\u0637\u0629 \u0645\u0634\u0631\u0641\u0629.
reversi2=\u0639\u0646\u062f\u0645\u0627 \u062a\u0646\u0642\u0631 \u0639\u0644\u0649 \u0646\u0642\u0637\u0629 \u0633\u064a\u062a\u063a\u064a\u0631 \u062c\u0645\u064a\u0639 \u0627\u0644\u0644\u0648\u0639\u0627\u0628 \u0628\u064a\u0646 \u0645\u0643\u0627\u0646 \u062a\u0636\u0639 \u0627\u0644\u0646\u0642\u0637\u0629 \u0648\u0646\u0642\u0637\u0629 \u0627\u0644\u0644\u0648\u0639 \u0627\u0644\u062a\u0627\u0644\u064a \u0627\u0644\u0645\u0648\u062c\u0648\u062f.
reversi3=\u0645\u0631\u062a\u0643 \u0642\u062f \u064a\u062a\u063a\u0627\u0637 \u0625\u0630\u0627 \u0644\u0645 \u064a\u0643\u0646 \u0647\u0646\u0627\u0643 \u062d\u0631\u0643 \u0642\u0627\u0646\u0648\u0646\u064a.
reversi4=\u0627\u0644\u0644\u0627\u0639\u0628 \u0627\u0644\u0630\u064a \u064a\u0641\u0648\u0632 \u0641\u064a \u0646\u0647\u0627\u064a\u0629 \u0627\u0644\u0644\u0639\u0628 \u0647\u0648 \u0627\u0644\u0630\u064a \u064a\u0643\u0648\u0646 \u0644\u062f\u064a\u0647 \u0627\u0644\u0623\u0643\u062b\u0631 \u0645\u0646 \u0627\u0644\u0644\u0648\u0639\u0627\u0628 \u0639\u0644\u0649 \u0627\u0644\u0644\u0648\u062d\u0629.
tutorialstring=\u0627\u0644\u062f\u0631\u0633 \u0627\u0644\u062a\u0648\u0636\u064a\u062d\u064a
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629
chinese=\u4e2d\u6587 (\u0627\u0644\u0635\u064a\u0646\u064a\u0629)
dutch=Nederlands (\u0627\u0644\u0647\u0648\u0644\u0646\u062f\u064a\u0629)
english=English (\u0627\u0644\u0625\u0646\u062c\u0644\u064a\u0632\u064a\u0629)
french=Fran\u00e7ais (\u0627\u0644\u0641\u0631\u0646\u0633\u064a\u0629)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u0627\u0644\u062c\u0648\u0631\u062c\u064a\u0629)
german=Deutsch (\u0627\u0644\u0623\u0644\u0645\u0627\u0646\u064a\u0629)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\u0627\u0644\u0647\u0646\u062f\u064a\u0629)
italian=Italiano (\u0627\u0644\u0625\u064a\u0637\u0627\u0644\u064a\u0629)
japanese=\u65e5\u672c\u8a9e (\u0627\u0644\u064a\u0627\u0628\u0627\u0646\u064a\u0629)
korean=\ud55c\uad6d\uc5b4 (\u0627\u0644\u0643\u0648\u0631\u064a\u0629)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\u0627\u0644\u0631\u0648\u0633\u064a\u0629)
spanish=Espa\u00f1ol (\u0627\u0644\u0625\u0633\u0628\u0627\u0646\u064a\u0629)

View File

@@ -1,17 +1,101 @@
# Window title
windowTitle=ISY Spiele-Auswahl
accept=Akzeptieren
ai=K\u00fcnstliche Intelligenz
app-title=ISY Spiele-Auswahl
are-you-sure=Sind Sie sicher?
back=Zur\u00fcck
cancel=Abbrechen
challenge=Herausforderung
computer-difficulty=Computer Schwierigkeit
computer-think-time=Computer Denkzeit
computer=Computer
connect=Verbinden
connect4=Connect 4
# Main Menu buttons
mainMenuSelectTicTacToe=Tic Tac Toe
mainMenuSelectReversi=Reversi
mainMenuSelectSudoku=Sudoku
mainMenuSelectBattleship=Flottenman\u00F6ver
mainMenuSelectOther=Andere
mainMenuSelectCredits=Credits
mainMenuSelectOptions=Optionen
mainMenuSelectQuit=Beenden
credits=Credits
dark=Dunkel
deny=Ablehnen
developers=Entwickler
disconnect=Trennen
effects-volume=Effektlautst\u00e4rke
enter-the-server-ip=Server-IP eingeben
enter-the-server-port=Server-Port eingeben
enter-your-name=Geben Sie Ihren Namen ein
error=Fehler
exit=Beenden
forfeit=Aufgeben
fullscreen=Vollbild
game-over=Spiel vorbei
general=Allgemein
high-contrast=Hoher Kontrast
invalid-username=Ung\u00fcltiger Benutzername
ip-address=IP-Adresse
is-not-a-valid-ip-address=ist keine g\u00fcltige IP-Adresse
is-not-a-valid-port=ist kein g\u00fcltiger Port
language=Sprache
large=Gro\u00df
layout-size=Layout-Gr\u00f6\u00dfe
light=Hell
local=Lokal
localization=Lokalisierung
master-volume=Gesamtlautst\u00e4rke
medium=Mittel
merge-commander=Merge Commander
moral-support=Mentale Unterst\u00fctzung
music-volume=Musiklautst\u00e4rke
name=Name
never=Nein, ich m\u00f6chte niemals irgendwelche Tutorials sehen.
no=Nein
ok=Ok
online=Online
opengl=OpenGL
options=Optionen
play=Spielen
player-name=Spielername
player=Spieler
please-enter-your-name=Bitte geben Sie Ihren Namen ein
port=Port
product-owner=Produktverantwortlicher
quit=Beenden
reversi=Reversi
scrum-master=Scrum Master
send=Senden
server-information=Serverinformationen
small=Klein
style=Stil
the-game-ended-in-a-draw=Das Spiel endete unentschieden
theme=Thema
tic-tac-toe=Tic Tac Toe
tictactoe1 =Willkommen beim Spiel Tic Tac Toe! Du kannst deinen Zug machen, indem du auf eines der 9 Felder auf dem Spielfeld klickst. Beispiel oben:
tictactoe2 =Ein Spieler gewinnt, wenn er drei Steine in einer Reihe hat ? horizontal, vertikal oder diagonal. Im obigen Beispiel gewinnt der Spieler mit einer diagonalen Reihe von drei Steinen.
to-a-game-of=zu einem Spiel von
tutorial=M\u00f6chtest du ein Tutorial f\u00fcr dieses Spiel sehen?
# Quit Menu text and buttons
quitMenuTextSure=Bist du sicher?
quitMenuButtonYes=Ja
quitMenuButtonNo=Nein
volume=Lautst\u00e4rke
windowed=Fenstermodus
yes=Ja
you-lost-against=Sie haben gegen ... verloren
you-were-challenged-by=Sie wurden herausgefordert von ...
you-win=Sie gewinnen
>=>
<=<
connect4.1=Willkommen beim Spiel Connect 4! Du kannst einen Zug machen, indem du auf eine der Spalten klickst. Der Zug wird in der niedrigsten noch freien Reihe dieser Spalte platziert.
connect4.2=Du kannst gewinnen, indem du 4 Spielsteine deiner Farbe horizontal, diagonal oder vertikal verbindest! Siehe das obige Beispiel.
reversi1=Willkommen beim Spiel Reversi! Du kannst einen Zug machen, indem du auf einen der leicht transparenten Punkte klickst.
reversi2=Wenn du auf einen Punkt klickst, werden alle Spielsteine dazwischen umgedreht, bis zum n<>chsten Punkt. Siehe das Beispiel oben, wo Gelb die zu drehenden Steine ist.
reversi3=Dein Zug kann <20>bersprungen werden, wenn es keinen legalen Zug gibt. Dein Gegner spielt dann weiter, bis du einen legalen Zug machen kannst.
reversi4=Der Spieler, der am Ende die meisten Steine auf dem Brett hat, gewinnt.
tutorialstring=Tutorial
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabisch)
chinese=\u4e2d\u6587 (Chinesisch)
dutch=Nederlands (Niederl\u00e4ndisch)
english=English (Englisch)
french=Fran\u00e7ais (Franz\u00f6sisch)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgisch)
german=Deutsch
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
italian=Italiano (Italienisch)
japanese=\u65e5\u672c\u8a9e (Japanisch)
korean=\ud55c\uad6d\uc5b4 (Koreanisch)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russisch)
spanish=Espa\u00f1ol (Spanisch)

View File

@@ -0,0 +1,103 @@
accept=Accept
ai=Artificial Intelligence
app-title=ISY Games Selector
are-you-sure=Are you sure?
back=Back
cancel=Cancel
challenge=Challenge
computer-difficulty=Computer difficulty
computer-think-time=Computer think time
computer=Computer
connect=Connect
credits=Credits
dark=Dark
deny=Deny
developers=Developers
disconnect=Disconnect
effects-volume=Effects Volume
enter-the-server-ip=Enter the server ip
enter-the-server-port=Enter the server port
enter-your-name=Enter your name
error=Error
exit=Exit
forfeit=Forfeit
fullscreen=Fullscreen
game-over=Game Over
general=General
high-contrast=High contrast
invalid-username=invalid username
ip-address=IP address
is-not-a-valid-ip-address=is not a valid-ip address
is-not-a-valid-port=is not a valid port
language=Language
large=Large
layout-size=Layout Size
light=Light
local=Local
localization=Localization
master-volume=Master Volume
medium=Medium
merge-commander=Merge Commander
moral-support=Moral Support
music-volume=Music Volume
name=Name
no=No
never=No, I never want to see any tutorials
ok=Ok
online=Online
opengl=OpenGL
options=Options
play=Play
player-name=Player name
player=Player
please-enter-your-name=Please enter your name
port=Port
product-owner=Product Owner
quit=Quit
reversi=Reversi
scrum-master=Scrum Master
send=Send
server-information=Server information
small=Small
style=Style
the-game-ended-in-a-draw=The game ended in a draw
theme=Theme
tic-tac-toe=Tic Tac Toe
tictactoe1 =Welcome to the game of Tic Tac Toe! You can make your move by clicking on any of the 9 squares on the board. Example above:
tictactoe2 =A player wins by getting 3 pieces in a row - horizontally, vertically or diagonally. In the example above, the player wins with a diagonal row of three pieces.
tutorial=Do you want a tutorial for this game?
connect4=Connect 4
to-a-game-of=to a game of
volume=Volume
windowed=Windowed
yes=Yes
you-lost-against=You lost against
you-were-challenged-by=You were challenged by
you-win=You win
>=>
<=<
// tutorial
connect4.1=Welcome to the game of Connect 4! You can make a move by clicking one of the columns. The move will be placed in the lowest row of that column that is not filled yet.
connect4.2=You can win by getting 4 pieces of your row horizontally, diagonally or vertically! For an example, see above.
reversi1=Welcome to the game of Reversi! You can make a move by clicking on one of the slightly transparent dots.
reversi2=Clicking on a dot will flip all the moves between where you place the dot and the next dot it finds. See the example above, where yellow is the moves to be flipped.
reversi3=Your turn may be skipped if there is no legal move. This will let your opponent play again until you get an opportunity at a legal move.
reversi4=The player who wins at the end of the game is the one who has the most pieces on the board.
tutorialstring=Tutorial
startgame=Start game!
goback=Go back
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabic)
chinese=\u4e2d\u6587 (Chinese)
dutch=Nederlands (Dutch)
english=English
french=Fran\u00e7ais (French)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgian)
german=Deutsch (German)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
italian=Italiano (Italian)
japanese=\u65e5\u672c\u8a9e (Japanese)
korean=\ud55c\uad6d\uc5b4 (Korean)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russian)
spanish=Espa\u00f1ol (Spanish)

View File

@@ -1,17 +1,101 @@
# Window title
windowTitle=Selector de juegos ISY
accept=Aceptar
ai=Inteligencia Artificial
app-title=Selector de Juegos ISY
are-you-sure=\u00bfEst\u00e1s seguro?
back=Atr\u00e1s
cancel=Cancelar
challenge=Desaf\u00edo
computer-difficulty=Dificultad del ordenador
computer-think-time=Tiempo de pensamiento del ordenador
computer=Ordenador
connect=Conectar
connect4=Connect 4
# Main Menu buttons
mainMenuSelectTicTacToe=Tres en raya
mainMenuSelectReversi=Reversi
mainMenuSelectSudoku=Sudoku
mainMenuSelectBattleship=Batalla naval
mainMenuSelectOther=Otros
mainMenuSelectCredits=Cr\u00E9ditos
mainMenuSelectOptions=Opciones
mainMenuSelectQuit=Salir
credits=Cr\u00e9ditos
dark=Oscuro
deny=Denegar
developers=Desarrolladores
disconnect=Desconectar
effects-volume=Volumen de efectos
enter-the-server-ip=Introduce la IP del servidor
enter-the-server-port=Introduce el puerto del servidor
enter-your-name=Introduce tu nombre
error=Error
exit=Salir
forfeit=Rendirse
fullscreen=Pantalla completa
game-over=Fin del juego
general=General
high-contrast=Alto contraste
invalid-username=nombre de usuario inv\u00e1lido
ip-address=Direcci\u00f3n IP
is-not-a-valid-ip-address=no es una direcci\u00f3n IP v\u00e1lida
is-not-a-valid-port=no es un puerto v\u00e1lido
language=Idioma
large=Grande
layout-size=Tama\u00f1o de dise\u00f1o
light=Claro
local=Local
localization=Localizaci\u00f3n
master-volume=Volumen maestro
medium=Mediano
merge-commander=Merge Commander
moral-support=Apoyo moral
music-volume=Volumen de m\u00fasica
name=Nombre
never=No, no quiero ver ning\u00fan tutorial nunca.
no=No
ok=OK
online=En l\u00ednea
opengl=OpenGL
options=Opciones
play=Jugar
player-name=Nombre del jugador
player=Jugador
please-enter-your-name=Por favor, introduce tu nombre
port=Puerto
product-owner=Propietario del producto
quit=Salir
reversi=Reversi
scrum-master=Scrum Master
send=Enviar
server-information=Informaci\u00f3n del servidor
small=Peque\u00f1o
style=Estilo
the-game-ended-in-a-draw=El juego termin\u00f3 en empate
theme=Tema
tic-tac-toe=Tres en raya
tictactoe1 =\u00a1Bienvenido al juego del Tres en Raya! Puedes hacer tu jugada haciendo clic en cualquiera de los 9 cuadros del tablero. Ejemplo arriba:
tictactoe2 =Un jugador gana al conseguir 3 fichas en l\u00ednea, ya sea horizontal, vertical o diagonalmente. En el ejemplo de arriba, el jugador gana con una fila diagonal de tres fichas.
to-a-game-of=a un juego de
tutorial=\u00bfQuieres ver un tutorial para este juego?
volume=Volumen
windowed=En ventana
yes=S\u00ed
you-lost-against=Perdiste contra
you-were-challenged-by=Fuiste desafiado por
you-win=Ganaste
>=>
<=<
connect4.1=\u00a1Bienvenido al juego de Connect 4! Puedes hacer un movimiento haciendo clic en una de las columnas. El movimiento se colocar<61> en la fila m<>s baja de esa columna que no est<73> llena.
connect4.2=\u00a1Puedes ganar consiguiendo 4 fichas de tu color horizontal, diagonal o verticalmente! Mira el ejemplo de arriba.
reversi1=\u00a1Bienvenido al juego de Reversi! Puedes hacer un movimiento haciendo clic en uno de los puntos ligeramente transparentes.
reversi2=Al hacer clic en un punto, se voltear<61>n todas las fichas entre donde colocas el punto y el siguiente punto que encuentre. Mira el ejemplo de arriba, donde amarillo son las fichas a voltear.
reversi3=Tu turno puede ser saltado si no hay un movimiento legal. Esto permitir<69> que tu oponente juegue nuevamente hasta que tengas una oportunidad legal.
reversi4=El jugador que gane al final del juego es quien tenga m<>s fichas en el tablero.
tutorialstring=Tutorial
# Quit Menu text and buttons
quitMenuTextSure=\u00BFEst\u00E1s seguro?
quitMenuButtonYes=S\u00ED
quitMenuButtonNo=No
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Ar\u00e1bigo)
chinese=\u4e2d\u6587 (Chino)
dutch=Nederlands (Neerland\u00e9s)
english=English (Ingl\u00e9s)
french=Fran\u00e7ais (Franc\u00e9s)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgiano)
german=Deutsch (Alem\u00e1n)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
italian=Italiano (Italiano)
japanese=\u65e5\u672c\u8a9e (Japon\u00e9s)
korean=\ud55c\uad6d\uc5b4 (Coreano)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Ruso)
spanish=Espa\u00f1ol

View File

@@ -1,17 +1,100 @@
# Window title
windowTitle=S\u00E9lecteur de jeux ISY
accept=Accepter
ai=Intelligence Artificielle
app-title=S\u00c9LECTEUR DE JEUX ISY
are-you-sure=\u00cates-vous s\u00fbr ?
back=Retour
cancel=Annuler
challenge=D\u00e9fi
computer-difficulty=Difficult\u00e9 de l'ordinateur
computer-think-time=Temps de r\u00e9flexion de l'ordinateur
computer=Ordinateur
connect=Connexion
connect4=Connect 4
# Main Menu buttons
mainMenuSelectTicTacToe=Morpion
mainMenuSelectReversi=Reversi
mainMenuSelectSudoku=Sudoku
mainMenuSelectBattleship=Bataille navale
mainMenuSelectOther=Autres
mainMenuSelectCredits=Cr\u00E9dits
mainMenuSelectOptions=Options
mainMenuSelectQuit=Quitter
credits=Cr\u00e9dits
dark=Sombre
deny=Refuser
developers=D\u00e9veloppeurs
disconnect=D\u00e9connexion
effects-volume=Volume des effets
enter-the-server-ip=Entrez l'adresse IP du serveur
enter-the-server-port=Entrez le port du serveur
enter-your-name=Entrez votre nom
error=Erreur
exit=Quitter
forfeit=Abandonner
fullscreen=Plein \u00e9cran
game-over=Fin de la partie
general=G\u00e9n\u00e9ral
high-contrast=Haut contraste
invalid-username=nom d'utilisateur invalide
ip-address=Adresse IP
is-not-a-valid-ip-address=n'est pas une adresse IP valide
is-not-a-valid-port=n'est pas un port valide
language=Langue
large=Grand
layout-size=Format de l'affichage
light=Clair
local=Local
localization=Traduction
master-volume=Volume principal
medium=Moyen
merge-commander=Merge Commander
moral-support=Soutien moral
music-volume=Volume de la musique
name=Nom
never=Non, je ne veux jamais voir de tutoriels.
no=Non
ok=OK
online=En ligne
opengl=OpenGL
options=Options
play=Jouer
player-name=Nom du joueur
player=Joueur
please-enter-your-name=Veuillez entrer votre nom
port=Port
product-owner=Responsable produit
quit=Quitter
reversi=Reversi
scrum-master=Scrum Master
send=Envoyer
server-information=Informations du serveur
small=Petit
style=Style
the-game-ended-in-a-draw=La partie s'est termin\u00e9e par un match nul
theme=Th\u00e8me
tic-tac-toe=Morpion
tictactoe1 =Bienvenue dans le jeu du Tic Tac Toe ! Vous pouvez jouer en cliquant sur l\u2019une des 9 cases du plateau. Exemple ci-dessus :
tictactoe2 =Un joueur gagne en alignant 3 pi\u00e8ces \u2013 horizontalement, verticalement ou en diagonale. Dans l\u2019exemple ci-dessus, le joueur gagne avec une diagonale de trois pi\u00e8ces.
to-a-game-of=\u00e0 une partie de
tutorial=Veux-tu voir un tutoriel pour ce jeu\u00a0?
volume=Volume
windowed=Fen\u00eatrr\u00e9
yes=Oui
you-lost-against=Vous avez perdu contre
you-were-challenged-by=Vous avez \u00e9t\u00e9 d\u00e9fi\u00e9 par
you-win=Vous avez gagn\u00e9
>=>
<=<
connect4.1=Bienvenue dans le jeu Connect 4 ! Vous pouvez effectuer un mouvement en cliquant sur l'une des colonnes. Le mouvement sera plac<61> dans la ligne la plus basse de cette colonne qui n'est pas encore remplie.
connect4.2=Vous pouvez gagner en alignant 4 pions de votre couleur horizontalement, diagonalement ou verticalement ! Voir l'exemple ci-dessus.
reversi1=Bienvenue dans le jeu Reversi ! Vous pouvez jouer en cliquant sur l'un des points l<>g<EFBFBD>rement transparents.
reversi2=Cliquer sur un point retournera tous les pions entre le point plac<61> et le prochain point trouv<75>. Voir l'exemple ci-dessus, o<> le jaune indique les pions <20> retourner.
reversi3=Votre tour peut <20>tre saut<75> s'il n'y a pas de coup l<>gal. Cela permettra <20> votre adversaire de jouer jusqu'<27> ce que vous ayez un coup l<>gal.
reversi4=Le joueur qui a le plus de pions <20> la fin du jeu gagne.
tutorialstring=Tutoriel
# Quit Menu text and buttons
quitMenuTextSure=\u00CAtes-vous s\u00FBr?
quitMenuButtonYes=Oui
quitMenuButtonNo=Non
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabe)
chinese=\u4e2d\u6587 (Chinois)
dutch=Nederlands (N\u00e9erlandais)
english=English (Anglais)
french=Fran\u00e7ais
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (G\u00e9orgien)
german=Deutsch (Allemand)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
italian=Italiano (Italien)
japanese=\u65e5\u672c\u8a9e (Japonais)
korean=\ud55c\uad6d\uc5b4 (Cor\u00e9en)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russe)
spanish=Espa\u00f1ol (Espagnol)

View File

@@ -0,0 +1,100 @@
accept=\u0938\u094d\u0935\u0940\u0915\u093e\u0930
ai=\u0915\u0943\u0924\u094d\u0930\u093f\u092e \u092c\u0941\u0926\u094d\u0927\u093f
app-title=ISY \u0917\u0947\u092e \u091a\u092f\u0928\u0915\u093e\u0930\u0940
are-you-sure=\u0915\u094d\u092f\u093e \u0906\u092a \u0928\u093f\u0936\u094d\u091a\u093f\u0924 \u0939\u0948\u0902?
back=\u092a\u0940\u091b\u0947
cancel=\u0930\u0926\u094d\u0926 \u0915\u0930\u0947\u0902
challenge=\u091a\u0941\u0928\u094c\u0924\u0940
computer-difficulty=\u0915\u0902\u092a\u094d\u092f\u0942\u091f\u0930 \u0915\u0940 \u0915\u0920\u0928\u093e\u0908
computer-think-time=\u0915\u0902\u092a\u094d\u092f\u0942\u091f\u0930 \u091a\u093f\u0902\u0924\u0928 \u0938\u092e\u092f
computer=\u0915\u0902\u092a\u094d\u092f\u0942\u091f\u0930
connect=\u091c\u094b\u095c\u0947\u0902
connect4=Connect 4
credits=\u0915\u094d\u0930\u0947\u0921\u093f\u091f\u094d\u0938
dark=\u0917\u0939\u0930\u093e
deny=\u0907\u0902\u0915\u093e\u0930
developers=\u0935\u093f\u0915\u093e\u0938\u093f\u0924\u093e
disconnect=\u091c\u094b\u095c \u091f\u0942\u091f\u0928\u093e
effects-volume=\u090f\u092b\u0947\u0915\u094d\u091f \u0935\u0949\u0932\u094d\u092f\u0942\u092e
enter-the-server-ip=\u0938\u0930\u094d\u0935\u0930 IP \u0926\u093e\u0916\u093f\u090f
enter-the-server-port=\u0938\u0930\u094d\u0935\u0930 \u092a\u094b\u0930\u094d\u091f \u0926\u093e\u0916\u093f\u090f
enter-your-name=\u0905\u092a\u0928\u093e \u0928\u093e\u092e \u0926\u093e\u0916\u093f\u090f
error=\u0924\u094d\u0930\u0941\u091f\u093f
exit=\u092c\u093e\u0939\u0930 \u0928\u093f\u0915\u093e\u0932\u0940\u090f\u0902
forfeit=\u0939\u093e\u0930 \u092e\u093e\u0928\u0928\u093e
fullscreen=\u092a\u0942\u0930\u0940 \u0938\u094d\u0915\u094d\u0930\u0940\u0928
game-over=\u0916\u0947\u0932 \u0916\u0924\u094d\u092e
general=\u0938\u093e\u092e\u093e\u0928\u094d\u092f
high-contrast=\u0909\u091A\u094D\u091A\u093F\u0924 \u0915\u0949\u0902\u091F\u094D\u0930\u093E\u0938\u094D\u091F
invalid-username=\u0905\u092e\u093e\u0928\u094d\u092f \u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e \u0928\u093e\u092e
ip-address=IP \u092a\u0924\u093e
is-not-a-valid-ip-address=\u092f\u0939 \u090f\u0915 \u0905\u092e\u093e\u0928\u094d\u092f IP \u092a\u0924\u093e \u0928\u0939\u0940\u0902 \u0939\u0948
is-not-a-valid-port=\u092f\u0939 \u090f\u0915 \u0905\u092e\u093e\u0928\u094d\u092f \u092a\u094b\u0930\u094d\u091f \u0928\u0939\u0940\u0902 \u0939\u0948
language=\u092d\u093e\u0937\u093e
large=\u092c\u095c\u093e
layout-size=\u0932\u0947\u090f\u0913\u091f \u0915\u093e \u0906\u0915\u093e\u0930
light=\u0915\u0947\u091c\u093c\u093e
local=\u0938\u094d\u0925\u093e\u0928\u0940\u092f
localization=\u0938\u094d\u0925\u093e\u0928\u0940\u092f\u0915\u0930\u0923
master-volume=\u092e\u093e\u0938\u094d\u091f\u0930 \u0935\u0949\u0932\u094d\u092f\u0942\u092e
medium=\u092e\u0927\u094d\u092f\u092e
merge-commander=\u092e\u0930\u094d\u091c \u0915\u092e\u093e\u0902\u0921\u0930
moral-support=\u0928\u0948\u0924\u093f\u0915 \u0938\u0939\u093e\u0930\u093e
music-volume=\u0938\u0902\u0917\u0940\u0924 \u0935\u0949\u0932\u094d\u092f\u0942\u092e
name=\u0928\u093e\u092e
never=\u0928\u0939\u0940\u0902, \u092e\u0948\u0902 \u0915\u092c\u094d\u0939\u0940 \u092d\u0940 \u0915\u094b\u0908 \u091f\u094d\u092f\u0942\u091f\u094b\u0930\u093f\u092f\u0932 \u0928\u0939\u0940\u0902 \u0926\u0947\u0916\u0928\u093e \u091a\u093e\u0939\u0924\u093e/\u091a\u093e\u0939\u0924\u0940\u0964
no=\u0928\u0939\u0940\u0902
ok=\u0920\u0940\u0915 \u0939\u0948
online=\u0911\u0928\u0932\u093e\u0907\u0928
opengl=OpenGL
options=\u0935\u093f\u0915\u0932\u094d\u092a
play=\u0916\u0947\u0932\u0947\u0902
player-name=\u0916\u093f\u0932\u093e\u095e\u0940 \u0915\u093e \u0928\u093e\u092e
player=\u0916\u093f\u0932\u093e\u095e\u0940
please-enter-your-name=\u0915\u0943\u092a\u092f\u093e \u0905\u092a\u0928\u093e \u0928\u093e\u092e \u0926\u093e\u0916\u093f\u090f
port=\u092a\u094b\u0930\u094d\u091f
product-owner=\u092a\u094d\u0930\u094b\u0921\u0915\u094d\u091f \u0915\u093e \u092e\u093e\u0932\u093f\u0915
quit=\u091b\u094b\u0921\u0947\u0902
reversi=\u0930\u093f\u0935\u0930\u094d\u0938\u0940
scrum-master=\u0938\u094d\u0915\u094d\u0930\u092e \u092e\u093e\u0938\u094d\u091f\u0930
send=\u092d\u0947\u091c\u0947\u0902
server-information=\u0938\u0930\u094d\u0935\u0930 \u091c\u093e\u0928\u0915\u093e\u0930\u0940
small=\u091b\u094b\u091f\u093e
style=\u0936\u0948\u0932\u0940
the-game-ended-in-a-draw=\u0916\u0947\u0932 \u091f\u0940\u0915 \u0939\u094b \u0917\u092f\u093e
theme=\u0925\u0940\u092e
tic-tac-toe=\u091f\u093f\u0915-\u091f\u0948\u0915-\u091f\u094b
tictactoe1 =\u091f\u093f\u0915-\u091f\u0948\u0915-\u091f\u094b \u0915\u0947 \u0916\u0947\u0932 \u092e\u0947\u0902 \u0906\u092a\u0915\u093e \u0938\u094d\u0935\u093e\u0917\u0924 \u0939\u0948! \u0906\u092a \u092c\u094b\u0930\u094d\u0921 \u092a\u0930 \u0915\u093f\u0938\u0940 \u092d\u0940 9 \u0916\u093e\u0928\u0947 \u092a\u0930 \u0915\u094d\u0932\u093f\u0915 \u0915\u0930\u0915\u0947 \u0905\u092a\u0928\u0940 \u091a\u093e\u0932 \u091a\u0932 \u0938\u0915\u0924\u0947 \u0939\u0948\u0902\u0964 \u090a\u092a\u0930 \u0926\u093f\u092f\u093e \u0917\u092f\u093e \u0909\u0926\u093e\u0939\u0930\u0923 \u0926\u0947\u0916\u0947\u0902:
tictactoe2 =\u0915\u094b\u0908 \u0916\u093f\u0932\u093e\u0921\u093c\u0940 \u0924\u092c \u091c\u0940\u0924\u0924\u093e \u0939\u0948 \u091c\u092c \u0935\u0939 \u092a\u0948 \u092a\u0902\u0915\u094d\u0924\u093f \u092e\u0947\u0902 \u0924\u0940\u0928 \u0928\u093f\u0936\u093e\u0928 \u090f\u0915 \u092a\u0902\u0915\u094d\u0924\u093f \u092e\u0947\u0902 \u0932\u0917\u093e \u0926\u0947\u0924\u093e \u0939\u0948 ? \u0915\u094d\u0937\u0948\u0924\u093f\u091c, \u090a\u0930\u094d\u0927\u094d\u0935\u093e\u0927\u0930 \u092f\u093e \u0924\u093f\u0930\u091b\u0947\u0964 \u090a\u092a\u0930 \u0909\u0926\u093e\u0939\u0930\u0923 \u092e\u0947\u0902, \u0916\u093f\u0932\u093e\u0921\u093c\u0940 \u0924\u093f\u0930\u091b\u0940 \u092a\u0902\u0915\u094d\u0924\u093f \u092e\u0947\u0902 \u0924\u093f\u0930\u091b\u0940 \u092a\u0902\u0915\u094d\u0924\u093f \u0938\u0947 \u091c\u0940\u0924\u0924\u093e \u0939\u0948\u0964
to-a-game-of=\u0916\u0947\u0932 \u0915\u0940 \u090f\u0915 \u0916\u0947\u0932 \u0915\u0940 \u0913\u0930
tutorial=\u0915\u094d\u092f\u093e \u0906\u092a \u0907\u0938 \u0917\u0947\u092e \u0915\u0947 \u0932\u093f\u090f \u0915\u094b\u0908 \u091f\u094d\u092f\u0942\u091f\u094b\u0930\u093f\u092f\u0932 \u0926\u0947\u0916\u0928\u093e \u091a\u093e\u0939\u0924\u0947 \u0939\u0948\u0902?
volume=\u0935\u0949\u0932\u094d\u092f\u0942\u092e
windowed=\u0935\u093f\u0902\u0921\u094b \u092e\u094b\u0921
yes=\u0939\u093e\u0901
you-lost-against=\u0906\u092a \u0939\u093e\u0930 \u0917\u090f
you-were-challenged-by=\u0906\u092a\u0915\u094b \u091a\u0941\u0928\u094c\u0924\u0940 \u0926\u0940 \u0917\u0908
you-win=\u0906\u092a \u091c\u0940\u0924 \u0917\u090f
>=>
<=<
connect4.1=\u0915\u0928\u094d\u0928\u0947 \u0915\u0940 \u091c\u0948 \u0915\u0947 \u091c\u094c\u0915 \u0915\u0928\u0947\u0915\u094d\u091f 4 \u092e\u0947\u0902! \u0906\u092a \u0915\u0940 \u091a\u0948\u0928 \u092a\u0932\u0938 \u092a\u0928\u094d\u0928 \u0928\u093e\u092e\u094d\u092c\u0921\u093e\u0928\u0947 \u0915\u0940 \u092f\u094b\u0917\u0924\u0940 \u092e\u0947\u0902 \u0915\u0940 \u0928\u093f\u091a\u094d\u091a\u0942\u0928 \u0915\u0940 \u0924\u0939 \u091a\u093f\u0928 \u092a\u0924\u093f \u0928\u0939\u0940\u0902 \u0926\u0947 \u092c\u0924\u0940.
connect4.2=\u092a\u093e\u0902\u091a \u092e\u0946\u092c\u0921 \u0915\u0940 \u092a\u0930\u092a\u0930\u092f\u094d\u0928 \u092d\u093e\u0935\u0940 \u0938\u0947 4 \u092a\u093f\u0938 \u0924\u093e\u0924\u093e \u0915\u0940 \u0930\u094f\u0936\u0942 \u0938\u0940\u0926\u094d\u0927 \u092e\u0947\u0902 \u092a\u0940\u0928\u094d\u0928\u094b\u0902 \u0915\u0940 \u092e\u093e\u0928\u094d\u0926\u0930 \u0939\u0940.
reversi1=\u0915\u0928\u094d\u0928\u0947 \u0915\u0940 \u091c\u0948 \u0910 \u0930\u0947\u0935\u0930\u094d\u0938\u0940 \u092e\u0947\u0902 \u0926\u0948\u091a \u092c\u0922\u093e\u0928 \u0915\u0940 \u092a\u0924\u094d\u0928 \u092a\u0930 \u092a\u094d\u0932\u0947 \u0916\u0942\u0928\u0947 \u0915\u0940 \u092a\u094d\u0930\u092f\u0948\u0915\u0944 \u0915\u0930\u0948\u0902.
reversi2=\u0915\u093f\u0938 \u092a\u0930 \u092a\u093f\u0938 \u092a\u0948\u0918 \u0915\u0940 \u091a\u0928 \u092e\u0947\u0902 \u0938\u092e\u093e\u0930\u094e \u092a\u093f\u0938 \u092a\u0940\u0918 \u092e\u0947\u0902 \u092a\u0930\u093f\u0923\u0924 \u0915\u093e \u092a\u0930\u093f\u0928\u0942\u0924\u0940 \u0915\u0940 \u092a\u094d\u0930\u0924\u093f \u092a\u0941\u0928\u0940 \u092a\u0930\u093f\u0928\u094d\u0924 \u0915\u0940 \u092a\u0940\u0938 \u092a\u0930\u094d\u092f\u0928\u0947 \u091c\u093e\u0902\u0918\u0942.
reversi3=\u092f\u0939 \u092a\u0930\u094d\u092f \u0938\u0947 \u0938\u0947\u091a \u0915\u0940 \u091c\u093e\u0902\u091c \u0928\u0939\u0940\u0902 \u0939\u0948 \u0914\u0938\u0924\u0947 \u0915\u0948 \u092a\u0948\u0928 \u092a\u0930\u094d\u092f \u0939\u0948 \u0914\u092a\u0915\u0940 \u0915\u0940 \u092a\u0932\u0947 \u092d\u0942\u0924 \u0915\u0940 \u0906\u0927\u093e \u092a\u0948\u0928 \u091c\u093e\u0902\u091c \u0915\u0930 \u0938\u0915\u0924\u0947 \u0939\u0948\u0902.
reversi4=\u0916\u0941\u092f \u0915\u093f \u0915\u0940 \u0928\u093f\u092e\u0940 \u092e\u0947\u0902 \u091a\u093e\u0932 \u0938\u092c\u0938\u0947 \u091a\u0942\u0928\u094d\u0928\u0947 \u0939\u0948, \u0935\u0949 \u0915\u0947 \u092e\u093e\u0924\u094d\u0930 \u091c\u0940\u0924\u0947 \u0939\u0948.
tutorialstring=\u0924\u0942\u091f\u0949\u0930\u093f\u092f\u0932
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0905\u0930\u092c\u0940)
chinese=\u4e2d\u6587 (\u091a\u0940\u0928\u0940)
dutch=Nederlands (\u0921\u091a)
english=English (\u0905\u0902\u0917\u094d\u0930\u0947\u091c\u0940)
french=Fran\u00e7ais (\u092b\u094d\u0930\u0947\u0902\u091a)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u091c\u094d\u091c\u094b\u0930\u094d\u091c\u093f\u092f\u0928)
german=Deutsch (\u091c\u0930\u094d\u092e\u0928)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940
italian=Italiano (\u0907\u091f\u093e\u0932\u093f\u092f\u0928)
japanese=\u65e5\u672c\u8a9e (\u091c\u093e\u092a\u093e\u0928\u0940)
korean=\ud55c\uad6d\uc5b4 (\u0915\u094b\u0930\u093f\u092f\u0928)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\u0930\u0942\u0938\u0940)
spanish=Espa\u00f1ol (\u0938\u094d\u092a\u0947\u0928\u093f\u0936)

View File

@@ -1,17 +1,99 @@
# Window title
windowTitle=Selettore giochi ISY
accept=Accetta
ai=Intelligenza Artificiale
app-title=Selettore di Giochi ISY
are-you-sure=Sei sicuro?
back=Indietro
cancel=Annulla
challenge=Sfida
computer-difficulty=Difficolt\u00e0 del computer
computer-think-time=Tempo di riflessione del computer
computer=Computer
connect=Connetti
connect4=Connect 4
credits=Crediti
dark=Scuro
deny=Nega
developers=Sviluppatori
disconnect=Disconnetti
effects-volume=Volume degli effetti
enter-the-server-ip=Inserisci l'IP del server
enter-the-server-port=Inserisci la porta del server
enter-your-name=Inserisci il tuo nome
error=Errore
exit=Esci
forfeit=Abbandona
fullscreen=Schermo intero
game-over=Fine del gioco
general=Generale
high-contrast=Alto contrasto
invalid-username=nome utente non valido
ip-address=Indirizzo IP
is-not-a-valid-ip-address=non \u00e8 un indirizzo IP valido
is-not-a-valid-port=non \u00e8 una porta valida
language=Lingua
large=Grande
layout-size=Dimensione layout
light=Chiaro
local=Locale
localization=Localizzazione
master-volume=Volume principale
medium=Medio
merge-commander=Merge Commander
moral-support=Supporto morale
music-volume=Volume della musica
name=Nome
never=No, non voglio mai vedere alcun tutorial.
no=No
ok=OK
online=Online
opengl=OpenGL
options=Opzioni
play=Gioca
player-name=Nome del giocatore
player=Giocatore
please-enter-your-name=Per favore inserisci il tuo nome
port=Porta
product-owner=Proprietario del prodotto
quit=Esci
reversi=Reversi
scrum-master=Scrum Master
send=Invia
server-information=Informazioni sul server
small=Piccolo
style=Stile
the-game-ended-in-a-draw=La partita \u00e8 terminata in parit\u00e0
theme=Tema
tic-tac-toe=Tris
tictactoe1 =Benvenuto nel gioco del Tris! Puoi fare la tua mossa cliccando su uno dei 9 quadrati della griglia. Esempio sopra:
tictactoe2 =Un giocatore vince mettendo 3 simboli in fila ? orizzontalmente, verticalmente o diagonalmente. Nell?esempio sopra, il giocatore vince con una fila diagonale di tre simboli.
to-a-game-of=a una partita di
tutorial=Vuoi vedere un tutorial per questo gioco?
volume=Volume
windowed=Finestra
yes=S\u00ec
you-lost-against=Hai perso contro
you-were-challenged-by=Sei stato sfidato da
you-win=Hai vinto
>=>
<=<
connect4.1=Benvenuto nel gioco Connect 4! Puoi fare una mossa cliccando su una delle colonne. La mossa sar<61> posizionata nella riga pi<70> bassa di quella colonna che non <20> ancora piena.
connect4.2=Puoi vincere ottenendo 4 pedine del tuo colore in orizzontale, diagonale o verticale! Guarda l'esempio sopra.
reversi1=Benvenuto nel gioco Reversi! Puoi fare una mossa cliccando su uno dei punti leggermente trasparenti.
reversi2=Cliccando su un punto, tutti i pezzi tra dove metti il punto e il prossimo punto trovato verranno girati. Guarda l'esempio sopra, dove il giallo indica i pezzi da girare.
reversi3=Il tuo turno pu<70> essere saltato se non ci sono mosse legali. Questo permetter<65> al tuo avversario di giocare fino a quando non avrai un'opportunit<69> legale.
reversi4=Il giocatore che alla fine del gioco ha pi<70> pezzi sulla scacchiera vince.
tutorialstring=Tutorial
# Main Menu buttons
mainMenuSelectTicTacToe=Tris
mainMenuSelectReversi=Reversi
mainMenuSelectSudoku=Sudoku
mainMenuSelectBattleship=Battaglia navale
mainMenuSelectOther=Altro
mainMenuSelectCredits=Crediti
mainMenuSelectOptions=Opzioni
mainMenuSelectQuit=Esci
# Quit Menu text and buttons
quitMenuTextSure=Sei sicuro?
quitMenuButtonYes=S\u00EC
quitMenuButtonNo=No
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabo)
chinese=\u4e2d\u6587 (Cinese)
dutch=Nederlands (Olandese)
english=English (Inglese)
french=Fran\u00e7ais (Francese)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgiano)
german=Deutsch (Tedesco)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
italian=Italiano
japanese=\u65e5\u672c\u8a9e (Giapponese)
korean=\ud55c\uad6d\uc5b4 (Coreano)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russo)
spanish=Espa\u00f1ol (Spagnolo)

View File

@@ -0,0 +1,99 @@
accept=\u627f\u8a8d
ai=\u4eba\u5de5\u77e9\u7565
app-title=ISY\u30b2\u30fc\u30e0\u30bb\u30ec\u30af\u30bf\u30fc
are-you-sure=\u672c\u5f53\u306b\u3088\u308d\u3057\u3044\u3067\u3059\u304b\uff1f
back=\u623b\u308b
cancel=\u30ad\u30e3\u30f3\u30bb\u30eb
challenge=\u6311\u6226
computer-difficulty=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u306e\u96e3\u6613\u5ea6
computer-think-time=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u306e\u601d\u8003\u6642\u9593
computer=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf
connect=\u63a5\u7d9a
connect4=Connect 4
credits=\u30af\u30ec\u30b8\u30c3\u30c8
dark=\u30c0\u30fc\u30af
deny=\u62d2\u5426
developers=\u958b\u767a\u8005
disconnect=\u5207\u65ad
effects-volume=\u52b9\u679c\u97f3\u91cf
enter-the-server-ip=\u30b5\u30fc\u30d0\u30fcIP\u3092\u5165\u529b
enter-the-server-port=\u30b5\u30fc\u30d0\u30fc\u30dd\u30fc\u30c8\u3092\u5165\u529b
enter-your-name=\u540d\u524d\u3092\u5165\u529b
error=\u30a8\u30e9\u30fc
exit=\u7d42\u4e86
forfeit=\u8f9e\u9000
fullscreen=\u30d5\u30eb\u30b9\u30af\u30ea\u30fc\u30f3
game-over=\u30b2\u30fc\u30e0\u30aa\u30fc\u30d0\u30fc
general=\u4e00\u822c
high-contrast=\u9AD8\u30B3\u30F3\u30C8\u30E9\u30B9
invalid-username=\u7121\u52b9\u306a\u30e6\u30fc\u30b6\u30fc\u540d
ip-address=IP\u30a2\u30c9\u30ec\u30b9
is-not-a-valid-ip-address=\u6709\u52b9\u306aIP\u30a2\u30c9\u30ec\u30b9\u3067\u306f\u3042\u308a\u307e\u305b\u3093
is-not-a-valid-port=\u6709\u52b9\u306a\u30dd\u30fc\u30c8\u756a\u53f7\u3067\u306f\u3042\u308a\u307e\u305b\u3093
language=\u8a00\u8a9e
large=\u5927
layout-size=\u30ec\u30a4\u30a2\u30a6\u30c8\u30b5\u30a4\u30ba
light=\u30e9\u30a4\u30c8
local=\u30ed\u30fc\u30ab\u30eb
localization=\u30ed\u30fc\u30ab\u30e9\u30a4\u30bc\u30fc\u30b7\u30e7\u30f3
master-volume=\u30de\u30b9\u30bf\u30fc\u30dc\u30ea\u30e5\u30fc\u30e0
medium=\u4e2d
merge-commander=\u30de\u30fc\u30b8\u30b3\u30de\u30f3\u30c0\u30fc
moral-support=\u30e1\u30f3\u30bf\u30eb\u30b5\u30dd\u30fc\u30c8
music-volume=\u97f3\u697d\u97f3\u91cf
name=\u540d\u524d
never=\u3044\u3044\u3048\u3001\u30c1\u30e5\u30fc\u30c8\u30ea\u30a2\u30eb\u306f\u4e8c\u5ea6\u3068\u898b\u305f\u304f\u3042\u308a\u307e\u305b\u3093\u3002
no=\u3044\u3044\u3048
ok=OK
online=\u30aa\u30f3\u30e9\u30a4\u30f3
opengl=OpenGL
options=\u30aa\u30d7\u30b7\u30e7\u30f3
play=\u30d7\u30ec\u30a4
player-name=\u30d7\u30ec\u30a4\u30e4\u30fc\u540d
player=\u30d7\u30ec\u30a4\u30e4\u30fc
please-enter-your-name=\u540d\u524d\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044
port=\u30dd\u30fc\u30c8
product-owner=\u30d7\u30ed\u30c0\u30af\u30c8\u30aa\u30fc\u30ca\u30fc
quit=\u7d42\u4e86
reversi=\u30ea\u30d0\u30fc\u30b7
scrum-master=\u30b9\u30af\u30e9\u30e0\u30de\u30b9\u30bf\u30fc
send=\u9001\u4fe1
server-information=\u30b5\u30fc\u30d0\u60c5\u5831
small=\u5c0f
style=\u30b9\u30bf\u30a4\u30eb
the-game-ended-in-a-draw=\u30b2\u30fc\u30e0\u306f\u5f15\u304d\u5206\u3051\u306b\u7d42\u308f\u308a\u307e\u3057\u305f
theme=\u30c6\u30fc\u30de
tic-tac-toe=\u4e09\u76ee\u4e26\u3079
tictactoe1 =\u4e09\u76ee\u4e26\u3079\u306e\u30b2\u30fc\u30e0\u3078\u3088\u3046\u3053\u305d\uff01\u30dc\u30fc\u30c9\u4e0a\u306e9\u3064\u306e\u30de\u30b9\u306e\u3044\u305a\u308c\u304b\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u624b\u3092\u6253\u3061\u307e\u3057\u3087\u3046\u3002\u4e0a\u306e\u4f8b\u3092\u53c2\u7167\uff1a
tictactoe2 =\u30d7\u30ec\u30a4\u30e4\u30fc\u306f\u3001\u6a2a\u30fb\u7e26\u30fb\u65b9\u5411\u306e\u3044\u305a\u308c\u304b\u3067\u30de\u30fc\u30af\u30923\u3064\u4e26\u3079\u308b\u3068\u52dd\u3061\u3067\u3059\u3002\u4e0a\u306e\u4f8b\u3067\u306f\u3001\u30d7\u30ec\u30a4\u30e4\u30fc\u304c\u659c\u3081\u306b3\u3064\u4e26\u3079\u3066\u52dd\u3063\u3066\u3044\u307e\u3059\u3002
to-a-game-of=\u30b2\u30fc\u30e0\u306b
tutorial=\u3053\u306e\u30b2\u30fc\u30e0\u306e\u30c1\u30e5\u30fc\u30c8\u30ea\u30a2\u30eb\u3092\u898b\u305f\u3044\u3067\u3059\u304b\uff1f
volume=\u97f3\u91cf
windowed=\u30a6\u30a3\u30f3\u30c9\u30a6\u8868\u793a
yes=\u306f\u3044
you-lost-against=\u3042\u306a\u305f\u306f ... \u306b\u6557\u308c\u307e\u3057\u305f
you-were-challenged-by=\u3042\u306a\u305f\u306f ... \u304b\u3089\u6311\u6226\u3055\u308c\u307e\u3057\u305f
you-win=\u52dd\u5229\u3067\u3059
>=>
<=<
connect4.1=\u30b3\u30cd\u30af\u30c84\u306e\u30b2\u30fc\u30e0\u3078\u3088\u3046\u3053\u305d! \u30ab\u30e9\u30e0\u306e\u4e0a\u306e\u30ab\u30e9\u30e0\u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u52d5\u304b\u3057\u3092\u884c\u3048\u307e\u3059\u3002\u52d5\u304b\u3057\u306f\u3001\u3060\u307e\u308a\u306f\u307e\u3067\u5869\u3067\u306a\u3044\u884c\u306b\u8a2d\u7f6e\u3055\u308c\u307e\u3059\u3002
connect4.2=\u6a2a\u7dda\u3001\u65b9\u5411\u306e\u307f\u3082\u306a\u3057\u3067\u30014\u3064\u306e\u8ca0\u3051\u3092\u7d50\u5408\u3055\u305b\u308b\u3068\u52dd\u3061\u307e\u3059! \u4e0a\u306e\u4f8b\u3092\u898b\u3066\u304f\u3060\u3055\u3044\u3002
reversi1=\u30ea\u30d0\u30fc\u30b7\u30fb\u30b2\u30fc\u30e0\u3078\u3088\u3046\u3053\u305d! \u30ab\u30e9\u30e0\u306e\u30b9\u30dd\u30c3\u30c8\u30c9\u30c3\u30c8\u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u52d5\u304b\u3057\u306e\u30d7\u30ec\u30a4\u304c\u3067\u304d\u307e\u3059\u3002
reversi2=\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u3001\u3064\u306a\u304c\u308a\u3092\u542b\u3081\u305f\u8ca0\u3051\u304c\u307e\u3067\u306e\u8ca0\u3051\u304c\u5909\u308f\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002
reversi3=\u6b21\u306e\u52d5\u304b\u3057\u304c\u306a\u3044\u5834\u5408\u3001\u8a8d\u5b9a\u3055\u308c\u305f\u52d5\u304b\u3057\u306e\u6642\u9593\u306f\u62d2\u7d76\u3055\u308c\u308b\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002
reversi4=\u672c\u6b21\u306b\u30dc\u30fc\u30c9\u4e0a\u3067\u6700\u591a\u306e\u8ca0\u3051\u3092\u6301\u3064\u30d7\u30ec\u30a4\u30e4\u30fc\u304c\u52dd\u3061\u307e\u3059\u3002
tutorialstring=\u30c1\u30e5\u30fc\u30c8\u30ea\u30a2\u30eb
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u30a2\u30e9\u30d3\u30a2\u8a9e)
chinese=\u4e2d\u6587 (\u4e2d\u6587)
dutch=Nederlands (\u30aa\u30e9\u30f3\u30c0\u8a9e)
english=English (\u82f1\u8a9e)
french=Fran\u00e7ais (\u30d5\u30e9\u30f3\u30b9\u8a9e)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u30b0\u30eb\u30b8\u30a2\u8a9e)
german=Deutsch (\u30c9\u30a4\u30c4\u8a9e)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\u30d2\u30f3\u30c7\u30a3\u8a9e)
italian=Italiano (\u30a4\u30bf\u30ea\u30a2\u8a9e)
japanese=\u65e5\u672c\u8a9e
korean=\ud55c\uad6d\uc5b4 (\u97d3\u56fd\u8a9e)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\u30ed\u30b7\u30a2\u8a9e)
spanish=Espa\u00f1ol (\u30b9\u30da\u30a4\u30f3\u8a9e)

View File

@@ -0,0 +1,99 @@
accept=\uC218\uB77D
ai=\uC778\uACF5 \uC9C0\uB2A5
app-title=ISY \uAC8C\uC784 \uC120\uD0DD\uAE30
are-you-sure=\uC815\uB9D0\uB85C \uD655\uC2E4\uD569\uB2C8\uAE4C?
back=\uB4A4\uB85C
cancel=\uCDE8\uC18C
challenge=\uCC38\uC5EC
computer-difficulty=\uCEF4\uD4E8\uD130 \uC5B4\uB9AC\uAE30
computer-think-time=\uCEF4\uD4E8\uD130 \uC0DD\uAC01 \uC2DC\uAC04
computer=\uCEF4\uD4E8\uD130
connect=\uC5F0\uACB0
connect4=Connect 4
credits=\uD06C\uB808\uB527
dark=\uC5B4\uB460
deny=\uAC70\uBD80
developers=\uAC1C\uBC1C\uC790
disconnect=\uC5F0\uACB0 \uC624\uD508
effects-volume=\uD6A8\uACFC\uC74C \uBCFC\uB968
enter-the-server-ip=\uC11C\uBC84 IP\uB97C \uC785\uB825\uD558\uC138\uC694
enter-the-server-port=\uC11C\uBC84 \uD3EC\uD2B8\uB97C \uC785\uB825\uD558\uC138\uC694
enter-your-name=\uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694
error=\uC624\uB958
exit=\uB098\uAC00\uAE30
forfeit=\uAE30\uAD6C
fullscreen=\uC804\uCCB4 \uD654\uBA74
game-over=\uAC8C\uC784 \uC885\uB8CC
general=\uC77C\uBC18
high-contrast=\uACE0\uB3C4 \uB2E8\uC5B4
invalid-username=\uBB34\uD6A8\uD55C \uC0AC\uC6A9\uC790 \uC774\uB984
ip-address=IP \uC8FC\uC18C
is-not-a-valid-ip-address=\uC62C\uBC14\uB978 IP \uC8FC\uC18C\uAC00 \uC544\uB2D9\uB2C8\uB2E4
is-not-a-valid-port=\uC62C\uBC14\uB978 \uD3EC\uD2B8\uAC00 \uC544\uB2D9\uB2C8\uB2E4
language=\uC5B8\uC5B4
large=\uD070
layout-size=\uB77C\uC774\uC6C3 \uD06C\uAE30
light=\uBCF4\uD1B5
local=\uB85C\uCEEC
localization=\uB85C\uCEEC\uB9AC\uC870
master-volume=\uBAA8\uB4E0 \uBCFC\uB968
medium=\uBCF4\uD1B5
merge-commander=\uBA54\uC9C0 \uCEE8\uBA38\uB2C8
moral-support=\uC815\uC2E0\uC801 \uC9C0\uC6D0
music-volume=\uC74C\uC545 \uBCFC\uB968
name=\uC774\uB984
no=\uC544\uB2C8\uC624
never=\uc544\ub2c8\uc694, \uc800\ub294 \ud29c\ud1a0\ub9ac\uc5bc\uc744 \ub2e4\uc2dc\ub294 \ubcf4\uace0 \uc2f6\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
ok=\uD655\uC778
online=\uC628\uB77C\uC778
opengl=OpenGL
options=\uC635\uC158
play=\uC7AC\uC0DD
player-name=\uD50C\uB808\uC774\uC5B4 \uC774\uB984
player=\uD50C\uB808\uC774\uC5B4
please-enter-your-name=\uC774\uB984\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694
port=\uD3EC\uD2B8
product-owner=\uD504\uB85C\uB354\uD2B8 \uC624\uB108
quit=\uC885\uB8CC
reversi=\uB9AC\uBC84\uC2DC
scrum-master=\uC2A4\uD06C\uB7FC \uB9C8\uC2A4\uD130
send=\uBCF4\uB0B4\uAE30
server-information=\uC11C\uBC84 \uC815\uBCF4
small=\uC791\uC740
style=\uC2A4\uD0C0\uC77C
the-game-ended-in-a-draw=\uAC8C\uC784\uC774 \uBB34\uC2B9\uBD80\uB85C \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4
theme=\uC8FC\uC81C
tic-tac-toe=\uD2F0\uD06C\uD0D1\uD1A0
tictactoe1 =\ud2f1\ud0dd\ud1a0 \uac8c\uc784\uc5d0 \uc624\uc2e0 \uac83\uc744 \ud658\uc601\ud569\ub2c8\ub2e4! \ubcf4\ub4dc\uc758 9\uac1c \uce78 \uc911 \ud558\ub098\ub97c \ud074\ub9ad\ud558\uc5ec \uc6c0\uc9c1\uc77c \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc704\uc758 \uc608\uc2dc\ub97c \ucc38\uace0\ud558\uc138\uc694:
tictactoe2 =\ud50c\ub808\uc774\uc5b4\ub294 \uac00\ub85c, \uc138\ub85c \ub610\ub294 \ub300\uac01\uc120\uc73c\ub85c \ub9d0 3\uac1c\ub97c \uc77c\ub82c\ub85c \ub193\uc73c\uba74 \uc2b9\ub9ac\ud569\ub2c8\ub2e4. \uc704\uc758 \uc608\uc5d0\uc11c \ud50c\ub808\uc774\uc5b4\ub294 \ub300\uac01\uc120\uc73c\ub85c \uc138 \uac1c\ub97c \uc5f0\uacb0\ud558\uc5ec \uc774\uacbc\uc2b5\ub2c8\ub2e4.
to-a-game-of=... \uAC8C\uC784\uC5D0
tutorial=\uc774 \uac8c\uc784\uc758 \ud29c\ud1a0\ub9ac\uc5bc\uc744 \ubcf4\uace0 \uc2f6\ub098\uc694?
volume=\uBCFC\uB968
windowed=\uCC3D \uBAA9\uB85D
yes=\uB124
you-lost-against=... \uC5D0\uAC8C \uC9C0\uC600\uC2B5\uB2C8\uB2E4
you-were-challenged-by=... \uB85C\uBD80\uD130 \uCC38\uC5EC \uC694\uCCAD\uC744 \uBC1B\uC558\uC2B5\uB2C8\uB2E4
you-win=\uC774\uACBC\uC2B5\uB2C8\uB2E4
>=>
<=<
connect4.1=Connect 4 \uacbd\uc6b0\uc5d0 \uc81c\uc2dc\ud569\ub2c8\ub2e4! \ud648\ub825\uc744 \ub2e4\ub978 \uc0c1\uc704\ub85c \ud074\ub9ad\ud558\uc2dc\uba70 \ub2e4\uc74c \uc815\uc758 \ud648\ub825\uc744 \ub610\ub294 \uc704\ub85c \uc0ac\uc6a9\ud558\uc2dc\uba70 \ud648\ub825\uc744 \uc124\uc815\ud569\ub2c8\ub2e4.
connect4.2=\uc0ac\uc6a9\uc790\uc758 \ud648\uc744 \uc54c\ub824 \ud574\uc8fc\uba70 \ud574\ub2f9 \ud648\uc758 4\uae38\uc744 \ud574\uc8fc\uba70 \ud655\uc9c0, \ub354\ub7ec \ubc29\uacfc \ub610\ub294 \uc0ac\uc6a9\uc790 \ud648\uc758 \uc5f4\ub9b0 \ucd5c\ub300 \ubc29\ud574\uc5d0 \uc5c6\uc74c\uc774\ub2e4!
reversi1=Reversi \uacbd\uc6b0\uc5d0 \uc81c\uc2dc\ud569\ub2c8\ub2e4! \ub2e4\ub978 \ud615\uc2dd\uc758 \ud648\uc744 \ud074\ub9ad\ud558\uc2dc\uba70 \ub2e4\uc74c \uc815\uc758 \ud648\uc744 \uc124\uc815\ud569\ub2c8\ub2e4.
reversi2=\ud074\ub9ad \ud558\uba70, \ub2e4\ub978 \ud648 \uc704\ub85c \ucd5c\uc2e0 \ubc1b\ub294 \ud648\uc5d0 \ub300\ud574 \ub2e4\uc774\ubc84\ub77c\uc758 \ud648\uc744 \ubcc0\uacbd\ud569\ub2c8\ub2e4.
reversi3=\uc0ac\uc6a9\uc790\uc758 \ud648\uc744 \ud074 \uc218 \uc5c6\uc2b5\uc2b5\ub2c8\ub2e4. \uc0ac\uc6a9\uc790 \ub2f5\uc5d0 \ub300\ud574 \uc811\ub2c8\ub2e4.
reversi4=\uacbd\uc6b0 \uc5d0\uc11c \ucd5c\ub300 \ud648\uc744 \uac00\uc838\ub294 \uc0ac\uc6a9\uc790\uc774 \uc52c\uc544\uc624\uba70 \uc0ac\uc6a9\uc790\uc758 \ud648\uc744 \uc54c\ub824\ud569\ub2c8\ub2e4.
tutorialstring=\ud14c\ud2b8\ub9ad
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0639\u0631\u0628\u064a\u0629)
chinese=\u4e2d\u6587 (\u4e2d\u6587)
dutch=Nederlands (\ub3c4\ucc99)
english=English (\uc601\uad6d\uc5b4)
french=Fran\u00e7ais (\ud504\ub791\uc81c\uc2a4\ucf54)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\uac8c\uc774\uc874)
german=Deutsch (\ub3c4\ucf54)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\ud567\ub9ac)
italian=Italiano (\uc774\ud0c0\ub9ac\uc5b4\ub098)
japanese=\u65e5\u672c\u8a9e (\uc65c\uc790\ub9ac\uc5b4)
korean=\ud55c\uad6d\uc5b4
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\ub85c\uc6b0\uc2a4\uc544\uc774\ucf58)
spanish=Espa\u00f1ol (\uc2a4\ud398\ub974\uc2a4\uc544\uc774\ucf58)

View File

@@ -1,17 +1,99 @@
# Window title
windowTitle=ISY Spellen Kiezer
accept=Accepteren
ai=Kunstmatige Intelligentie
app-title=ISY Spel Kiezer
are-you-sure=Weet je het zeker?
back=Terug
cancel=Annuleren
challenge=Uitdaging
computer-difficulty=Computermoeilijkheid
computer-think-time=Denktijd computer
computer=Computer
connect=Verbinden
credits=Credits
dark=Donker
deny=Weigeren
developers=Ontwikkelaars
disconnect=Verbreken
effects-volume=Effectvolume
enter-the-server-ip=Voer het server-IP in
enter-the-server-port=Voer de serverpoort in
enter-your-name=Voer je naam in
error=Fout
exit=Afsluiten
forfeit=Opgeven
fullscreen=Volledig scherm
game-over=Spel afgelopen
general=Algemeen
high-contrast=Hoog contrast
invalid-username=ongeldige gebruikersnaam
ip-address=IP-adres
is-not-a-valid-ip-address=is geen geldig IP-adres
is-not-a-valid-port=is geen geldige poort
language=Taal
large=Groot
layout-size=Lay-outgrootte
light=Licht
local=Lokaal
localization=Lokalisatie
master-volume=Hoofdvolume
medium=Middelgroot
merge-commander=Merge Commander
moral-support=Morele steun
music-volume=Muziekvolume
name=Naam
never=Nee, ik wil nooit tutorials zien.
no=Nee
ok=Ok<EFBFBD>
online=Online
opengl=OpenGL
options=Opties
play=Spelen
player-name=Spelersnaam
player=Speler
please-enter-your-name=Voer alstublieft je naam in
port=Poort
product-owner=Producteigenaar
quit=Stoppen
reversi=Reversi
scrum-master=Scrum Master
send=Verzenden
server-information=Serverinformatie
small=Klein
style=Stijl
the-game-ended-in-a-draw=Het spel eindigde in een gelijkspel
theme=Thema
tic-tac-toe=Boter Kaas en Eieren
tictactoe1 =Welkom bij het spel Boter, Kaas en Eieren! Je kunt je zet doen door op een van de 9 vakjes op het bord te klikken. Voorbeeld hierboven:
tictactoe2 =Een speler wint door 3 stukken op een rij te krijgen ? horizontaal, verticaal of diagonaal. In het voorbeeld hierboven wint de speler met een diagonale rij van drie stukken.
connect4=Vier op een rij
to-a-game-of=voor een spelletje
tutorial=Wil je een tutorial voor dit spel zien?
volume=Volume
windowed=Venstermodus
yes=Ja
you-lost-against=Je hebt verloren van
you-were-challenged-by=Je bent uitgedaagd door
you-win=Je wint
>=>
<=<
connect4.1=Welkom bij het spel Connect 4! Je kunt een zet doen door op een van de kolommen te klikken. De zet wordt geplaatst in de laagste nog lege rij van die kolom.
connect4.2=Je kunt winnen door 4 van je stukken horizontaal, diagonaal of verticaal op een rij te krijgen! Zie het voorbeeld hierboven.
reversi1=Welkom bij het spel Reversi! Je kunt een zet doen door op een van de licht transparante stippen te klikken.
reversi2=Door op een stip te klikken draai je alle stukken om tussen de plaats waar je de stip zet en de volgende stip die wordt gevonden. Zie het voorbeeld hierboven, waar geel de stukken zijn die omgedraaid worden.
reversi3=Je beurt kan worden overgeslagen als er geen legale zet is. Hierdoor kan je tegenstander doorgaan tot jij een legale zet kunt doen.
reversi4=De speler die aan het einde van het spel de meeste stukken op het bord heeft, wint.
tutorialstring=Tutorial
# Main Menu buttons
mainMenuSelectTicTacToe=Boter Kaas En Eieren
mainMenuSelectReversi=Reversi
mainMenuSelectSudoku=Sudoku
mainMenuSelectBattleship=Zeeslag
mainMenuSelectOther=Anders
mainMenuSelectCredits=Credits
mainMenuSelectOptions=Opties
mainMenuSelectQuit=Afsluiten
# Quit Menu text and buttons
quitMenuTextSure=Weet je het zeker?
quitMenuButtonYes=Ja
quitMenuButtonNo=Nee
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (Arabisch)
chinese=\u4e2d\u6587 (Chinees)
dutch=Nederlands
english=English (Engels)
french=Fran\u00e7ais (Frans)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (Georgisch)
german=Deutsch (Duits)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (Hindi)
italian=Italiano (Italiaans)
japanese=\u65e5\u672c\u8a9e (Japans)
korean=\ud55c\uad6d\uc5b4 (Koreaans)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (Russisch)
spanish=Espa\u00f1ol (Spaans)

View File

@@ -0,0 +1,99 @@
accept=\u041f\u0440\u0438\u043d\u044f\u0442\u044c
ai=\u0418\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442
app-title=ISY \u0412\u044b\u0431\u043e\u0440 \u0438\u0433\u0440
are-you-sure=\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b?
back=\u041d\u0430\u0437\u0430\u0434
cancel=\u041e\u0442\u043c\u0435\u043d\u0430
challenge=\u0412\u044b\u0437\u043e\u0432
connect4=Connect 4
computer-difficulty=\u0421\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430
computer-think-time=\u0412\u0440\u0435\u043c\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430
computer=\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440
connect=\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f
credits=\u041a\u0440\u0435\u0434\u0438\u0442\u044b
dark=\u0422\u0451\u043c\u043d\u044b\u0439
deny=\u041e\u0442\u043a\u0430\u0437\u0430\u0442\u044c
developers=\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438
disconnect=\u041e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f
effects-volume=\u0413\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432
enter-the-server-ip=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 IP \u0441\u0435\u0440\u0432\u0435\u0440\u0430
enter-the-server-port=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u043e\u0440\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430
enter-your-name=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0435 \u0438\u043c\u044f
error=\u041e\u0448\u0438\u0431\u043a\u0430
exit=\u0412\u044b\u0445\u043e\u0434
forfeit=\u0421\u0434\u0430\u0442\u044c \u0441\u043e\u0440\u043e\u0432\u043d\u043e\u0441\u0442\u0438
fullscreen=\u041f\u043e\u043b\u043d\u043e\u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c
game-over=\u0418\u0433\u0440\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u0430
general=\u041e\u0431\u0449\u0438\u0435
high-contrast=\u0412\u044B\u0441\u043E\u043A\u0430\u044F \u043A\u043E\u043D\u0442\u0440\u0430\u0441\u0442\u043D\u043E\u0441\u0442\u044C
invalid-username=\u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e\u0435 \u0438\u043c\u044f
ip-address=IP \u0430\u0434\u0440\u0435\u0441
is-not-a-valid-ip-address=\u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c IP \u0430\u0434\u0440\u0435\u0441\u043e\u043c
is-not-a-valid-port=\u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u043e\u0440\u0442\u043e\u043c
language=\u042f\u0437\u044b\u043a
large=\u0411\u043e\u043b\u044c\u0448\u043e\u0439
layout-size=\u0420\u0430\u0437\u043c\u0435\u0440 \u043c\u043e\u043d\u0442\u0430\u0436\u0430
light=\u0421\u0432\u0435\u0442\u043b\u044b\u0439
local=\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439
localization=\u041b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f
master-volume=\u041e\u0431\u0449\u0438\u0439 \u0433\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c
medium=\u0421\u0440\u0435\u0434\u043d\u0438\u0439
merge-commander=Merge Commander
moral-support=\u041c\u043e\u0440\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430
music-volume=\u0413\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c \u043c\u0443\u0437\u044b\u043a\u0438
name=\u0418\u043c\u044f
never=\u041d\u0435\u0442, \u044f \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0445\u043e\u0447\u0443 \u0432\u0438\u0434\u0435\u0442\u044c \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0438.
no=\u041d\u0435\u0442
ok=OK
online=\u0412 \u0441\u0435\u0442\u0438
opengl=OpenGL
options=\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
play=\u0418\u0433\u0440\u0430\u0442\u044c
player-name=\u0418\u043c\u044f \u0438\u0433\u0440\u043e\u043a\u0430
player=\u0418\u0433\u0440\u043e\u043a
please-enter-your-name=\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0435 \u0438\u043c\u044f
port=\u041f\u043e\u0440\u0442
product-owner=\u0412\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430
quit=\u0412\u044b\u0445\u043e\u0434
reversi=\u0420\u0435\u0432\u0435\u0440\u0441\u0438
scrum-master=Scrum Master
send=\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c
server-information=\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0435
small=\u041c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439
style=\u0421\u0442\u0438\u043b\u044c
the-game-ended-in-a-draw=\u0418\u0433\u0440\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430\u0441\u044c \u043d\u0438\u0447\u044c\u0435\u0439
theme=\u0422\u0435\u043c\u0430
tic-tac-toe=\u041a\u0440\u0435\u0441\u0442\u0438\u043a\u043e
tictactoe1 =\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u0438\u0433\u0440\u0443 \u041a\u0440\u0435\u0441\u0442\u0438\u043a\u0438-\u043d\u043e\u043b\u0438\u043a\u0438! \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u043e\u0434, \u043d\u0430\u0436\u0430\u0432 \u043d\u0430 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 9 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u043e\u0432 \u043d\u0430 \u043f\u043e\u043b\u0435. \u041f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0448\u0435:
tictactoe2 =\u0418\u0433\u0440\u043e\u043a \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442, \u0435\u0441\u043b\u0438 \u0441\u0442\u0430\u0432\u0438\u0442 3 \u0441\u0438\u043c\u0432\u043e\u043b\u0430 \u043f\u043e\u0434\u0440\u044f\u0434 ? \u043f\u043e \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u0438, \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438 \u0438\u043b\u0438 \u0434\u0438\u0430\u0433\u043e\u043d\u0430\u043b\u0438. \u0412 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u043e\u043c \u0432\u044b\u0448\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0433\u0440\u043e\u043a \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442 \u043f\u043e \u0434\u0438\u0430\u0433\u043e\u043d\u0430\u043b\u0438
to-a-game-of=\u043a \u0438\u0433\u0440\u0435 \u0432
tutorial=\u0425\u043e\u0447\u0435\u0448\u044c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0443\u0447\u0435\u0431\u043d\u0438\u043a \u043f\u043e \u044d\u0442\u043e\u0439 \u0438\u0433\u0440\u0435?
volume=\u0413\u0440\u043e\u043c\u043a\u043e\u0441\u0442\u044c
windowed=\u041e\u043a\u043d\u043e
yes=\u0414\u0430
you-lost-against=\u0412\u044b \u043f\u0440\u043e\u0438\u0433\u0440\u0430\u043b\u0438 \u043a\u043e\u043c\u0443
you-were-challenged-by=\u0412\u0430\u0441 \u0432\u044b\u0437\u0432\u0430\u043b \u043d\u0430 \u0441\u043e\u0440\u0435\u0432\u043d\u0438\u043a
you-win=\u0412\u044b \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442\u0435
>=>
<=<
connect4.1=\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u0438\u0433\u0440\u0443 Connect 4! \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u043e\u0434, \u043a\u043b\u0438\u043a\u043d\u0443\u044f \u043f\u043e \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432. \u0425\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d \u0432 \u043d\u0438\u0436\u0430\u0439 \u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432 \u044d\u0442\u043e\u0439 \u043a\u043e\u043b\u043e\u043d\u043a\u0435.
connect4.2=\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u0438\u0433\u0440\u0430\u0442\u044c, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0432 4 \u0444\u0438\u0448\u043a\u0438 \u0432\u0430\u0448\u0435\u0433\u043e \u0446\u0432\u0435\u0442\u0430 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e, \u0434\u0438\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u0438\u043b\u0438 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e!
reversi1=\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u0438\u0433\u0440\u0443 Reversi! \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u043e\u0434, \u043a\u043b\u0438\u043a\u043d\u0443\u044f \u043f043 \u043f043 \u043d043 \u043e043 \u043d043 \u043e043 \u043a043 \u0430043 \u043a043 \u0430043.
reversi2=\u041d043 \u043d043 \u0430043 \u043a043 \u0430043 \u043a043 \u043e043 \u043c043 \u0435043 \u0436043 \u0435043 \u0434043 \u0435043 \u043d043 \u0430043.
reversi3=\u0412043 \u0430043 \u0436043 \u0434043 \u0430043 \u043d043 \u0438043 \u043d043 \u0435043 \u0435043 \u0432043 \u0430043.
reversi4=\u0418043 \u0433043 \u0440043 \u043e043 \u043a043 \u043e043 \u0442043 \u043e043 \u0442043 \u043e043 \u0435043 \u0435043 \u0430043 \u0435043 \u043d043 \u0438043 \u0435043 \u0435043 \u043c043 \u0430043.
tutorialstring=\u0423\u0447\u0435\u0431\u043d\u0438\u043a
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u0410\u0440\u0430\u0431\u0441\u043a\u0438\u0439)
chinese=\u4e2d\u6587 (\u041a\u0438\u0442\u0430\u0439\u0441\u043a\u0438\u0439)
dutch=Nederlands (\u041d\u0438\u0434\u0435\u0440\u043b\u0430\u043d\u0434\u0441\u043a\u0438\u0439)
english=English (\u0410\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439)
french=Fran\u00e7ais (\u0424\u0440\u0430\u043d\u0446\u0443\u0437\u0441\u043a\u0438\u0439)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u0413\u0440\u0443\u0437\u0438\u043d\u0441\u043a\u0438\u0439)
german=Deutsch (\u041d\u0435\u043c\u0435\u0446\u043a\u0438\u0439)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\u0425\u0438\u043d\u0434\u0438)
italian=Italiano (\u0418\u0442\u0430\u043b\u044c\u044f\u043d\u0441\u043a\u0438\u0439)
japanese=\u65e5\u672c\u8a9e (\u042f\u043f\u043e\u043d\u0441\u043a\u0438\u0439)
korean=\ud55c\uad6d\uc5b4 (\u041a\u043e\u0440\u0435\u0439\u0441\u043a\u0438\u0439)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439
spanish=Espa\u00f1ol (\u0418\u0441\u043f\u0430\u043d\u0441\u043a\u0438\u0439)

View File

@@ -1,30 +1,99 @@
# suppress inspection "LossyEncoding" for whole file
# Window title
windowTitle=ISY \u6E38\u620F\u9009\u62E9\u5668
# ?????
accept=\u63a5\u53d7
ai=\u4eba\u5de5\u667a\u80fd
app-title=ISY \u6e38\u620f\u9009\u62e9\u5668
are-you-sure=\u60a8\u786e\u5b9a\u5417\uff1f
back=\u8fd4\u56de
cancel=\u53d6\u6d88
challenge=\u6311\u6218
computer-difficulty=\u8ba1\u7b97\u673a\u96be\u5ea6
computer-think-time=\u8ba1\u7b97\u673a\u601d\u8003\u65f6\u95f4
computer=\u8ba1\u7b97\u673a
connect=\u8fde\u63a5
connect4=Connect 4
credits=\u81f4\u8c22
dark=\u6697\u8272
deny=\u62d2\u7edd
developers=\u5f00\u53d1\u8005
disconnect=\u65ad\u5f00\u8fde\u63a5
effects-volume=\u6548\u679c\u97f3\u91cf
enter-the-server-ip=\u8f93\u5165\u670d\u52a1\u5668 IP
enter-the-server-port=\u8f93\u5165\u670d\u52a1\u5668\u7aef\u53e3
enter-your-name=\u8f93\u5165\u60a8\u7684\u540d\u5b57
error=\u9519\u8bef
exit=\u9000\u51fa
forfeit=\u68c0\u8f93
fullscreen=\u5168\u5c4f
game-over=\u6e38\u620f\u7ed3\u675f
general=\u901a\u7528
high-contrast=\u9AD8\u5BF9\u6BD4\u5EA6
invalid-username=\u7528\u6237\u540d\u65e0\u6548
ip-address=IP \u5730\u5740
is-not-a-valid-ip-address=\u4e0d\u662f\u6709\u6548\u7684 IP \u5730\u5740
is-not-a-valid-port=\u4e0d\u662f\u6709\u6548\u7684\u7aef\u53e3
language=\u8bed\u8a00
large=\u5927
layout-size=\u5e03\u5c40\u5927\u5c0f
light=\u4eae\u8272
local=\u672c\u5730
localization=\u672c\u5730\u5316
master-volume=\u603b\u97f3\u91cf
medium=\u4e2d
merge-commander=\u5408\u5e76\u6307\u6325
moral-support=\u7cbe\u795e\u652f\u6301
music-volume=\u97f3\u4e50\u97f3\u91cf
name=\u540d\u5b57
never=\u4e0d\uff0c\u6211\u5b8c\u5168\u4e0d\u60f3\u518d\u770b\u5230\u4efb\u4f55\u6559\u7a0b\u3002
no=\u4e0d
ok=\u786e\u5b9a
online=\u5728\u7ebf
opengl=OpenGL
options=\u9009\u9879
play=\u6e38\u73a9
player-name=\u73a9\u5bb6\u540d
player=\u73a9\u5bb6
please-enter-your-name=\u8bf7\u8f93\u5165\u60a8\u7684\u540d\u5b57
port=\u7aef\u53e3
product-owner=\u4ea7\u54c1\u62e5\u6709\u8005
quit=\u9000\u51fa
reversi=\u9ed1\u767d\u68cb
scrum-master=\u9879\u76ee\u7ecf\u7406
send=\u53d1\u9001
server-information=\u670d\u52a1\u5668\u4fe1\u606f
small=\u5c0f
style=\u98ce\u683c
the-game-ended-in-a-draw=\u6e38\u620f\u4ee5\u548c\u5c40\u7ed3\u675f
theme=\u4e3b\u9898
tic-tac-toe=\u4e09\u5b9a\u7ebf
tictactoe1 =\u6b22\u8fce\u6765\u5230\u4e95\u5b57\u68cb\u6e38\u620f\uff01\u4f60\u53ef\u4ee5\u901a\u8fc7\u70b9\u51fb\u68cb\u76d8\u4e0a\u4efb\u610f\u4e00\u4e2a\u4e5d\u4e2a\u65b9\u683c\u6765\u843d\u5b50\u3002\u4e0a\u65b9\u793a\u4f8b\uff1a
tictactoe2 =\u73a9\u5bb6\u5728\u6a2a\u3001\u7ad6\u6216\u659c\u7ebf\u4e0a\u8fde\u7eed\u653e\u7f6e\u4e09\u4e2a\u68cb\u5b50\u5373\u53ef\u83b7\u80dc\u3002\u5728\u4e0a\u65b9\u7684\u793a\u4f8b\u4e2d\uff0c\u73a9\u5bb6\u901a\u8fc7\u659c\u7ebf\u4e0a\u7684\u4e09\u4e2a\u68cb\u5b50\u83b7\u80dc\u4e86\u6bd4\u8d5b\u3002
to-a-game-of=\u6311\u6218\u4e00\u573a
tutorial=\u4f60\u60f3\u770b\u8fd9\u4e2a\u6e38\u620f\u7684\u6559\u7a0b\u5417\uff1f
volume=\u97f3\u91cf
windowed=\u7a97\u53e3\u6a21\u5f0f
yes=\u662f
you-lost-against=\u60a8\u8f93\u7ed9\u4e86
you-were-challenged-by=\u60a8\u88ab\u6311\u6218\u81ea
you-win=\u60a8\u83b7\u80dc\u4e86
>=>
<=<
connect4.1=\u6b22\u8fce\u6765\u5230 Connect 4 \u6e38\u620f! \u4f60\u53ef\u4ee5\u70b9\u51fb\u4e00\u5217\u6761\u76ee\u64cd\u4f5c. \u64cd\u4f5c\u5c06\u88c5\u7f6e\u5728\u672a\u88c5\u5165\u7684\u6700\u4f4e\u884c.
connect4.2=\u5982\u679c\u5f97\u52304\u4e2a\u5bf9\u5e94\u7684\u4ee3\u7406\u7ec4\u6210\u6c34\u5e73\u3001\u5347\u5e26\u6216\u5782\u76f4\u5373\u53ef\u80dc. \u770b\u4e0a\u65b9\u793a\u4f8b.
reversi1=\u6b22\u8fce\u6765\u5230 Reversi \u6e38\u620f! \u4f60\u53ef\u4ee5\u70b9\u51fb\u4e00\u4e2a\u9ed8\u8272\u5149\u900f\u7a7a\u70b9\u64cd\u4f5c.
reversi2=\u70b9\u51fb\u4e00\u4e2a\u70b9\u65f6\u5c06\u5c06\u6240\u6709\u4e2d\u95f4\u7684\u4ee3\u7406\u7ffb\u8f6c\u3002 \u770b\u4e0a\u65b9\u793a\u4f8b\uff0c\u9ec4\u8272\u662f\u5bf9\u4ee3\u7406\u9700\u64ad\u7684\u4ee3\u7406.
reversi3=\u5982\u679c\u6ca1\u6709\u5408\u6cd5\u64cd\u4f5c\u4f60\u7684\u8fdb\u6b65\u53ef\u80fd\u88ab\u5ffd\u7565. \u8fd9\u4f1a\u8ba9\u5bf9\u624b\u518d\u6b21\u64cd\u4f5c\u5230\u4f60\u6709\u5408\u6cd5\u64cd\u4f5c\u65f6.
reversi4=\u672c\u6e38\u620f\u7ed3\u675f\u65f6\u8d62\u5f97\u6ee1\u8fc7\u76d8\u9762\u7684\u4ee3\u7406\u6570\u6700\u591a\u7684\u4eba\u5c31\u80dc.
tutorialstring=\u6559\u7a0b
# Main Menu buttons
mainMenuSelectTicTacToe=\u4E95\u5B57\u68CB
# ???
mainMenuSelectReversi=\u9ED1\u767D\u68CB
# ???
mainMenuSelectSudoku=\u6570\u72EC
# ??
mainMenuSelectBattleship=\u6D77\u6218\u68CB
# ???
mainMenuSelectOther=\u5176\u4ED6
# ??
mainMenuSelectCredits=\u5236\u4F5C\u4EBA\u5458
# ????
mainMenuSelectOptions=\u9009\u9879
# ??
mainMenuSelectQuit=\u9000\u51FA
# ??
# Quit Menu text and buttons
quitMenuTextSure=\u4F60\u786E\u5B9A\u5417\uFF1F
# ?????
quitMenuButtonYes=\u662F
# ?
quitMenuButtonNo=\u5426
# ?
arabic=\u0627\u0644\u0639\u0631\u0628\u064a\u0629 (\u963f\u62c9\u4f2f\u8bed)
chinese=\u4e2d\u6587
dutch=Nederlands (\u8377\u5170\u8bed)
english=English (\u82f1\u8bed)
french=Fran\u00e7ais (\u6cd5\u8bed)
georgian=\u10e5\u10d0\u10e0\u10d4\u10e1\u10d8 (\u683c\u9c81\u5409\u4e9a\u8bed)
german=Deutsch (\u5fb7\u8bed)
hindi=\u0939\u093f\u0928\u094d\u0926\u0940 (\u5370\u5ea6\u8bed)
italian=Italiano (\u610f\u5927\u5229\u8bed)
japanese=\u65e5\u672c\u8a9e (\u65e5\u8bed)
korean=\ud55c\uad6d\uc5b4 (\u97e9\u8bed)
russian=\u0420\u0443\u0441\u0441\u043a\u0438\u0439 (\u4fc4\u8bed)
spanish=Espa\u00f1ol (\u897f\u73ed\u7259\u8bed)

View File

@@ -1,37 +0,0 @@
.background {
-fx-background-color: linear-gradient(to bottom right, #21a7b2, #8f32b9);
}
.text {
-fx-fill: white;
-fx-font-family: "Segoe UI", sans-serif;
-fx-font-weight: bold;
-fx-font-size: 24px;
}
.button, .text-field, .combo-box, .combo-box-popup .list-cell {
-fx-padding: 10 20;
-fx-background-color: transparent;
-fx-border-color: transparent;
}
.combo-box-popup .list-view {
-fx-background-color: #1d1d1d;
}
.text-field {
-fx-text-fill: white;
}
.button:hover, .text-field:hover, .combo-box:hover, .combo-box-popup .list-cell:hover {
-fx-cursor: hand;
-fx-effect: dropshadow(gaussian, #00ffff7f, 10, 0.5, 0, 0);
-fx-border-color: white;
}
.text-field:focused, .combo-box:focused {
-fx-border-color: white;
}

View File

@@ -0,0 +1,199 @@
.bg-primary {
-fx-background-color: linear-gradient(to bottom, #2a3a45, #1c2730);
}
.bg-secondary {
-fx-background-color: linear-gradient(to bottom, #3b4a57, #2a3742);
}
.bg-popup {
-fx-background-color: rgba(20, 40, 55, 0.9);
-fx-background-radius: 8;
-fx-effect: dropshadow(gaussian, #224455cc, 8, 0, 0, 2);
}
.song-display {
-fx-padding: 8 12 8 12;
-fx-spacing: 6px;
-fx-alignment: center;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.5), 6, 0.5, 0, 2);
-fx-min-width: 220px;
-fx-max-width: 260px;
}
.song-title {
-fx-font-size: 14px;
-fx-fill: white;
}
.progress-bar {
-fx-pref-width: 200px;
-fx-accent: red;
}
.progress-bar > .track {
-fx-background-radius: 30;
}
.progress-bar > .bar {
-fx-background-radius: 30px;
}
.progress-text {
-fx-font-size: 11px;
-fx-fill: white;
}
.skip-button {
-fx-background-color: transparent;
-fx-background-radius: 0;
-fx-cursor: hand;
-fx-text-fill: white;
}
.skip-button .text {
-fx-fill: white;
}
.pause-button {
-fx-background-color: transparent;
-fx-background-radius: 0;
-fx-cursor: hand;
-fx-text-fill: white;
}
.pause-button .text {
-fx-fill: white;
}
.previous-button {
-fx-background-color: transparent;
-fx-background-radius: 0;
-fx-cursor: hand;
-fx-text-fill: white;
}
.previous-button .text {
-fx-fill: white;
}
.button {
-fx-background-color: linear-gradient(to bottom, #1f5e20, #2e7d2e);
-fx-background-radius: 8;
-fx-border-color: #3caf3f;
-fx-cursor: hand;
-fx-effect: dropshadow(gaussian, #3caf3fdd, 6, 0, 0, 2);
-fx-text-fill: #e0f2e9;
-fx-font-weight: bold;
}
.button:hover {
-fx-background-color: linear-gradient(to bottom, #44a044, #57b257);
-fx-border-color: #2f7d2f;
}
.combo-box {
-fx-background-color: linear-gradient(to bottom, #3c5155, #2a3a3e);
-fx-background-radius: 6;
-fx-border-color: #3caf3f;
-fx-cursor: hand;
}
.combo-box:hover {
-fx-border-color: #55a755;
}
.combo-box:focused {
-fx-border-color: #88cc88;
-fx-effect: dropshadow(gaussian, #88cc8899, 5, 0, 0, 1);
}
.combo-box .arrow,
.combo-box .arrow-button {
-fx-background-color: transparent;
-fx-border-color: transparent;
}
.combo-box .list-cell {
-fx-background-color: transparent;
-fx-text-fill: #a8d0a8;
}
.combo-box .list-view {
-fx-background-color: #264233;
-fx-background-radius: 6;
-fx-border-color: #3caf3f;
}
.combo-box-popup .list-cell {
-fx-text-fill: #a8d0a8;
}
.combo-box-popup .list-cell:hover {
-fx-background-color: #44a044;
}
.combo-box-popup .list-cell:selected {
-fx-background-color: #2e7d2e;
-fx-text-fill: #e0f2e9;
}
.input {
-fx-background-color: linear-gradient(to bottom, #1f3a3b, #124040);
-fx-background-radius: 6;
-fx-border-color: #3caf3f;
-fx-text-fill: #a8d0a8;
-fx-font-weight: normal;
}
.input:hover {
-fx-border-color: #55a755;
}
.input:focused {
-fx-border-color: #88cc88;
-fx-effect: dropshadow(gaussian, #88cc8899, 5, 0, 0, 1);
}
.my-turn {
-fx-fill: #e05656;
-fx-font-weight: bold;
}
.separator .line {
-fx-border-color: #55a755;
-fx-opacity: 1;
}
.slider {
-fx-background-color: transparent;
}
.slider .thumb {
-fx-background-color: linear-gradient(to bottom, #2e7d2e, #44a044);
-fx-background-radius: 50%;
-fx-effect: dropshadow(gaussian, #3caf3fdd, 5, 0, 0, 1);
}
.slider .thumb:hover {
-fx-scale-x: 1.15;
-fx-scale-y: 1.15;
}
.slider .track {
-fx-background-color: linear-gradient(to left, #57b257, #e05c5c);
-fx-background-insets: 0;
-fx-background-radius: 6;
}
.text {
-fx-fill: #a8d0a8;
-fx-font-weight: normal;
-fx-text-fill: #a8d0a8;
}
.header {
-fx-fill: #88cc88;
-fx-font-weight: bold;
-fx-text-fill: #88cc88;
}

Some files were not shown because too many files have changed in this diff Show More