214 Commits

Author SHA1 Message Date
Johannes Schmelz
bcf4956d2d TradeReplay popup 2024-12-02 03:16:50 +01:00
Johannes Schmelz
13754c843a clean up 2024-12-02 03:03:42 +01:00
Johannes Schmelz
4743a6882c fixed testing env 2024-12-02 03:02:05 +01:00
Johannes Schmelz
2dbc727728 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 03:00:28 +01:00
Johannes Schmelz
560bedc80b mortage 2024-12-02 03:00:22 +01:00
Johannes Schmelz
7ace959f1f sellHouse 2024-12-02 02:48:06 +01:00
Yvonne Schmidt
95dc7b07e2 fixed typos 2024-12-02 02:40:53 +01:00
Yvonne Schmidt
fa20a6cb2a Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 01:50:20 +01:00
Yvonne Schmidt
36b308e616 fixed TradeMenu formating 2024-12-02 01:49:56 +01:00
Johannes Schmelz
b912835edb Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 01:37:37 +01:00
Johannes Schmelz
add5dab611 buyHouse complete 2024-12-02 01:37:32 +01:00
Johannes Schmelz
5172766216 cleanup 2024-12-02 01:34:43 +01:00
Yvonne Schmidt
fcb55e52fc fixed esc in BuildingAdminMenu 2024-12-02 01:11:38 +01:00
Yvonne Schmidt
411f7ea25b added selector and selection display to RepayMortage 2024-12-02 01:06:58 +01:00
Yvonne Schmidt
e05ad71fff added selector and selection display to TakeMortage 2024-12-02 01:03:55 +01:00
Yvonne Schmidt
d08a172227 added selector and selection display to SellHouse 2024-12-02 00:59:10 +01:00
Johannes Schmelz
4fff8394d9 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 00:48:53 +01:00
Johannes Schmelz
5bb438c221 working selector 2024-12-02 00:47:06 +01:00
Simon Wilkening
a753017fcd Rent relabeled 2024-12-01 23:52:25 +01:00
Yvonne Schmidt
5522be228b added selection display 2024-12-01 23:22:19 +01:00
Johannes Schmelz
3b729c9a04 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 23:12:51 +01:00
Johannes Schmelz
eda2fcd327 jail logic complete 2024-12-01 23:11:02 +01:00
Simon Wilkening
09e12fc610 GulagInfo renamed 2024-12-01 22:08:28 +01:00
Johannes Schmelz
93152f4073 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 21:55:10 +01:00
Johannes Schmelz
17a1d3fbbb fixed rent 2024-12-01 21:55:06 +01:00
Yvonne Schmidt
a0e2b6e8e2 Merge remote-tracking branch 'origin/gui' into gui 2024-12-01 21:54:30 +01:00
Yvonne Schmidt
79a08a0c9e replaced listbox in sellHouse with a selector 2024-12-01 21:53:53 +01:00
Simon Wilkening
a24d6fd4b6 BuildingFields corrected 2024-12-01 21:44:14 +01:00
Johannes Schmelz
f220aeb78c resolve merge 2024-12-01 21:42:05 +01:00
Luca Puderbach
85e0c68a36 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 21:33:18 +01:00
Luca Puderbach
113e1b7aa5 Spieler Bewegungs hochdatum 2024-12-01 21:33:07 +01:00
Johannes Schmelz
cfcc232432 trigger Bankrupt PopUp 2024-12-01 21:30:55 +01:00
Johannes Schmelz
29e9b54cc4 trigger NoMoneyPopUp 2024-12-01 21:24:33 +01:00
Yvonne Schmidt
0c90d1f185 Merge remote-tracking branch 'origin/gui' into gui 2024-12-01 21:19:20 +01:00
Yvonne Schmidt
b5090ea179 fixed overlapping with propertycard 2024-12-01 21:18:57 +01:00
Johannes Schmelz
cfbf20f745 payBail 2024-12-01 20:55:58 +01:00
Johannes Schmelz
dd002746aa trigger winner and looser popup 2024-12-01 20:52:29 +01:00
Johannes Schmelz
11f4560745 du kommst ins Gulag Popup 2024-12-01 20:31:29 +01:00
Johannes Schmelz
b702e3a14d first tests 2024-12-01 20:12:36 +01:00
Johannes Schmelz
3b2cfad774 fixed TradeConfrim 2024-12-01 19:20:34 +01:00
Johannes Schmelz
9164dc6893 formatting 2024-12-01 18:37:53 +01:00
Simon Wilkening
d3cf36ecb1 BuildingFields corrected 2024-12-01 18:23:20 +01:00
Johannes Schmelz
7d0a0123e0 server side logic for propertyAdmin 2024-12-01 18:17:46 +01:00
Johannes Schmelz
2f025e2e1a sort according to id 2024-12-01 17:51:24 +01:00
Luca Puderbach
9bf9e8406b model pfad gefixt 2024-12-01 16:29:25 +01:00
Johannes Schmelz
6bd1ed6e3a earnMoney with event card movement 2024-12-01 16:05:57 +01:00
Johannes Schmelz
0f6205fbc7 fixed topDialog 2024-12-01 15:57:33 +01:00
Johannes Schmelz
f2a6888fb2 fixed JailState 2024-12-01 15:50:09 +01:00
Johannes Schmelz
5143e21ba6 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 13:53:55 +01:00
Johannes Schmelz
26dc24a1f4 fixed verhandeln 2024-12-01 13:53:50 +01:00
Luca Puderbach
350c157493 Figuren Animationen 2024-12-01 05:38:27 +01:00
Luca Puderbach
51b879a7c8 Figuren Bewegung eingefügt 2024-12-01 05:05:11 +01:00
Luca Puderbach
528126aa29 Kleines Ereigniskarten update 2024-12-01 05:04:27 +01:00
Luca Puderbach
73bfafa7f7 Anpassungen Ereigniskarten 2024-12-01 03:00:30 +01:00
Luca Puderbach
686a12e465 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 02:47:34 +01:00
Luca Puderbach
358beacc65 Mozzarella Update 2024-12-01 02:47:30 +01:00
Johannes Schmelz
69db0aa29b Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 02:47:12 +01:00
Johannes Schmelz
20f44ad2d4 fixed San cost 2024-12-01 02:40:12 +01:00
Simon Wilkening
d73c5e0904 Farben angepasst 2024-12-01 02:23:50 +01:00
Johannes Schmelz
f322e9bd8f Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 02:14:13 +01:00
Johannes Schmelz
b8e1645eb8 fixed player movement and go money 2024-12-01 02:14:09 +01:00
Simon Wilkening
73a908cd71 PorpertyOverwiev gerettet 2024-12-01 02:10:10 +01:00
Johannes Schmelz
a6b7ea4ce8 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 02:08:20 +01:00
Johannes Schmelz
4af08ffffd fix trade reject 2024-12-01 02:07:39 +01:00
Yvonne Schmidt
dc66fd7384 changed font colors and sizes 2024-12-01 01:48:09 +01:00
Simon Wilkening
16ff61264b BuyHouse etc. aktualisiert 2024-12-01 00:47:12 +01:00
Luca Puderbach
f3ec17b0b1 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 00:39:05 +01:00
Luca Puderbach
1c31915627 Werkzeugbank Rand 2024-12-01 00:39:00 +01:00
Yvonne Schmidt
79c96677bd Merge remote-tracking branch 'origin/gui' into gui 2024-12-01 00:35:27 +01:00
Yvonne Schmidt
54118071cb fixed popup overlap 2024-12-01 00:34:57 +01:00
Johannes Schmelz
2e28b54936 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-01 00:30:55 +01:00
Johannes Schmelz
f333e2d2c0 button function 2024-12-01 00:30:50 +01:00
Yvonne Schmidt
b89d40b39f fixed nullPointer 2024-12-01 00:14:04 +01:00
Yvonne Schmidt
488ae154cf fixed overlapping popups 2024-11-30 23:26:37 +01:00
Johannes Schmelz
c1e501c271 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-30 22:39:12 +01:00
Johannes Schmelz
89d5185c91 rent popup fixed 2024-11-30 22:39:08 +01:00
Simon Wilkening
f4bf38bca1 AcceptTrade, RejectTrade und NoMoneyWarning hinzugefügt 2024-11-30 22:01:35 +01:00
Johannes Schmelz
b87b3f054b trigger rent popup 2024-11-30 21:49:16 +01:00
Johannes Schmelz
f6137b8b68 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-30 20:50:40 +01:00
Johannes Schmelz
87309235bd trade logic complete 2024-11-30 20:50:36 +01:00
Simon Wilkening
d37017bfa0 Winner and Looser Popup close the game again 2024-11-30 20:33:08 +01:00
Simon Wilkening
5d6440bd50 Eventcards korrigiert 2024-11-30 20:20:43 +01:00
Johannes Schmelz
a70295f1ff Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-30 15:15:35 +01:00
Johannes Schmelz
b681b13468 send Trades 2024-11-30 15:15:30 +01:00
Johannes Schmelz
2c536f32cf fixed close on FoodField 2024-11-30 15:14:58 +01:00
Yvonne Schmidt
991fe5280f centered account values 2024-11-30 01:03:11 +01:00
Yvonne Schmidt
174fe5cfb3 resized LooserPopUp 2024-11-30 00:58:24 +01:00
Yvonne Schmidt
119284f256 resized WinnerPopUp 2024-11-30 00:40:58 +01:00
Yvonne Schmidt
05680af726 fixed BuildingAdminMenu 2024-11-29 23:07:58 +01:00
Johannes Schmelz
fba82f670b fixed jailState 2024-11-29 19:21:27 +01:00
Johannes Schmelz
afa2ebd004 set correct translation 2024-11-29 19:04:00 +01:00
Johannes Schmelz
f0eeff3493 update view 2024-11-29 18:27:25 +01:00
Johannes Schmelz
44d64c4e0f trigger timeoutPopup 2024-11-29 17:42:10 +01:00
Johannes Schmelz
86ece3b70d fixed move logic 2024-11-29 16:44:28 +01:00
Simon Wilkening
6cdad71693 Gulag und Rent erstellt 2024-11-29 08:57:11 +01:00
Simon Wilkening
cf6d5ea22e BuyHouse, RepayMortage und TakeMortage erstellt 2024-11-29 08:27:51 +01:00
Yvonne Schmidt
ecf227daa6 added colored strip to toolbar 2024-11-29 07:42:59 +01:00
Luca Puderbach
4b5a156865 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-29 07:22:51 +01:00
Luca Puderbach
cfae369fd3 Anzeige Spielerfarbe + Figur Pos 2024-11-29 07:22:46 +01:00
Simon Wilkening
b05eabbbf8 Verschiedene Popups kommentiert und richtig benannt 2024-11-29 07:21:28 +01:00
Simon Wilkening
fd178eee43 Merge remote-tracking branch 'origin/gui' into gui
# Conflicts:
#	Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/ConfirmTrade.java
2024-11-29 07:16:21 +01:00
Simon Wilkening
aef2ef34fb Verschiedene Popups kommentiert und richtig benannt 2024-11-29 07:14:44 +01:00
Johannes Schmelz
fcbffa1189 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-29 07:11:24 +01:00
Johannes Schmelz
0d8240381e fixed some mistakes 2024-11-29 07:11:20 +01:00
Yvonne Schmidt
77da6679ef added another label styling 2024-11-29 06:55:59 +01:00
Yvonne Schmidt
5845254caa added new label styling 2024-11-29 06:47:26 +01:00
Yvonne Schmidt
5d92d7cfcc Merge remote-tracking branch 'origin/gui' into gui 2024-11-29 06:42:56 +01:00
Yvonne Schmidt
67f6649242 added selector with no integration 2024-11-29 06:34:42 +01:00
Johannes Schmelz
1438ae5e4f improve position calc 2024-11-29 06:26:09 +01:00
Johannes Schmelz
01c351e64b Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-29 06:23:12 +01:00
Johannes Schmelz
b0c21dfcb8 added trigger for winner looser popup 2024-11-29 06:23:08 +01:00
Simon Wilkening
f4cddbc87f Bankrott-Warnung und Timeout-Warning kommentiert und richtig benannt 2024-11-29 06:20:23 +01:00
Luca Puderbach
cfce176c82 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-29 06:20:03 +01:00
Luca Puderbach
782b1a10c3 Kleine model Changes 2024-11-29 06:19:58 +01:00
Johannes Schmelz
2d9cd0e4e1 resolve merge conflict 2024-11-29 06:17:57 +01:00
Johannes Schmelz
908ba09e2a more models 2024-11-29 05:58:28 +01:00
Johannes Schmelz
4a84ef4b3c more models 2024-11-29 05:58:15 +01:00
Johannes Schmelz
f3353327dd added first models 2024-11-29 05:56:39 +01:00
Johannes Schmelz
316433f592 resolve merge conflicts 2024-11-29 05:33:03 +01:00
Yvonne Schmidt
1ccdea0c87 Merge remote-tracking branch 'origin/gui' into gui 2024-11-29 05:16:44 +01:00
Yvonne Schmidt
7d9af0c4c7 added selector to SellHouse 2024-11-29 05:16:33 +01:00
Simon Wilkening
a1247cdae5 Bankrott-Warnung und Timeout-Warning erstellt erstellt 2024-11-29 05:11:24 +01:00
Luca Puderbach
5696192cce Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-29 04:41:14 +01:00
Luca Puderbach
91826b730f Lade Figuren auf Spielbrett 2024-11-29 04:35:16 +01:00
Johannes Schmelz
48b1cf817a refactor 2024-11-29 04:32:57 +01:00
Johannes Schmelz
94ba9f0af2 rudimentary function for trade 2024-11-29 03:07:17 +01:00
Yvonne Schmidt
333f27a016 modified toolbar button behaviour 2024-11-28 23:41:45 +01:00
Johannes Schmelz
b67379a6c3 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-28 22:56:06 +01:00
Johannes Schmelz
1e6188cf24 open buy popups 2024-11-28 22:56:02 +01:00
Yvonne Schmidt
12e859edd5 finished PropertyOverviewMenu 2024-11-28 21:55:44 +01:00
Johannes Schmelz
e000dcfc51 cleanup 2024-11-28 19:50:53 +01:00
Johannes Schmelz
e7a06159bb Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-28 19:42:07 +01:00
Johannes Schmelz
c900b6384d lock button when not active 2024-11-28 19:40:30 +01:00
Simon Wilkening
970a0ae254 Gebäude_Abreißen erstellt 2024-11-28 04:34:33 +01:00
Yvonne Schmidt
5e0ac0abc7 fixed button disabled behaviour 2024-11-28 03:58:40 +01:00
Simon Wilkening
bcd6711965 Merge remote-tracking branch 'origin/gui' into gui 2024-11-28 03:16:35 +01:00
Simon Wilkening
bb63a4df9f Popup_Handel_bestätigen erstellt 2024-11-28 03:16:11 +01:00
Yvonne Schmidt
b4d7349583 added framework for PropertyOverviewMenu 2024-11-28 03:00:28 +01:00
Luca Puderbach
fed8a3fd2d Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-28 02:31:50 +01:00
Luca Puderbach
bc6e7174ec Test Modelle Umbenannt 2024-11-28 02:31:43 +01:00
Yvonne Schmidt
075f98883a fixed toolbar fontsize 2024-11-28 02:02:29 +01:00
Yvonne Schmidt
c9df3a6176 Merge remote-tracking branch 'origin/gui' into gui 2024-11-28 00:40:25 +01:00
Johannes Schmelz
b2d2a79b00 added hslider 2024-11-28 00:40:11 +01:00
Luca Puderbach
26d8283930 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-28 00:18:27 +01:00
Luca Puderbach
4079c0a32c Würfel animation hinzugefügt 2024-11-28 00:13:32 +01:00
Johannes Schmelz
6d72a94fe4 event card complete 2024-11-28 00:07:32 +01:00
Yvonne Schmidt
227a7a027f added comments 2024-11-27 23:40:16 +01:00
Johannes Schmelz
9e595b92ba crash when rolling dice and waitForTurn removed 2024-11-27 23:19:25 +01:00
Luca Puderbach
c346058631 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-27 17:34:52 +01:00
Luca Puderbach
f2678ea33d doppelwürfel 2024-11-27 17:34:41 +01:00
Yvonne Schmidt
45a43d6998 Merge remote-tracking branch 'origin/gui' into gui 2024-11-27 00:17:31 +01:00
Yvonne Schmidt
cb9888af7a completed BuildingAdminMenu 2024-11-27 00:17:04 +01:00
Johannes Schmelz
93b183254f Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-27 00:11:11 +01:00
Johannes Schmelz
e92b305a56 cleanup 2024-11-27 00:11:07 +01:00
Johannes Schmelz
5b0628da15 dynamically get the fieldid for by popups 2024-11-27 00:10:59 +01:00
Yvonne Schmidt
8d087a8e84 added framework for BuildingAdminMenu 2024-11-26 23:15:14 +01:00
Johannes Schmelz
1715926c1c Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-26 23:01:59 +01:00
Johannes Schmelz
c8b69efca2 added correct colors in LobbyMenu 2024-11-26 23:01:55 +01:00
Yvonne Schmidt
7f6011720c lobbyMenu ready button toggles to grey 2024-11-26 22:30:13 +01:00
Yvonne Schmidt
bdc5f0269f fixed cancel button position 2024-11-26 22:27:55 +01:00
Yvonne Schmidt
a6054e825e fixed trade display 2024-11-26 22:24:03 +01:00
Johannes Schmelz
156e76fe0a cleanup 2024-11-26 21:31:21 +01:00
Johannes Schmelz
89587a4c78 set default value for drop down selection 2024-11-26 21:28:41 +01:00
Johannes Schmelz
29cc73e83b automaticyally set player name as 'Spieler'+ id+1 2024-11-26 20:58:57 +01:00
Johannes Schmelz
e56cdb1dcb Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-26 20:00:54 +01:00
Johannes Schmelz
9107a08011 dynamically set players in ChoosePatner 2024-11-26 20:00:50 +01:00
Yvonne Schmidt
0242587a5f added groundwork for selection listeners 2024-11-26 19:54:02 +01:00
Yvonne Schmidt
3ce27023c2 Merge remote-tracking branch 'origin/gui' into gui 2024-11-26 19:42:01 +01:00
Johannes Schmelz
174958c6b1 can now dynamically update toolbar view 2024-11-26 18:50:24 +01:00
Johannes Schmelz
c71e8b1e8e removed hostplayer as hostplayer always has id 0 2024-11-26 18:48:13 +01:00
Yvonne Schmidt
ada067a2a0 added and centered buttons 2024-11-26 18:25:23 +01:00
Johannes Schmelz
f4c4f6bc93 cleanup 2024-11-26 17:53:49 +01:00
Simon Wilkening
6eeb6fd209 Properties_de übersetzt 2024-11-26 15:29:45 +01:00
Simon Wilkening
efba3c496a Deckhelper korrigiert, Properties angepasst 2024-11-26 15:15:29 +01:00
Johannes Schmelz
27a0ab52e6 dice button now works and update dice images accordingly 2024-11-26 14:59:48 +01:00
Yvonne Schmidt
d6ce859fcd ChoosePartner accept-button opens TradeMenu 2024-11-26 01:12:29 +01:00
Yvonne Schmidt
e5f69c9536 Merge remote-tracking branch 'origin/gui' into gui
# Conflicts:
#	Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/ChoosePartner.java
2024-11-26 01:08:59 +01:00
Yvonne Schmidt
d8a2225038 added framework for TradeMenu 2024-11-26 01:07:59 +01:00
Johannes Schmelz
7b91a679f5 abbrechen button in chossePatner 2024-11-26 00:57:22 +01:00
Yvonne Schmidt
840658b590 fixed background location again 2024-11-26 00:34:49 +01:00
Yvonne Schmidt
c5e7ef855e fixed background location 2024-11-26 00:25:31 +01:00
Yvonne Schmidt
170227c97f fixed header in ChoosePartner menu 2024-11-26 00:21:13 +01:00
Johannes Schmelz
379803278b Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-26 00:11:42 +01:00
Johannes Schmelz
3956d8efa7 show all playe stats in toolbar 2024-11-26 00:11:37 +01:00
Yvonne Schmidt
269aceaf1a added ChoosePartner menu 2024-11-26 00:11:01 +01:00
Yvonne Schmidt
41127565fc Merge remote-tracking branch 'origin/gui' into gui 2024-11-26 00:10:52 +01:00
Johannes Schmelz
0e405d2f90 send PlayerHandler in GameStart 2024-11-25 22:11:35 +01:00
Yvonne Schmidt
f67810b288 fixed toolbar buttons 2024-11-25 21:29:54 +01:00
Johannes Schmelz
4095d9e79d fixed buyCard color and button function 2024-11-25 21:29:00 +01:00
Johannes Schmelz
547a4c2353 cleanup toolbar 2024-11-25 21:14:38 +01:00
Johannes Schmelz
9120e4d53c show test world when GameStart message is recieved 2024-11-25 17:50:54 +01:00
Johannes Schmelz
1a62b76104 corrected map size 2024-11-25 16:28:50 +01:00
Johannes Schmelz
cc7f277bef fixed b button 2024-11-25 15:05:02 +01:00
Johannes Schmelz
274df8dfd1 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-25 06:50:05 +01:00
Johannes Schmelz
2e256f4ff5 Merge branch 'gui' into 'main'
Gui v1.0

See merge request progproj/gruppen-ht24/Gruppe-02!16
2024-11-25 05:33:36 +00:00
Johannes Schmelz
d10111d2ab Gui v1.0 2024-11-25 05:33:36 +00:00
Johannes Schmelz
0c2b266f5e Merge branch 'main' into 'gui'
# Conflicts:
#   Projekte/battleship/client/src/main/java/pp/battleship/client/Menu.java
#   Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy
#   Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/Player.java
2024-11-25 05:33:21 +00:00
Simon Wilkening
16b4dbae18 Deckhelper korrigiert 2024-11-25 06:30:04 +01:00
Johannes Schmelz
88409dcc99 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-25 05:42:49 +01:00
Johannes Schmelz
5cacff39b7 refactor typo 2024-11-25 05:42:45 +01:00
Yvonne Schmidt
093723a9d0 added outline for ChoosePartner Menu 2024-11-25 05:40:49 +01:00
Johannes Schmelz
f67ce6be44 Merge branch 'Testhandbuch' into 'main'
newest version of tests

See merge request progproj/gruppen-ht24/Gruppe-02!15
2024-11-25 04:34:06 +00:00
Johannes Schmelz
1be29b8b7a newest version of tests 2024-11-25 04:34:06 +00:00
Johannes Schmelz
dfdbcdc9f3 board visible again 2024-11-25 05:16:24 +01:00
Johannes Schmelz
bd725e2dc4 refactor 2024-11-25 04:54:35 +01:00
Johannes Schmelz
dd9d9144dd Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-25 04:52:56 +01:00
Johannes Schmelz
1a429e4bb6 fixed settings in toolbar 2024-11-25 04:52:53 +01:00
Yvonne Schmidt
ad6fb5e926 added dice containers 2024-11-25 04:52:34 +01:00
Johannes Schmelz
72cb7049ba remove demo cube 2024-11-25 04:19:13 +01:00
Johannes Schmelz
2e42f3afac added testing shortcuts 2024-11-25 04:09:48 +01:00
Yvonne Schmidt
8474c9f5bc fixed EventCard sizing 2024-11-25 03:56:07 +01:00
Johannes Schmelz
b7ed03f7e8 resolve merge conflicts 2024-11-25 03:55:06 +01:00
Johannes Schmelz
a44b6b5e4c Merge branch 'connect' into 'gui'
Client connect to server

See merge request progproj/gruppen-ht24/Gruppe-02!14
2024-11-25 02:46:03 +00:00
Johannes Schmelz
5268f75e17 Client connect to server 2024-11-25 02:46:03 +00:00
156 changed files with 10391 additions and 3080 deletions

View File

@@ -18,10 +18,11 @@ import com.simsilica.lemur.style.ElementId;
import static pp.battleship.Resources.lookup;
import pp.battleship.client.gui.GameMusic;
import pp.battleship.client.gui.VolumeSlider;
import pp.dialog.Dialog;
import pp.dialog.StateCheckboxModel;
import pp.dialog.TextInputDialog;
import pp.battleship.client.gui.VolumeSlider;
import static pp.util.PreferencesUtils.getPreferences;
/**

View File

@@ -1,6 +1,7 @@
package pp.battleship.client.gui;
import com.simsilica.lemur.Slider;
/**
* The VolumeSlider class represents the Volume Slider in the Menu.
* It extends the Slider class and provides functionalities for setting the music volume,

View File

@@ -21,9 +21,11 @@ def sliderColor = color(0.6, 0.8, 0.8, 1)
def sliderBgColor = color(0.5, 0.75, 0.75, 1)
def gradientColor = color(0.5, 0.75, 0.85, 0.5)
def tabbuttonEnabledColor = color(0.4, 0.45, 0.5, 1)
def solidWhiteBackground = new QuadBackgroundComponent(color(1, 1, 1, 1)) // Solid white
def greyBackground = color(0.8, 0.8, 0.8, 1) // Grey background color
def redBorderColor = color(1, 0, 0, 1) // Red border color
def solidWhiteBackground = new QuadBackgroundComponent(new ColorRGBA(1, 1, 1, 1))
def greyBackground = new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 1.0f));
def lightGreyBackground = new QuadBackgroundComponent(new ColorRGBA(0.4f, 0.4f, 0.4f, 1.0f));
def lightGrey = color(0.6, 0.6, 0.6, 1.0)
@@ -62,6 +64,16 @@ selector("label-Bold", "pp") {
textHAlignment = HAlignment.Center
textVAlignment = VAlignment.Center
}
selector("label-toolbar", "pp") {
insets = new Insets3f(2, 2, 2, 2)
font = font("Interface/Fonts/Metropolis/Metropolis-Bold-32.fnt")
fontSize = 30
color = new ColorRGBA(ColorRGBA.White)
textHAlignment = HAlignment.Center
textVAlignment = VAlignment.Center
}
selector("label-Text", "pp") {
insets = new Insets3f(2, 2, 2, 2)
@@ -69,6 +81,19 @@ selector("label-Text", "pp") {
color = buttonEnabledColor
}
selector("label-account", "pp") {
insets = new Insets3f(2, 2, 2, 2)
fontSize = 25
color = new ColorRGBA(ColorRGBA.White)
textHAlignment = HAlignment.Center
textVAlignment = VAlignment.Center
}
selector("card-label", "pp") {
insets = new Insets3f(2, 2, 2, 2)
color = ColorRGBA.Black
}
selector("header", "pp") {
font = font("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt")
insets = new Insets3f(2, 2, 2, 2)
@@ -246,10 +271,25 @@ selector("tab.button", "pp") {
buttonCommands = stdButtonCommands
}
selector("settings-title", "pp") {
fontSize = 48 // Set font size
def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Grey inner border
def innerBackground = new QuadBackgroundComponent(buttonBgColor) // White outer border background
background = outerBackground
fontSize = 40
insets = new Insets3f(3, 3, 3, 3)
textHAlignment = HAlignment.Center
textVAlignment = VAlignment.Center
}
selector("warning-title", "pp") {
def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Grey inner border
def innerBackground = new QuadBackgroundComponent(buttonBgColor) // White outer border background
font = font("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt")
background = outerBackground
fontSize = 40
insets = new Insets3f(3, 3, 3, 3)
textHAlignment = HAlignment.Center
textVAlignment = VAlignment.Center
}
selector("menu-button", "pp") {
fontSize = 40 // Set font size
@@ -285,3 +325,44 @@ selector("selector.item.label", "hover") {
background = new QuadBackgroundComponent(new ColorRGBA(0.2f, 0.6f, 1.0f, 0.9f)) // Highlighted background
}
def enabledCommandToolbar = new Command<Button>() {
void execute(Button source) {
if (source.isEnabled()){
source.setColor(ColorRGBA.White)
def orangeBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)); // Orange background
source.setBackground(orangeBackground);
} else{
source.setColor(ColorRGBA.White)
def grayBackground = new QuadBackgroundComponent(ColorRGBA.Gray); // Gray background
source.setBackground(grayBackground);
}
}
}
def stdButtonCommandsToolbar = [
(ButtonAction.Down) : [pressedCommand],
(ButtonAction.Up) : [pressedCommand],
(ButtonAction.Enabled) : [enabledCommandToolbar],
(ButtonAction.Disabled): [enabledCommandToolbar]
]
selector("button-toolbar", "pp") {
def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Orange border
def innerBackground = new QuadBackgroundComponent(buttonBgColor) // Inner button background
// Apply the outer border as the main background
background = outerBackground
// Use insets to create a margin/padding effect for the inner background
insets = new Insets3f(3, 3, 3, 3) // Adjust the border thickness
textHAlignment = HAlignment.Center
textVAlignment = VAlignment.Center
buttonCommands = stdButtonCommandsToolbar
}

View File

@@ -24,10 +24,10 @@ overlay.top.color=1, 1, 1, 1
settings.show=false
#
# Specifies the width of the application window in pixels.
settings.resolution.width=1920
settings.resolution.width=1200
#
# Specifies the height of the application window in pixels.
settings.resolution.height=1080
settings.resolution.height=800
#
# Determines whether the application runs in full-screen mode.
settings.full-screen=false

View File

@@ -0,0 +1,113 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client;
import java.lang.System.Logger;
import java.util.List;
import com.jme3.input.controls.ActionListener;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import pp.monopoly.client.gui.TestWorld;
import pp.monopoly.game.server.Player;
/**
* Represents the state responsible for managing the battle interface within the Battleship game.
* This state handles the display and interaction of the battle map, including the opponent's map.
* It manages GUI components, input events, and the layout of the interface when this state is enabled.
*/
public class GameAppState extends MonopolyAppState {
private static final Logger LOGGER = System.getLogger(MonopolyAppState.class.getName());
private static final float DEPTH = 0f;
private static final float GAP = 20f;
/**
* A listener for handling click events in the battle interface.
* When a click is detected, it triggers the corresponding actions on the opponent's map.
*/
private final ActionListener clickListener = (name, isPressed, tpf) -> click(isPressed);
/**
* The root node for all GUI components in the battle state.
*/
private final Node battleNode = new Node("Game"); //NON-NLS
/**
* A view representing the opponent's map in the GUI.
*/
private TestWorld testWorld;
/**
* Enables the battle state by initializing, laying out, and adding GUI components.
* Attaches the components to the GUI node and registers input listeners.
*/
@Override
protected void enableState() {
battleNode.detachAllChildren();
initializeGuiComponents();
layoutGuiComponents();
addGuiComponents();
getApp().getGuiNode().attachChild(battleNode);
}
/**
* Disables the battle state by removing GUI components and unregistering input listeners.
* Also handles cleanup of resources, such as the opponent's map view.
*/
@Override
protected void disableState() {
getApp().getGuiNode().detachChild(battleNode);
getApp().getInputManager().removeListener(clickListener);
}
/**
* Initializes the GUI components used in the battle state.
* Creates the opponent's map view and adds a grid overlay to it.
*/
private void initializeGuiComponents() {
// Initialisiere TestWorld mit Spielern
testWorld = new TestWorld(getApp());
testWorld.initializeScene();
}
/**
* Adds the initialized GUI components to the battle node.
* Currently, it attaches the opponent's map view to the node.
*/
private void addGuiComponents() {
}
/**
* Lays out the GUI components within the window, positioning them appropriately.
* The opponent's map view is positioned based on the window's dimensions and a specified gap.
*/
private void layoutGuiComponents() {
final AppSettings s = getApp().getContext().getSettings();
final float windowWidth = s.getWidth();
final float windowHeight = s.getHeight();
}
/**
* Handles click events in the battle interface. If the event indicates a click (not a release),
* it translates the cursor position to the model's coordinate system and triggers the game logic
* for interacting with the opponent's map.
*
* @param isPressed whether the mouse button is currently pressed (true) or released (false)
*/
private void click(boolean isPressed) {
}
@Override
public void update(float tpf) {
// testWorld.update(tpf);
super.update(tpf);
}
}

View File

@@ -34,7 +34,7 @@ public class GameMusic extends AbstractAppState{
return PREFERENCES.getBoolean(ENABLED_PREF, true);
}
/**
/**
* Checks if sound is enabled in the preferences.
*
* @return float to which the volume is set

View File

@@ -30,6 +30,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
private static final Logger LOGGER = System.getLogger(GameSound.class.getName());
private static final Preferences PREFERENCES = getPreferences(GameSound.class);
private static final String ENABLED_PREF = "enabled"; //NON-NLS
private static final String VOLUME_PREF = "volume"; //NON-NLS
private AudioNode passStartSound;
private AudioNode eventCardSound;
@@ -59,6 +60,15 @@ public class GameSound extends AbstractAppState implements GameEventListener {
setEnabled(!isEnabled());
}
/**
* Checks if sound is enabled in the preferences.
*
* @return float to which the volume is set
*/
public static float volumeInPreferences() {
return PREFERENCES.getFloat(VOLUME_PREF, 0.5f);
}
/**
* Sets the enabled state of this AppState.
* Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
@@ -92,7 +102,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
tradeAcceptedSound = loadSound(app, "Sound/Effects/tradeAccepted.ogg");
tradeRejectedSound = loadSound(app, "Sound/Effects/tradeRejected.ogg");
winnerSound = loadSound(app, "Sound/Effects/winner.ogg");
looserSound = loadSound(app, "Sound/Effects/looser.ogg");
looserSound = loadSound(app, "Sound/Effects/loser.ogg");
buttonSound = loadSound(app, "Sound/Effects/button.ogg");
}
@@ -193,21 +203,40 @@ public class GameSound extends AbstractAppState implements GameEventListener {
if (isEnabled() && buttonSound != null)
buttonSound.playInstance();
}
/**
* Sets the volume of the sounds
* @param vol the volume to which the sounds should be set
*/
public void setVolume(float vol){
passStartSound.setVolume(vol);
eventCardSound.setVolume(vol);
gulagSound.setVolume(vol);
diceRollSound.setVolume(vol);
moneyCollectSound.setVolume(vol);
moneyLostSound.setVolume(vol);
tradeAcceptedSound.setVolume(vol);
tradeRejectedSound.setVolume(vol);
winnerSound.setVolume(vol);
looserSound.setVolume(vol);
buttonSound.setVolume(vol);
PREFERENCES.putFloat(VOLUME_PREF, vol);
}
@Override
public void receivedEvent(SoundEvent event) {
switch (event.sound()) {
case PASS_START -> passStart();
case EVENT_CARD -> eventCard();
case GULAG -> eventCard();
case DICE_ROLL -> eventCard();
case MONEY_COLLECTED -> eventCard();
case MONEY_LOST -> eventCard();
case TRADE_ACCEPTED -> eventCard();
case TRADE_REJECTED -> eventCard();
case WINNER -> eventCard();
case LOSER -> eventCard();
case BUTTON -> eventCard();
case GULAG -> gulag();
case DICE_ROLL -> diceRoll();
case MONEY_COLLECTED -> moneyCollect();
case MONEY_LOST -> moneyLost();
case TRADE_ACCEPTED -> tradeAccepted();
case TRADE_REJECTED -> tradeRejected();
case WINNER -> winner();
case LOSER -> looser();
case BUTTON -> button();
}
}
}

View File

@@ -1,51 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client;
import java.util.prefs.Preferences;
import pp.dialog.Dialog;
import static pp.util.PreferencesUtils.getPreferences;
/**
* The Menu class represents the main menu in the Battleship game application.
* It extends the Dialog class and provides functionalities for loading, saving,
* returning to the game, and quitting the application.
*/
class Menu extends Dialog {
private static final Preferences PREFERENCES = getPreferences(Menu.class);
private static final String LAST_PATH = "last.file.path";
private final MonopolyApp app;
/**
* Constructs the Menu dialog for the Battleship application.
*
* @param app the BattleshipApp instance
*/
public Menu(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
}
/**
* Updates the state of the load and save buttons based on the game logic.
*/
@Override
public void update() {
}
/**
* As an escape action, this method closes the menu if it is the top dialog.
*/
@Override
public void escape() {
close();
}
}

View File

@@ -1,298 +1,493 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.LogManager;
import com.jme3.app.DebugKeysAppState;
import com.jme3.app.SimpleApplication;
import com.jme3.app.StatsAppState;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.system.AppSettings;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.style.BaseStyles;
import pp.dialog.Dialog;
import pp.dialog.DialogBuilder;
import pp.dialog.DialogManager;
import pp.graphics.Draw;
import pp.monopoly.client.gui.*;
import static pp.monopoly.Resources.lookup;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.client.gui.StartMenu;
import pp.monopoly.client.gui.TestWorld;
import pp.monopoly.client.gui.popups.*;
import pp.monopoly.game.client.ClientGameLogic;
import pp.monopoly.game.client.MonopolyClient;
import pp.monopoly.game.client.ServerConnection;
import pp.monopoly.model.card.DeckHelper; // TODO für den Import der Queue notwendig
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.notification.ClientStateEvent;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent;
import pp.monopoly.server.MonopolyServer;
import pp.monopoly.notification.Sound;
/**
* The main class for the Battleship client application.
* It manages the initialization, input setup, GUI setup, and game states for the client.
*/
public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener {
private BitmapText topText;
private final ServerConnection serverConnection;
private final ClientGameLogic logic;
private final MonopolyAppConfig config;
private final ActionListener escapeListener = (name, isPressed, tpf) -> handleEscape(isPressed);
private final DialogManager dialogManager = new DialogManager(this);
private final ExecutorService executor = Executors.newCachedThreadPool();
private final Draw draw;
private SettingsMenu settingsMenu;
private TestWorld testWorld;
private boolean isSettingsMenuOpen = false;
private boolean inputBlocked = false;
private MonopolyServer monopolyServer;
private NetworkSupport networkSupport;
private BoardManager boardManager = new BoardManager();
// TODO Temp später entfernen
private DeckHelper deckHelper = new DeckHelper(); //TODO für den Import der Queue notwendig
private EventCard eventCard;
private BuildingPropertyCard buildingProperty;
private FoodFieldCard foodField;
private GateFieldCard gateField;
private BuyCard buyCard;
private boolean isBuyCardPopupOpen = false;
private final ActionListener BListener = (name, isPressed, tpf) -> handleB(isPressed);
/**
* Logger for logging messages within the application.
*/
private static final Logger LOGGER = System.getLogger(MonopolyApp.class.getName());
/**
* Path to the styles script for GUI elements.
*/
private static final String STYLES_SCRIPT = "Interface/Lemur/pp-styles.groovy"; // NON-NLS
private static final String STYLES_SCRIPT = "Interface/Lemur/pp-styles.groovy"; //NON-NLS
/**
* Path to the font resource used in the GUI.
*/
private static final String FONT = "Interface/Fonts/Default.fnt"; // NON-NLS
private static final String FONT = "Interface/Fonts/Default.fnt"; //NON-NLS
/**
* Path to the client configuration file, if one exists.
*/
private static final File CONFIG_FILE = new File("client.properties");
/**
* Input mapping name for mouse clicks.
*/
public static final String CLICK = "CLICK";
/**
* Input mapping name for the Escape key.
*/
private static final String ESC = "ESC";
/**
* Manager for handling dialogs within the application.
*/
private final DialogManager dialogManager = new DialogManager(this);
/**
* The server connection instance, used for communicating with the game server.
*/
private final ServerConnection serverConnection;
/**
* Instance of the {@link Draw} class for rendering graphics.
*/
private Draw draw;
/**
* Text display at the top of the GUI for showing information to the user.
*/
private BitmapText topText;
/**
* Executor service for handling asynchronous tasks within the application.
*/
private ExecutorService executor;
/**
* Handler for managing the client's game logic.
*/
private final ClientGameLogic logic;
/**
* Configuration settings for the Battleship client application.
*/
private final MonopolyAppConfig config;
/**
* Listener for handling actions triggered by the Escape key.
*/
private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
//TODO temp for testing
private EventCardPopup eventCard;
private BuildingPropertyCard buildingProperty;
private FoodFieldCard foodField;
private GateFieldCard gateField;
private LooserPopUp looserpopup;
private Bankrupt bankrupt;
private TimeOut timeOut;
private SellHouse sellHouse;
private BuyHouse buyHouse;
private TakeMortage takeMortage;
private RepayMortage repayMortage;
private boolean isBuyCardPopupOpen = false;
private final ActionListener BListener = (name, isPressed, tpf) -> handleB(isPressed);
private TestWorld testWorld;
static {
// Configure logging
LogManager manager = LogManager.getLogManager();
try {
manager.readConfiguration(new FileInputStream("logging.properties"));
LOGGER.log(Level.INFO, "Successfully read logging properties"); //NON-NLS
}
catch (IOException e) {
LOGGER.log(Level.INFO, e.getMessage());
}
}
/**
* Starts the Battleship application.
*
* @param args Command-line arguments for launching the application.
*/
public static void main(String[] args) {
new MonopolyApp().start();
}
/**
* Constructs a new {@code MonopolyApp} instance.
* Initializes the configuration, server connection, and game logic listeners.
*/
public MonopolyApp() {
this.draw = new Draw(assetManager);
config = new MonopolyAppConfig();
networkSupport = new NetworkSupport(this); // Initialize NetworkSupport
serverConnection = networkSupport;
config.readFromIfExists(CONFIG_FILE);
serverConnection = makeServerConnection();
logic = new ClientGameLogic(serverConnection);
logic.addListener(this);
setShowSettings(config.getShowSettings());
setSettings(makeSettings());
}
@Override
public MonopolyAppConfig getConfig() {
return config;
/**
* Creates and configures application settings from the client configuration.
*
* @return A configured {@link AppSettings} object.
*/
private AppSettings makeSettings() {
final AppSettings settings = new AppSettings(true);
settings.setTitle(lookup("monopoly.name"));
settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight());
settings.setFullscreen(config.fullScreen());
settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer());
settings.setGammaCorrection(config.useGammaCorrection());
return settings;
}
/**
* Factory method for creating a server connection based on the current
* client configuration.
*
* @return A {@link ServerConnection} instance, which could be a real or mock server.
*/
private ServerConnection makeServerConnection() {
return new NetworkSupport(this);
}
/**
* Returns the dialog manager responsible for managing in-game dialogs.
*
* @return The {@link DialogManager} instance.
*/
public DialogManager getDialogManager() {
return dialogManager;
}
/**
* Returns the game logic handler for the client.
*
* @return The {@link ClientGameLogic} instance.
*/
@Override
public ClientGameLogic getGameLogic() {
return logic;
}
public BoardManager getBoardManager() {
return boardManager;
}
// TODO analoge Implementierung zum Boardmamager zum Testen der EventCardPopups
public DeckHelper getDeckHelper(){
return deckHelper;
}
public NetworkSupport getNetworkSupport() {
return networkSupport;
}
private AppSettings makeSettings() {
final AppSettings settings = new AppSettings(true);
settings.setTitle("Monopoly Game");
settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight());
settings.setFullscreen(config.fullScreen());
return settings;
/**
* Returns the current configuration settings for the Battleship client.
*
* @return The {@link BattleshipClientConfig} instance. //TODO Fehler im Kommentar
*/
@Override
public MonopolyAppConfig getConfig() {
return config;
}
/**
* Initializes the application.
* Sets up input mappings, GUI, game states, and connects to the server.
*/
@Override
public void simpleInitApp() {
GuiGlobals.initialize(this);
BaseStyles.loadStyleResources(STYLES_SCRIPT);
GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); // NON-NLS
BaseStyles.loadStyleResources("com/simsilica/lemur/style/base/glass-styles.groovy");
GuiGlobals.getInstance().getStyles();
final BitmapFont normalFont = assetManager.loadFont(FONT); // NON-NLS
setPauseOnLostFocus(false);
draw = new Draw(assetManager);
setupInput();
setupStates();
setupGui();
// Zeige das Startmenü
StartMenu.createStartMenu(this);
new StartMenu(this).open();
}
/**
* Sets up the graphical user interface (GUI) for the application.
*/
private void setupGui() {
BitmapFont normalFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
GuiGlobals.initialize(this);
BaseStyles.loadStyleResources(STYLES_SCRIPT);
BaseStyles.loadGlassStyle();
GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS
final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
topText = new BitmapText(normalFont);
topText.setLocalTranslation(10, settings.getHeight() - 10, 0);
final int height = context.getSettings().getHeight();
topText.setLocalTranslation(10f, height - 10f, 0f);
topText.setColor(config.getTopColor());
guiNode.attachChild(topText);
}
/**
* Configures input mappings and sets up listeners for user interactions.
*/
private void setupInput() {
inputManager.deleteMapping(INPUT_MAPPING_EXIT);
inputManager.setCursorVisible(true);
inputManager.addMapping("ESC", new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addListener(escapeListener, "ESC");
inputManager.setCursorVisible(false);
inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(escapeListener, ESC);
//TODO tmp for testing
inputManager.addMapping("B", new KeyTrigger(KeyInput.KEY_B));
inputManager.addListener(BListener, "B");
}
private void handleEscape(boolean isPressed) {
if (isPressed) {
if (settingsMenu != null && isSettingsMenuOpen) {
// Schließe das SettingsMenu
System.out.println("Schließe SettingsMenu...");
settingsMenu.close();
settingsMenu = null;
setSettingsMenuOpen(false);
} else {
// Öffne das SettingsMenu
System.out.println("Öffne SettingsMenu...");
settingsMenu = new SettingsMenu(this);
settingsMenu.open();
setSettingsMenuOpen(true);
}
}
inputManager.addMapping("T", new KeyTrigger(KeyInput.KEY_T));
}
//logik zum wechselnden erscheinen und verschwinden beim drücken von B //TODO süäter entfernen
private void handleB(boolean isPressed) {
if (isPressed) {
if (eventCard != null && isBuyCardPopupOpen) {
// Schließe das SettingsMenu
System.out.println("Schließe BuyCardPopup...");
eventCard.close();
eventCard = null;
setBuyCardPopupOpen(false);
} else {
// Öffne das SettingsMenu
System.out.println("Öffne BuyCardPopup...");
eventCard = new EventCard(this);
eventCard.open();
setBuyCardPopupOpen(true);
}
Dialog tmp = new GulagInfo(this, 3);
tmp.open();
}
}
private void blockInputs() {
if (!inputBlocked) {
System.out.println("Blockiere Eingaben...");
inputManager.setCursorVisible(true); // Cursor sichtbar machen
inputManager.clearMappings(); // Alle Mappings entfernen
inputBlocked = true;
/**
* Initializes and attaches the necessary application states for the game.
*/
private void setupStates() {
if (config.getShowStatistics()) {
final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
final StatsAppState stats = new StatsAppState(guiNode, normalFont);
stateManager.attach(stats);
}
flyCam.setEnabled(false);
stateManager.detach(stateManager.getState(StatsAppState.class));
stateManager.detach(stateManager.getState(DebugKeysAppState.class));
attachGameSound();
attachGameMusic();
stateManager.attach(new GameAppState());
}
public void unblockInputs() {
if (inputBlocked) {
System.out.println("Aktiviere Eingaben...");
setupInput(); // Standard-Eingaben neu registrieren
inputBlocked = false;
}
/**
* Attaches the game sound state and sets its initial enabled state.
*/
private void attachGameSound() {
final GameSound gameSound = new GameSound();
logic.addListener(gameSound);
gameSound.setEnabled(GameSound.enabledInPreferences());
stateManager.attach(gameSound);
}
public void setInfoText(String text) {
topText.setText(text);
/**
* Attaches the background music state and sets its initial enabled state.
*/
private void attachGameMusic() {
final GameMusic gameSound = new GameMusic();
gameSound.setEnabled(GameMusic.enabledInPreferences());
stateManager.attach(gameSound);
}
/**
* Updates the application state every frame.
* This method is called once per frame during the game loop.
*
* @param tpf Time per frame in seconds.
*/
@Override
public void receivedEvent(InfoTextEvent event) {
setInfoText(event.key());
public void simpleUpdate(float tpf) {
super.simpleUpdate(tpf);
dialogManager.update(tpf);
logic.update(tpf);
stateManager.update(tpf);
// //TODO testing replace later
// if (testWorld != null) {
// testWorld.update(tpf);
// }
}
@Override
public void stop(boolean waitFor) {
if (executor != null) executor.shutdownNow();
serverConnection.disconnect();
super.stop(waitFor);
}
public DialogManager getDialogManager() {
return dialogManager;
/**
* Handles the Escape key action to either close the top dialog or show the main menu.
*
* @param isPressed Indicates whether the Escape key is pressed.
*/
public void escape(boolean isPressed) {
if (!isPressed) return;
if (dialogManager.showsDialog())
dialogManager.escape();
else
new SettingsMenu(this).open();
}
/**
* Returns the {@link Draw} instance used for rendering graphical elements in the game.
*
* @return The {@link Draw} instance.
*/
public Draw getDraw() {
return draw;
}
public ExecutorService getExecutor() {
return executor;
}
public void closeApp() {
stop();
}
public void errorDialog(String errorMessage) {
DialogBuilder.simple(dialogManager)
.setTitle("Fehler")
.setText(errorMessage)
.setOkButton("OK")
.build()
.open();
}
public void setSettingsMenuOpen(boolean isOpen) {
this.isSettingsMenuOpen = isOpen;
}
// TODO später entfernen
public void setBuyCardPopupOpen(boolean isOpen) {
this.isBuyCardPopupOpen = isOpen;
}
@Override
public void simpleUpdate(float tpf) {
if (testWorld != null) {
testWorld.update(tpf); // Aktualisiere die Kamera in der TestWorld
}
}
public void startTestWorld() {
guiNode.detachAllChildren(); // Entferne GUI
testWorld = new TestWorld(this); // Erstelle eine Instanz von TestWorld
testWorld.initializeScene(); // Initialisiere die Szene
}
// TODO später entfernen
public void startBuyCard() {
}
public void returnToMenu() {
guiNode.detachAllChildren(); // Entferne die GUI
StartMenu.createStartMenu(this); // Zeige das Startmenü erneut
/**
* Tries to connect
*/
public void connect() {
serverConnection.connect();
}
/**
* Startet den Server in einem neuen Thread.
* Handles a request to close the application.
* If the request is initiated by pressing ESC, this parameter is true.
*
* @param esc If true, the request is due to the ESC key being pressed.
*/
public void startServer() {
new Thread(() -> {
try {
MonopolyServer.main(new String[0]); // Startet den MonopolyServer
} catch (Exception e) {
errorDialog("Fehler: Server konnte nicht gestartet werden.");
}
}).start();
@Override
public void requestClose(boolean esc) { /* do nothing */ }
/**
* Closes the application, displaying a confirmation dialog if the client is connected to a server.
*/
public void closeApp() {
if (serverConnection.isConnected())
confirmDialog(lookup("confirm.leaving"), this::close);
else
close();
}
public MonopolyServer getMonopolyServer() {
return monopolyServer;
/**
* Closes the application, disconnecting from the server and stopping the application.
*/
private void close() {
serverConnection.disconnect();
stop();
}
public ServerConnection getServerConnection() {
return serverConnection;
/**
* Updates the informational text displayed in the GUI.
*
* @param text The information text to display.
*/
public void setInfoText(String text) {
LOGGER.log(Level.DEBUG, "setInfoText {0}", text); //NON-NLS
topText.setText(text);
}
/**
* Updates the informational text in the GUI based on the key received in an {@link InfoTextEvent}.
*
* @param event The {@link InfoTextEvent} containing the key for the text to display.
*/
@Override
public void receivedEvent(InfoTextEvent event) {
LOGGER.log(Level.DEBUG, "received info text {0}", event.key()); //NON-NLS
setInfoText(lookup(event.key()));
}
/**
* Handles client state events to update the game states accordingly.
*
* @param event The {@link ClientStateEvent} representing the state change.
*/
@Override
public void receivedEvent(ClientStateEvent event) {
stateManager.getState(GameAppState.class).setEnabled(true);
}
/**
* Returns the executor service used for handling multithreaded tasks.
*
* @return The {@link ExecutorService} instance.
*/
public ExecutorService getExecutor() {
if (executor == null)
executor = Executors.newCachedThreadPool();
return executor;
}
/**
* Stops the application, shutting down the executor service and halting execution.
*
* @param waitFor If true, waits for the application to stop before returning.
*/
@Override
public void stop(boolean waitFor) {
if (executor != null) executor.shutdownNow();
super.stop(waitFor);
}
/**
* Displays a confirmation dialog with a specified question and action for the "Yes" button.
*
* @param question The question to display in the dialog.
* @param yesAction The action to perform if "Yes" is selected.
*/
public void confirmDialog(String question, Runnable yesAction) {
DialogBuilder.simple(dialogManager)
.setTitle(lookup("dialog.question"))
.setText(question)
.setOkButton(lookup("button.yes"), d -> {
getGameLogic().playSound(Sound.BUTTON); // Play sound
yesAction.run(); // Execute the original yesAction
})
.setNoButton(lookup("button.no"), d -> getGameLogic().playSound(Sound.BUTTON))
.build()
.open();
}
/**
* Displays an error dialog with the specified error message.
*
* @param errorMessage The error message to display in the dialog.
*/
public void errorDialog(String errorMessage) {
DialogBuilder.simple(dialogManager)
.setTitle(lookup("dialog.error"))
.setText(errorMessage)
.setOkButton(lookup("button.ok"), d -> getGameLogic().playSound(Sound.BUTTON))
.build()
.open();
}
public void disconnect() {
serverConnection.disconnect();
}
public int getId() {
if (serverConnection != null && serverConnection instanceof NetworkSupport) return ((NetworkSupport) serverConnection).getId();
return 0;
}
}

View File

@@ -1,146 +0,0 @@
package pp.monopoly.client;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.TextField;
import pp.dialog.Dialog;
import pp.dialog.DialogBuilder;
import pp.dialog.SimpleDialog;
/**
* Represents a dialog for setting up a network connection in the Monopoly game.
* Allows users to specify the host and port for connecting to a game server.
*/
class NetworkDialog extends SimpleDialog {
private static final Logger LOGGER = System.getLogger(NetworkDialog.class.getName());
private static final String LOCALHOST = "localhost";
private static final String DEFAULT_PORT = "42069";
private final NetworkSupport network;
private final TextField host = new TextField(LOCALHOST);
private final TextField port = new TextField(DEFAULT_PORT);
private String hostname;
private int portNumber;
private Future<Object> connectionFuture;
private Dialog progressDialog;
/**
* Constructs a new NetworkDialog.
*
* @param network The NetworkSupport instance to be used for network operations.
*/
NetworkDialog(NetworkSupport network) {
super(network.getApp().getDialogManager());
this.network = network;
initializeDialog();
}
/**
* Initializes the dialog with input fields and connection buttons.
*/
private void initializeDialog() {
final MonopolyApp app = network.getApp();
Container inputContainer = new Container();
// Titel und Eingabefelder für Host und Port
inputContainer.addChild(new Label("Server-Adresse"));
inputContainer.addChild(host);
inputContainer.addChild(new Label("Port"));
inputContainer.addChild(port);
Button connectButton = inputContainer.addChild(new Button("Verbinden"));
connectButton.addClickCommands(source -> connect());
Button cancelButton = inputContainer.addChild(new Button("Abbrechen"));
cancelButton.addClickCommands(source -> app.closeApp());
app.getGuiNode().attachChild(inputContainer);
}
/**
* Initiates the connection attempt based on the entered host and port.
*/
private void connect() {
LOGGER.log(Level.INFO, "Connecting to host={0}, port={1}", host, port);
try {
hostname = host.getText().trim().isEmpty() ? LOCALHOST : host.getText();
portNumber = Integer.parseInt(port.getText());
openProgressDialog();
connectionFuture = network.getApp().getExecutor().submit(this::initNetwork);
} catch (NumberFormatException e) {
network.getApp().errorDialog("Port muss eine Zahl sein.");
}
}
/**
* Opens a progress dialog while connecting.
*/
private void openProgressDialog() {
progressDialog = DialogBuilder.simple(network.getApp().getDialogManager())
.setText("Verbinde zum Server...")
.build();
progressDialog.open();
}
/**
* Attempts to initialize the network connection.
*
* @throws RuntimeException If an error occurs when creating the client.
*/
private Object initNetwork() {
try {
network.initNetwork(hostname, portNumber);
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Updates the connection status and handles completion or failure.
*/
@Override
public void update(float delta) {
if (connectionFuture != null && connectionFuture.isDone()) {
try {
connectionFuture.get();
onSuccess();
} catch (ExecutionException e) {
onFailure(e.getCause());
} catch (InterruptedException e) {
LOGGER.log(Level.WARNING, "Connection interrupted.", e);
Thread.currentThread().interrupt();
}
}
}
/**
* Handles a successful connection to the game server.
*/
private void onSuccess() {
connectionFuture = null;
progressDialog.close();
this.close();
network.getApp().setInfoText("Warte auf einen Gegner...");
}
/**
* Handles a failed connection attempt.
*
* @param e The cause of the failure.
*/
private void onFailure(Throwable e) {
connectionFuture = null;
progressDialog.close();
network.getApp().errorDialog("Verbindung zum Server fehlgeschlagen.");
network.getApp().setInfoText(e.getLocalizedMessage());
}
}

View File

@@ -1,8 +1,11 @@
package pp.monopoly.client;
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
package pp.monopoly.client;
import com.jme3.network.Client;
import com.jme3.network.ClientStateListener;
@@ -10,10 +13,17 @@ import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import pp.monopoly.client.gui.CreateGameMenu;
import pp.monopoly.game.client.ServerConnection;
import pp.monopoly.message.client.ClientMessage;
import pp.monopoly.message.server.ServerMessage;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import static pp.monopoly.Resources.lookup;
/**
* Manages the network connection for the Monopoly application.
* Handles connecting to and disconnecting from the server, and sending messages.
@@ -24,7 +34,7 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
private Client client;
/**
* Constructs a NetworkSupport instance for the Monopoly application.
* Constructs a NetworkSupport instance for the given Monopoly application.
*
* @param app The Monopoly application instance.
*/
@@ -32,20 +42,25 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
this.app = app;
}
/**
* Return the client connections Id
*
* @return the client id
*/
public int getId() {
if (client == null) return 0;
return client.getId();
}
/**
* Returns the Monopoly application instance.
*
* @return Monopoly application instance
*/
MonopolyApp getApp() {
public MonopolyApp getApp() {
return app;
}
public int getId() {
if (client == null) return 0;
return client.getId();
}
/**
* Checks if there is a connection to the game server.
*
@@ -62,9 +77,8 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/
@Override
public void connect() {
if (client == null) {
new NetworkDialog(this).open();
}
if (client == null)
new CreateGameMenu(this).open();
}
/**
@@ -75,7 +89,7 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
if (client == null) return;
client.close();
client = null;
LOGGER.log(Level.INFO, "Client connection closed.");
LOGGER.log(Level.INFO, "client closed"); //NON-NLS
}
/**
@@ -86,9 +100,8 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
* @throws IOException If an I/O error occurs when creating the client.
*/
public void initNetwork(String host, int port) throws IOException {
if (client != null) {
throw new IllegalStateException("Already connected to the game server.");
}
if (client != null)
throw new IllegalStateException("trying to join a game again");
client = Network.connectToServer(host, port);
client.start();
client.addMessageListener(this);
@@ -103,10 +116,9 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/
@Override
public void messageReceived(Client client, Message message) {
LOGGER.log(Level.INFO, "Message received from server: {0}", message);
if (message instanceof ServerMessage serverMessage) {
LOGGER.log(Level.INFO, "message received from server: {0}", message); //NON-NLS
if (message instanceof ServerMessage serverMessage)
app.enqueue(() -> serverMessage.accept(app.getGameLogic()));
}
}
/**
@@ -116,7 +128,7 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/
@Override
public void clientConnected(Client client) {
LOGGER.log(Level.INFO, "Successfully connected to server: {0}", client);
LOGGER.log(Level.INFO, "Client connected: {0}", client); //NON-NLS
}
/**
@@ -127,9 +139,13 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/
@Override
public void clientDisconnected(Client client, DisconnectInfo disconnectInfo) {
LOGGER.log(Level.INFO, "Disconnected from server: {0}", disconnectInfo);
LOGGER.log(Level.INFO, "Client {0} disconnected: {1}", client, disconnectInfo); //NON-NLS
if (this.client != client)
throw new IllegalArgumentException("parameter value must be client");
LOGGER.log(Level.INFO, "client still connected: {0}", client.isConnected()); //NON-NLS
this.client = null;
app.enqueue(() -> app.setInfoText("Verbindung zum Server verloren."));
disconnect();
app.enqueue(() -> app.setInfoText(lookup("lost.connection.to.server")));
}
/**
@@ -139,47 +155,10 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/
@Override
public void send(ClientMessage message) {
LOGGER.log(Level.INFO, "Sending message to server: {0}", message);
if (client == null) {
app.errorDialog("Verbindung zum Server verloren.");
} else {
LOGGER.log(Level.INFO, "sending {0}", message); //NON-NLS
if (client == null)
app.errorDialog(lookup("lost.connection.to.server"));
else
client.send(message);
}
}
public void startServerAndJoin() {
new Thread(() -> {
// Server starten
app.startServer();
// Warten, bis der Server tatsächlich betriebsbereit ist
int retries = 5;
while (retries > 0) {
try {
initNetwork("localhost", app.getConfig().getPort());
app.enqueue(() -> app.setInfoText("Erfolgreich verbunden!"));
return; // Verbindung erfolgreich
} catch (IOException e) {
retries--;
try {
Thread.sleep(1000); // Eine Sekunde warten und erneut versuchen
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break; // Abbrechen, wenn der Thread unterbrochen wird
}
}
}
// Wenn alle Versuche fehlschlagen
app.enqueue(() -> app.errorDialog("Fehler: Verbindung zum Server fehlgeschlagen."));
}).start();
}
public void connectToServer(String host, int port) {
try {
initNetwork(host, port); // Verbindung initialisieren
app.setInfoText("Erfolgreich mit Server verbunden!");
} catch (IOException e) {
app.errorDialog("Fehler: Verbindung zum Server fehlgeschlagen.");
}
}
}
}

View File

@@ -0,0 +1,182 @@
package pp.monopoly.client.gui;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.popups.BuyHouse;
import pp.monopoly.client.gui.popups.RepayMortage;
import pp.monopoly.client.gui.popups.SellHouse;
import pp.monopoly.client.gui.popups.TakeMortage;
import pp.monopoly.notification.Sound;
public class BuildingAdminMenu extends Dialog {
private final MonopolyApp app;
private final Container mainContainer;
private Geometry background;
private final Button backButton = new Button("Zurück");
private final Button buildButton = new Button("Bauen");
private final Button demolishButton = new Button("Abriss");
private final Button takeMortgageButton = new Button("Hypothek aufnehmen");
private final Button payMortgageButton = new Button("Hypothek bezahlen");
private final Button overviewButton = new Button("Übersicht");
public BuildingAdminMenu(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Background Image
addBackgroundImage();
// Main container for the UI components
mainContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
mainContainer.setPreferredSize(new Vector3f(800, 600, 0));
mainContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(1, 1, 1, 0.7f))); // Translucent white background
// Add header
mainContainer.addChild(createHeaderContainer());
// Add content
mainContainer.addChild(createContent());
// Attach main container to GUI node
app.getGuiNode().attachChild(mainContainer);
mainContainer.setLocalTranslation(
(app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + mainContainer.getPreferredSize().y) / 2,
7
);
}
/**
* Creates the header container.
*
* @return The header container.
*/
private Container createHeaderContainer() {
Container headerContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
headerContainer.setPreferredSize(new Vector3f(800, 100, 0));
Label headerLabel = headerContainer.addChild(new Label("Grundstücke Verwalten", new ElementId("header")));
headerLabel.setFontSize(45);
headerLabel.setInsets(new Insets3f(10, 10, 10, 10));
return headerContainer;
}
/**
* Creates the main content container with columns for Overview, Build, and Mortgage.
*
* @return The content container.
*/
private Container createContent() {
Container contentContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
contentContainer.setPreferredSize(new Vector3f(800, 500, 0));
// Overview Column
Container overviewColumn = new Container(new SpringGridLayout(Axis.Y, Axis.X));
overviewColumn.addChild(new Label("Übersicht:")).setFontSize(30);
//Building Overview Button
overviewButton.setPreferredSize(new Vector3f(200, 50, 0));
overviewButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
new PropertyOverviewMenu(app).open();
}));
overviewColumn.addChild(overviewButton);
// Back Button
backButton.setPreferredSize(new Vector3f(200, 50, 0));
backButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
overviewColumn.addChild(backButton);
contentContainer.addChild(overviewColumn);
// Build Column
Container buildColumn = new Container(new SpringGridLayout(Axis.Y, Axis.X));
buildColumn.addChild(new Label("Bauen:")).setFontSize(30);
// Build Houses Button
buildButton.setPreferredSize(new Vector3f(200, 50, 0));
buildButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
new BuyHouse(app).open();
}));
buildColumn.addChild(buildButton);
//Demolish Houses Button
demolishButton.setPreferredSize(new Vector3f(200, 50, 0));
demolishButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
new SellHouse(app).open();
}));
buildColumn.addChild(demolishButton);
contentContainer.addChild(buildColumn);
// Mortgage Column
Container mortgageColumn = new Container(new SpringGridLayout(Axis.Y, Axis.X));
mortgageColumn.addChild(new Label("Hypotheken:")).setFontSize(30);
// Lend Mortgage Button
takeMortgageButton.setPreferredSize(new Vector3f(200, 50, 0));
takeMortgageButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
new TakeMortage(app).open();
}));
mortgageColumn.addChild(takeMortgageButton);
//Repay Mortgage Button
payMortgageButton.setPreferredSize(new Vector3f(200, 50, 0));
payMortgageButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
new RepayMortage(app).open();
}));
mortgageColumn.addChild(payMortgageButton);
contentContainer.addChild(mortgageColumn);
return contentContainer;
}
/**
* Adds a background image to the dialog.
*/
private void addBackgroundImage() {
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
background = new Geometry("Background", quad);
Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
backgroundMaterial.setTexture("ColorMap", backgroundImage);
background.setMaterial(backgroundMaterial);
background.setLocalTranslation(0, 0, 6); // Position behind other GUI elements
app.getGuiNode().attachChild(background);
}
@Override
public void close() {
app.getGuiNode().detachChild(mainContainer);
app.getGuiNode().detachChild(background);
super.close();
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
@Override
public void update(float delta) {
// Periodic updates if necessary
}
}

View File

@@ -1,6 +1,5 @@
package pp.monopoly.client.gui;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
@@ -9,11 +8,7 @@ import com.jme3.renderer.Camera;
*/
public class CameraController {
private final Camera camera;
private final Vector3f center; // Fokuspunkt der Kamera
private final float radius; // Radius der Kreisbewegung
private final float height; // Höhe der Kamera über dem Spielfeld
private final float speed; // Geschwindigkeit der Kamerabewegung
private float angle; // Aktueller Winkel in der Kreisbewegung
private final float height = 25; // Höhe der Kamera über dem Spielfeld // Aktueller Winkel in der Kreisbewegung
/**
* Konstruktor für den CameraController.
@@ -24,13 +19,10 @@ public class CameraController {
* @param height Die Höhe der Kamera über dem Fokuspunkt
* @param speed Die Geschwindigkeit der Kamerabewegung
*/
public CameraController(Camera camera, Vector3f center, float radius, float height, float speed) {
public CameraController(Camera camera) {
this.camera = camera;
this.center = center;
this.radius = radius;
this.height = height;
this.speed = speed;
this.angle = 0; // Starte bei Winkel 0
setPosition(0);
camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
}
/**
@@ -39,7 +31,7 @@ public class CameraController {
* @param tpf Zeit pro Frame
*/
public void update(float tpf) {
camera.lookAt(center, Vector3f.UNIT_Y);
camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
}
public void setPosition(int fieldID) {

View File

@@ -0,0 +1,224 @@
package pp.monopoly.client.gui;
import java.util.Set;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList;
import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.ViewAssetsRequest;
import pp.monopoly.model.TradeHandler;
import pp.monopoly.notification.Sound;
public class ChoosePartner extends Dialog {
private final MonopolyApp app;
private Selector<String> playerSelector;
private final Button cancelButton = new Button("Abbrechen");
private final Button confirmButton = new Button("Bestätigen");
private final Container mainContainer;
private Container lowerLeftMenu;
private Container lowerRightMenu;
private Geometry background;
private TradeHandler tradeHandler;
private VersionedReference<Set<Integer>> selectionRef; // Reference to track selector changes
private String lastSelected = ""; // To keep track of the last selected value
QuadBackgroundComponent translucentWhiteBackground =
new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
/**
* Constructs the ChoosePartner dialog.
*
* @param app The Monopoly application instance.
*/
public ChoosePartner(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
tradeHandler = new TradeHandler(app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()));
app.getGameLogic().send(new ViewAssetsRequest());
// Background Image
addBackgroundImage();
// Main container for the UI components
mainContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
mainContainer.setPreferredSize(new Vector3f(1000, 600, 0));
mainContainer.setBackground(translucentWhiteBackground);
// Add title with background
Label headerLabel = mainContainer.addChild(new Label("Wähle deinen Handelspartner:", new ElementId("label-Bold")));
headerLabel.setFontSize(40);
headerLabel.setBackground(new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f)));
// Dropdown for player selection
mainContainer.addChild(createDropdown());
// Add buttons
mainContainer.addChild(createButtonContainer());
// Attach main container to GUI node
app.getGuiNode().attachChild(mainContainer);
mainContainer.setLocalTranslation(
(app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + mainContainer.getPreferredSize().y) / 2,
4
);
// Initialize selection reference for tracking changes
selectionRef = playerSelector.getSelectionModel().createReference();
}
/**
* Creates the dropdown menu for selecting a partner.
*
* @return The dropdown container.
*/
private Container createDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
dropdownContainer.setPreferredSize(new Vector3f(100, 80, 0));
dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(ColorRGBA.Black)));
VersionedList<String> playerOptions = new VersionedList<>();
for (Player player : app.getGameLogic().getPlayerHandler().getPlayers()) {
if (player.getId() != app.getId()) {
playerOptions.add(player.getName() + " (ID: " + player.getId() + ")");
}
}
playerSelector = new Selector<>(playerOptions, "glass");
dropdownContainer.addChild(playerSelector);
Vector3f dimens = dropdownContainer.getPreferredSize();
Vector3f dimens2 = playerSelector.getPopupContainer().getPreferredSize();
dimens2.setX(dimens.getX());
playerSelector.getPopupContainer().setPreferredSize(new Vector3f(200, 200, 3));
playerSelector.setLocalTranslation(0, 0, 5);
// Set initial selection
if (!playerOptions.isEmpty()) {
onDropdownSelectionChanged(playerOptions.get(0));
}
return dropdownContainer;
}
/**
* Creates the button container with cancel and confirm buttons.
*
* @return The button container.
*/
private Container createButtonContainer() {
Container buttonContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
buttonContainer.setBackground(translucentWhiteBackground);
// "Abbrechen" button
lowerLeftMenu = new Container();
cancelButton.setPreferredSize(new Vector3f(200, 60, 0));
cancelButton.setFontSize(30);
cancelButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
lowerLeftMenu.addChild(cancelButton);
// Position the container near the bottom-left corner
lowerLeftMenu.setLocalTranslation(new Vector3f(120, 170, 5)); // Adjust X and Y to align with the bottom-left corner
app.getGuiNode().attachChild(lowerLeftMenu);
// "Bestätigen" button
lowerRightMenu = new Container();
confirmButton.setPreferredSize(new Vector3f(200, 60, 0));
confirmButton.setFontSize(30);
confirmButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
new TradeMenu(app, tradeHandler).open();
}));
lowerRightMenu.addChild(confirmButton);
// Position the container near the bottom-right corner
lowerRightMenu.setLocalTranslation(new Vector3f(app.getCamera().getWidth() - 320, 170, 5)); // X: 220px from the right, Y: 50px above the bottom
app.getGuiNode().attachChild(lowerRightMenu);
return buttonContainer;
}
/**
* Adds a background image to the dialog.
*/
private void addBackgroundImage() {
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
background = new Geometry("Background", quad);
Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
backgroundMaterial.setTexture("ColorMap", backgroundImage);
background.setMaterial(backgroundMaterial);
background.setLocalTranslation(0, 0, 3); // Position behind other GUI elements
app.getGuiNode().attachChild(background);
}
/**
* Handles the escape action for the dialog.
*/
@Override
public void escape() {
new SettingsMenu(app).open();
}
/**
* Updates the dialog periodically, called by the dialog manager.
*
* @param delta The time elapsed since the last update.
*/
@Override
public void update(float delta) {
// Check if the selection has changed
if (selectionRef.update()) {
String selected = playerSelector.getSelectedItem();
if (!selected.equals(lastSelected)) {
lastSelected = selected;
onDropdownSelectionChanged(selected);
}
}
}
@Override
public void close() {
app.getGuiNode().detachChild(playerSelector);
app.getGuiNode().detachChild(lowerLeftMenu);
app.getGuiNode().detachChild(lowerRightMenu);
app.getGuiNode().detachChild(mainContainer);
app.getGuiNode().detachChild(background);
super.close();
}
/**
* Callback for when the dropdown selection changes.
*/
private void onDropdownSelectionChanged(String selected) {
app.getGameLogic().playSound(Sound.BUTTON);
int idStart = selected.indexOf("(ID: ") + 5; // Find start of the ID
int idEnd = selected.indexOf(")", idStart); // Find end of the ID
String idStr = selected.substring(idStart, idEnd); // Extract the ID as a string
int playerId = Integer.parseInt(idStr); // Convert the ID to an integer
// Find the player by ID
Player selectedPlayer = app.getGameLogic().getPlayerHandler().getPlayerById(playerId);
if (selectedPlayer != null) {
tradeHandler.setReceiver(selectedPlayer); // Set the receiver in TradeHandler
}
}
}

View File

@@ -1,151 +1,226 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client.gui;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.SpringGridLayout;
import static pp.monopoly.Resources.lookup;
import com.simsilica.lemur.style.ElementId;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.StartMenu;
import pp.monopoly.client.NetworkSupport;
import pp.monopoly.notification.Sound;
import pp.monopoly.server.MonopolyServer;
import pp.dialog.Dialog;
import pp.dialog.DialogBuilder;
/**
* CreateGameMenu class represents the menu for creating a new game.
* Represents a dialog for setting up a network connection in the Battleship game.
* Allows users to specify the host and port for connecting to a game server.
*/
public class CreateGameMenu {
private final MonopolyApp app;
private final Container menuContainer;
private Geometry background;
private Label serverStatusLabel;
public CreateGameMenu(MonopolyApp app) {
this.app = app;
// Hintergrundbild laden und hinzufügen
addBackgroundImage();
// Hauptcontainer für das Menü
menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
menuContainer.setPreferredSize(new Vector3f(600, 400, 0)); // Feste Größe des Containers
// Titel
Label title = menuContainer.addChild(new Label("Neues Spiel", new ElementId("header")));
title.setFont(app.getAssetManager().loadFont("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt"));
title.setFontSize(50);
// Eingabefelder-Container
Container inputContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X)));
inputContainer.setPreferredSize(new Vector3f(200, 150, 0)); // Eingabefelder nicht ganz so breit
inputContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand
inputContainer.addChild(new Label("Server-Adresse:"));
TextField playerNameField = inputContainer.addChild(new TextField("localhost"));
playerNameField.setPreferredWidth(400); // Breite des Textfelds
inputContainer.addChild(new Label("Port:"));
TextField serverAddressField = inputContainer.addChild(new TextField("42069"));
serverAddressField.setPreferredWidth(400); // Breite des Textfelds
// Button-Container
Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
buttonContainer.setPreferredSize(new Vector3f(400, 50, 0));
buttonContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand
// "Abbrechen"-Button
Button cancelButton = buttonContainer.addChild(new Button("Abbrechen"));
cancelButton.setPreferredSize(new Vector3f(120, 40, 0));
cancelButton.addClickCommands(source -> goBackToStartMenu());
// "Selber hosten"-Button
Button hostButton = buttonContainer.addChild(new Button("Selber hosten"));
hostButton.setPreferredSize(new Vector3f(120, 40, 0));
hostButton.addClickCommands(source -> app.getNetworkSupport().startServerAndJoin());
// "Beitreten"-Button
Button joinButton = buttonContainer.addChild(new Button("Beitreten"));
joinButton.setPreferredSize(new Vector3f(120, 40, 0));
joinButton.addClickCommands(source -> {
try {
String host = playerNameField.getText().trim();
int port = Integer.parseInt(serverAddressField.getText().trim());
app.getNetworkSupport().connectToServer(host, port);
// LobbyMenu öffnen
app.enqueue(() -> {
app.getGuiNode().detachAllChildren(); // Bestehende GUI entfernen
new LobbyMenu(app); // LobbyMenu erstellen
});
} catch (NumberFormatException e) {
app.errorDialog("Port muss eine Zahl sein.");
}
});
// Serverstatus-Label
serverStatusLabel = menuContainer.addChild(new Label("Serverstatus: Noch nicht gestartet"));
serverStatusLabel.setFontSize(24);
// Zentrierung des Containers
menuContainer.setLocalTranslation(
(app.getCamera().getWidth() - menuContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + menuContainer.getPreferredSize().y) / 2,
1 // Höhere Z-Ebene für den Vordergrund
);
app.getInputManager().addMapping("OpenTestWorld", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_T));
app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("OpenTestWorld") && isPressed) {
app.startTestWorld(); // Öffnet die TestWorld
}
}
}, "OpenTestWorld");
// TODO später entfernen
app.getInputManager().addMapping("OpenBuyCard", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_B));
app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("OpenBuyCard") && isPressed) {
app.startBuyCard(); // Öffnet die TestWorld
}
}
}, "OpenBuyCard");
app.getGuiNode().attachChild(menuContainer);
}
public class CreateGameMenu extends Dialog {
private static final Logger LOGGER = System.getLogger(CreateGameMenu.class.getName());
private static final String LOCALHOST = "localhost"; //NON-NLS
private static final String DEFAULT_PORT = "42069"; //NON-NLS
private final NetworkSupport network;
private final TextField host = new TextField(LOCALHOST);
private final TextField port = new TextField(DEFAULT_PORT);
private final Button serverButton = new Button("Selber hosten");
private final Button cancelButton = new Button("Abbrechen");
private final Button joinButton = new Button("Beitreten");
private String hostname;
private int portNumber;
private Future<Object> connectionFuture;
private Dialog progressDialog;
/**
* Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu.
* Constructs a new CreateGameMenu.
*
* @param network The NetworkSupport instance to be used for network operations.
*/
private void addBackgroundImage() {
public CreateGameMenu(NetworkSupport network) {
super(network.getApp().getDialogManager());
this.network = network;
host.setSingleLine(true);
host.setPreferredWidth(400f);
port.setSingleLine(true);
final MonopolyApp app = network.getApp();
int screenWidth = app.getContext().getSettings().getWidth();
int screenHeight = app.getContext().getSettings().getHeight();
// Set up the background image
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
background = new Geometry("Background", quad);
Quad quad = new Quad(screenWidth, screenHeight);
Geometry background = new Geometry("Background", quad);
Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
backgroundMaterial.setTexture("ColorMap", backgroundImage);
background.setMaterial(backgroundMaterial);
background.setLocalTranslation(0, 0, -1); // Hintergrundebene
background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
app.getGuiNode().attachChild(background);
addChild(new Label("Spiel erstellen", new ElementId("header"))); //NON-NLS
final Container input = new Container(new SpringGridLayout());
input.addChild(new Label(lookup("host.name") + ": "));
input.addChild(host, 1);
input.addChild(new Label(lookup("port.number") + ": "));
input.addChild(port, 1);
addChild(input);
// "Abbrechen"-Button
cancelButton.setPreferredSize(new Vector3f(120, 40, 0));
cancelButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
this.close();
new StartMenu(network.getApp()).open();
}));
addChild(cancelButton);
// "Selber hosten"-Button
serverButton.addClickCommands(s -> ifTopDialog( () -> {
network.getApp().getGameLogic().playSound(Sound.BUTTON);
startServerInThread();
} ));
addChild(serverButton);
// "Beitreten"-Button
joinButton.setPreferredSize(new Vector3f(120, 40, 0));
joinButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
connect();
}));
addChild(joinButton);
}
/**
* Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird.
* Handles the action for the connect button in the connection dialog.
* Tries to parse the port number and initiate connection to the server.
*/
private void goBackToStartMenu() {
app.getGuiNode().detachChild(menuContainer);
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
StartMenu.createStartMenu(app);
private void connect() {
LOGGER.log(Level.INFO, "connect to host={0}, port={1}", host, port); //NON-NLS
try {
hostname = host.getText().trim().isEmpty() ? LOCALHOST : host.getText();
portNumber = Integer.parseInt(port.getText());
openProgressDialog();
connectionFuture = network.getApp().getExecutor().submit(this::initNetwork);
}
catch (NumberFormatException e) {
network.getApp().errorDialog(lookup("port.must.be.integer"));
}
}
/**
* Creates a dialog indicating that the connection is in progress.
*/
private void openProgressDialog() {
progressDialog = DialogBuilder.simple(network.getApp().getDialogManager())
.setText(lookup("label.connecting"))
.build();
progressDialog.open();
}
/**
* Tries to initialize the network connection.
*
* @throws RuntimeException If an error occurs when creating the client.
*/
private Object initNetwork() {
try {
network.initNetwork(hostname, portNumber);
return null;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void escape() {
new SettingsMenu(network.getApp()).open();
}
/**
* This method is called by {@linkplain pp.dialog.DialogManager#update(float)} for periodically
* updating this dialog. T
*/
@Override
public void update(float delta) {
if (connectionFuture != null && connectionFuture.isDone())
try {
connectionFuture.get();
success();
}
catch (ExecutionException e) {
failure(e.getCause());
}
catch (InterruptedException e) {
LOGGER.log(Level.WARNING, "Interrupted!", e); //NON-NLS
Thread.currentThread().interrupt();
}
}
/**
* Handles a successful connection to the game server.
*/
private void success() {
connectionFuture = null;
progressDialog.close();
this.close();
new LobbyMenu(network.getApp()).open();
}
/**
* Handles a failed connection attempt.
*
* @param e The cause of the failure.
*/
private void failure(Throwable e) {
connectionFuture = null;
progressDialog.close();
network.getApp().errorDialog(lookup("server.connection.failed"));
network.getApp().setInfoText(e.getLocalizedMessage());
}
/**
* Starts the server in a separate thread.
*/
private void startServerInThread() {
serverButton.setEnabled(false);
Thread serverThread = new Thread(() -> {
try {
MonopolyServer.main(null);
} catch (Exception e) {
serverButton.setEnabled(true);
LOGGER.log(Level.ERROR, "Server could not be started", e);
network.getApp().errorDialog("Could not start server: " + e.getMessage());
}
});
serverThread.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
connect();
}
}

View File

@@ -22,17 +22,16 @@ import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList;
import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.game.client.ClientGameLogic;
import pp.monopoly.game.server.Player;
import pp.monopoly.game.server.PlayerColor;
import pp.monopoly.game.server.PlayerHandler;
import pp.monopoly.model.Figure;
import pp.monopoly.model.Rotation;
import pp.monopoly.message.client.PlayerReady;
import pp.monopoly.notification.Sound;
import java.util.Set;
public class LobbyMenu {
public class LobbyMenu extends Dialog {
private final MonopolyApp app;
private final Container menuContainer;
@@ -40,35 +39,29 @@ public class LobbyMenu {
private Geometry circle;
private Container lowerLeftMenu;
private Container lowerRightMenu;
private ColorRGBA playerColor= ColorRGBA.Gray;
private PlayerHandler playerHandler;
private TextField startingCapital;
private TextField playerInputField;
private Selector<String> figureDropdown;
private TextField startingCapital = new TextField("15000");
private String figure;
public LobbyMenu(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
this.playerHandler = ClientGameLogic.getPlayerHandler(); // Initialize PlayerHandler
int playerID = app.getNetworkSupport().getId(); // Retrieve the player ID
assignPlayerColor(playerID); //set the Players Color
app.getGuiNode().detachAllChildren(); // Entfernt das CreateGameMenu (inklusive Hintergrund)
addBackgroundImage();// Hintergrundbild laden und hinzufügen
playerInputField = new TextField("Spieler "+(app.getId()+1));
// Hintergrundbild laden und hinzufügen
addBackgroundImage();
QuadBackgroundComponent translucentWhiteBackground =
new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
menuContainer.setPreferredSize(new Vector3f(1000, 600, 0));
menuContainer.setPreferredSize(new Vector3f(1000, 600, 0)); // Fixed size of the container
menuContainer.setBackground(translucentWhiteBackground);
// Create a smaller horizontal container for the label, input field, and spacers
Container horizontalContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
horizontalContainer.setPreferredSize(new Vector3f(600, 40, 0));
horizontalContainer.setPreferredSize(new Vector3f(600, 40, 0)); // Adjust container size
horizontalContainer.setBackground(null);
Label title = horizontalContainer.addChild(new Label("Startkapital:", new ElementId("label-Bold")));
@@ -79,7 +72,7 @@ public class LobbyMenu {
spacerBeforeInput.setPreferredSize(new Vector3f(20, 1, 0)); // Width of the spacer
// Add an input field (TextField)
TextField startingCapital = horizontalContainer.addChild(new TextField("15 000"));
horizontalContainer.addChild(startingCapital);
startingCapital.setPreferredWidth(100); // Set the width of the input field
startingCapital.setPreferredSize(new Vector3f(150, 50, 0));
startingCapital.setInsets(new Insets3f(5, 10, 5, 10)); // Add padding around the text inside the field
@@ -97,6 +90,7 @@ public class LobbyMenu {
// Dropdowns and Labels
Container dropdownContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(ColorRGBA.Black)));
dropdownContainer.setPreferredSize(new Vector3f(800, 200, 0));
dropdownContainer.setBackground(null);
dropdownContainer.setInsets(new Insets3f(10, 0, 0, 0));
@@ -106,18 +100,16 @@ public class LobbyMenu {
playerInputContainer.setBackground(null);
TextField playerInputField = new TextField("Spieler 1");
playerInputField.setPreferredSize(new Vector3f(100, 20, 0));
playerInputField.setInsets(new Insets3f(5, 10, 5, 10));
playerInputField.setInsets(new Insets3f(5, 10, 5, 10)); // Add padding for the text inside the field
playerInputField.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
playerInputContainer.addChild(playerInputField);
// Spacer (Center Circle Area)
Label spacer = dropdownContainer.addChild(new Label(""));
spacer.setPreferredSize(new Vector3f(200, 200, 0));
spacer.setPreferredSize(new Vector3f(200, 200, 0)); // Adjust this to fit the center graphic
// Figur Dropdown
Container figureDropdownContainer = dropdownContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X)));
figureDropdownContainer.setPreferredSize(new Vector3f(150, 80, 0));
figureDropdownContainer.addChild(new Label("Figur:"));
figureDropdownContainer.setBackground(null);
@@ -129,14 +121,18 @@ public class LobbyMenu {
figures.add("OOP");
figures.add("Handyholster");
Selector<String> figureDropdown = new Selector<>(figures, "glass");
figureDropdown.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
figureDropdown.setPreferredSize(new Vector3f(150, 140, 0));
Vector3f dimens = figureDropdownContainer.getPreferredSize();
figureDropdown.setPreferredSize(new Vector3f(100, 20, 0));
figureDropdownContainer.addChild(figureDropdown);
Vector3f dimens = dropdownContainer.getPreferredSize();
Vector3f dimens2 = figureDropdown.getPopupContainer().getPreferredSize();
dimens2.setX( dimens.getX() );
figureDropdown.getPopupContainer().setPreferredSize( dimens2 );
figureDropdownContainer.addChild(figureDropdown);
figureDropdown.getPopupContainer().setPreferredSize(new Vector3f(200,200,5));
figureDropdown.getSelectionModel().setSelection(0);
figure = "Laptop";
addSelectionActionListener(figureDropdown, this::onDropdownSelectionChanged);
@@ -146,10 +142,13 @@ public class LobbyMenu {
buttonContainer.setBackground(null);
// Lower-left container for "Abbrechen" button
lowerLeftMenu = new Container();
Button cancelButton = new Button("Abbrechen");
Button cancelButton = new Button("Beenden");
cancelButton.setPreferredSize(new Vector3f(200, 60, 0)); // Set size to match the appearance in the image
cancelButton.setFontSize(18); // Adjust font size
cancelButton.addClickCommands(source -> goBackToCreateGame()); // Add functionality
cancelButton.addClickCommands(s -> ifTopDialog(() -> {
app.closeApp();
app.getGameLogic().playSound(Sound.BUTTON);
}));
lowerLeftMenu.addChild(cancelButton);
// Position the container near the bottom-left corner
@@ -162,11 +161,12 @@ public class LobbyMenu {
readyButton.setPreferredSize(new Vector3f(200, 60, 0)); // Set size to match the appearance in the image
readyButton.setFontSize(18); // Adjust font size
readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.Green)); // Add color to match the style
readyButton.addClickCommands(source -> applyStartingCapital(playerID));
readyButton.addClickCommands(source -> applyPlayerName(playerID));
readyButton.addClickCommands(source -> applyFigure(playerID));
readyButton.addClickCommands(s -> ifTopDialog(() -> {
toggleReady();
app.getGameLogic().playSound(Sound.BUTTON);
readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
}));
lowerRightMenu.addChild(readyButton);
//TODO aktivieren des Spielers in den ready Status und Sprung in den nächsten Menüzustand
// Position the container near the bottom-right corner
lowerRightMenu.setLocalTranslation(new Vector3f(app.getCamera().getWidth() - 320, 170, 3)); // X: 220px from the right, Y: 50px above the bottom
@@ -190,59 +190,7 @@ public class LobbyMenu {
app.getGuiNode().attachChild(menuContainer);
}
/**
* Apply the starting capital only if the current player is the host.
*/
private void applyStartingCapital(int playerID) {
Player currentPlayer = playerHandler.getPlayerById(playerID);
// Check if the current player is the host
if (currentPlayer.equals(playerHandler.getHostPlayer())) {
try {
// Parse and validate starting capital
int startBalance = Integer.parseInt(startingCapital.getText().replaceAll("[^\\d]", ""));
if (startBalance < 0) throw new NumberFormatException("Starting capital must be positive.");
// Apply the starting balance to all players
playerHandler.setStartBalance(startBalance);
System.out.println("Starting balance set to: " + startBalance);
} catch (NumberFormatException e) {
System.err.println("Invalid starting capital: " + e.getMessage());
}
} else {
System.out.println("Only the host can set the starting balance.");
}
}
/**
* Apply the player name from the input field.
*/
private void applyPlayerName(int playerID) {
Player currentPlayer = playerHandler.getPlayerById(playerID);
String playerName = playerInputField.getText().trim();
if (!playerName.isEmpty()) {
currentPlayer.setName(playerName);
System.out.println("Player name set to: " + playerName);
} else {
System.err.println("Invalid player name: Name cannot be empty.");
}
}
/**
* Apply the selected figure to the player.
*/
private void applyFigure(int playerID) {
Player currentPlayer = playerHandler.getPlayerById(playerID);
String selectedFigure = figureDropdown.getSelectedItem();
if (selectedFigure != null && !selectedFigure.isEmpty()) {
currentPlayer.setFigure(new Figure(0, 0, 0, Rotation.RIGHT, "selectedFigure"));
System.out.println("Player figure set to: " + selectedFigure);
} else {
System.err.println("Invalid figure selection.");
}
}
/**
* Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu.
@@ -266,61 +214,36 @@ public class LobbyMenu {
// Create a material with a solid color
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", playerColor); // Set the desired color
material.setColor("Color", idToColor()); // Set the desired color
circleGeometry.setMaterial(material);
return circleGeometry;
}
public void setPlayerColor(ColorRGBA newColor) {
this.playerColor = newColor;
// Update the circle's color
if (circle != null) {
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", playerColor);
circle.setMaterial(material);
}
}
/**
* Assigns a color to the player based on their ID.
*
* @param playerID the player's ID
*/
private void assignPlayerColor(int playerID) {
switch (playerID) {
case 0:
playerColor = PlayerColor.RED.getColor();
break;
case 1:
playerColor = PlayerColor.GREEN_LIGHT.getColor();
break;
case 2:
playerColor = PlayerColor.BLUE.getColor();
break;
case 3:
playerColor = PlayerColor.PINK.getColor();
break;
case 4:
playerColor = PlayerColor.GREEN_DARK.getColor();
break;
case 5:
playerColor = PlayerColor.YELLOW.getColor();
break;
private ColorRGBA idToColor() {
switch (app.getId()+1) {
case 1: return PlayerColor.CYAN.getColor();
case 2: return PlayerColor.YELLOW.getColor();
case 3: return PlayerColor.RED.getColor();
case 4: return PlayerColor.PINK.getColor();
case 5: return PlayerColor.GREEN.getColor();
case 6: return PlayerColor.PURPLE.getColor();
default:
playerColor = ColorRGBA.White; // Default color if ID is unknown
return null;
}
}
/**
* Geht zurück zum CreateGameMenu.
* Schaltet den "Bereit"-Status um.
*/
private void goBackToCreateGame() {
app.getGuiNode().detachChild(menuContainer);
app.getGuiNode().detachChild(background);
app.getGuiNode().detachChild(circle);
app.getGuiNode().detachChild(lowerLeftMenu);
app.getGuiNode().detachChild(lowerRightMenu);
new CreateGameMenu(app);
private void toggleReady() {
app.getGameLogic().send(new PlayerReady(true, playerInputField.getText(), figure, Integer.parseInt(startingCapital.getText())));
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
/**
@@ -334,7 +257,6 @@ public class LobbyMenu {
public void update(float tpf) {
if (selectionRef.update()) {
String selected = selectionRef.get().toString();
System.out.println(selected);
listener.onSelectionChanged(selected);
}
}
@@ -363,28 +285,28 @@ public class LobbyMenu {
* Callback for when the dropdown selection changes.
*/
private void onDropdownSelectionChanged(String selected) {
System.out.println("Selected: " + selected);
app.getGameLogic().playSound(Sound.BUTTON);
switch (selected) {
case "[0]":
System.out.println("Laptop selected");
figure = "Laptop";
break;
case "[1]":
System.out.println("Flugzeug selected");
figure = "Flugzeug";
break;
case "[2]":
System.out.println("Jägermeister selected");
figure = "Jägermeister";
break;
case "[3]":
System.out.println("Katze selected");
figure = "Katze";
break;
case "[4]":
System.out.println("OOP selected");
figure = "OOP";
break;
case "[5]":
System.out.println("Handyholster selected");
figure = "Handyholster";
break;
default:
System.out.println("Unknown selection");
break;
}
}

View File

@@ -0,0 +1,258 @@
package pp.monopoly.client.gui;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.game.server.Player;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.FoodField;
import pp.monopoly.model.fields.GateField;
import pp.monopoly.model.fields.PropertyField;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* PropertyOverviewMenu is a dialog for displaying the player's properties in the game.
*/
public class PropertyOverviewMenu extends Dialog {
private final MonopolyApp app;
private final Container mainContainer;
private final Container displayContainer;
private final Slider horizontalSlider;
private final List<Container> cards;
/**
* Constructs the PropertyOverviewMenu dialog.
*
* @param app The Monopoly application instance.
*/
public PropertyOverviewMenu(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Make the menu fullscreen
Vector3f screenSize = new Vector3f(app.getCamera().getWidth(), app.getCamera().getHeight(), 0);
// Main container for the menu layout
mainContainer = new Container();
mainContainer.setPreferredSize(screenSize); // Make fullscreen
mainContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.8f))); // Semi-transparent background
// Header label
Label headerLabel = mainContainer.addChild(new Label("Meine Grundstücke", new ElementId("header")));
headerLabel.setFontSize(40);
// Central display container (to hold the "Gebäude" cards)
displayContainer = mainContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y, FillMode.Even, FillMode.None))); // Horizontal layout
displayContainer.setPreferredSize(new Vector3f(screenSize.x - 300, 550, 0)); // Take up the remaining width
displayContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.White));
displayContainer.setLocalTranslation(0, 0, 11);
// Add some placeholder "Gebäude" cards to the display container
cards = new ArrayList<>();
populatePlayerProperties();
// Initially add only visible cards to the displayContainer
refreshVisibleCards(0);
// Horizontal slider for scrolling through cards
horizontalSlider = mainContainer.addChild(new Slider(Axis.X));
horizontalSlider.setPreferredSize(new Vector3f(screenSize.x - 300, 20, 5));
horizontalSlider.setModel(new DefaultRangedValueModel(0, Math.max(0, cards.size() - 5), 0));
horizontalSlider.addControl(new SliderValueChangeListener());
// Add the "Zurück" button at the bottom
Button backButton = mainContainer.addChild(new Button("Zurück", new ElementId("button")));
backButton.setPreferredSize(new Vector3f(200, 60, 0));
backButton.addClickCommands(source -> this.close());
// Attach the main container to the GUI node
app.getGuiNode().attachChild(mainContainer);
mainContainer.setLocalTranslation(
0,
app.getCamera().getHeight(), // Align to the top
10
);
}
/**
* Fetches the player's properties and populates them into the cards list.
*/
private void populatePlayerProperties() {
// Fetch the current player
Player currentPlayer = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
// Fetch the player's properties using their indices
List<PropertyField> fields = new ArrayList<>();
for (Integer i : currentPlayer.getProperties()) {
fields.add((PropertyField) app.getGameLogic().getBoardManager().getFieldAtIndex(i));
}
// Iterate through the fetched properties
for (PropertyField property : fields.stream().sorted(Comparator.comparingInt(PropertyField::getId)).collect(Collectors.toList())) {
if (property instanceof BuildingProperty) {
BuildingProperty building = (BuildingProperty) property;
cards.add(createBuildingCard(building));
} else if (property instanceof FoodField) {
FoodField foodField = (FoodField) property;
cards.add(createFoodFieldCard(foodField));
} else if (property instanceof GateField) {
GateField gateField = (GateField) property;
cards.add(createGateFieldCard(gateField));
}
}
}
/**
* Creates a card for BuildingProperty with detailed rent and cost information.
*/
private Container createBuildingCard(BuildingProperty field) {
Container card = new Container();
card.setPreferredSize(new Vector3f(200, 300, 2)); // Match the size of the BuildingPropertyCard
card.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
card.setInsets(new Insets3f(5, 5, 5, 5)); // Add 5-pixel inset
card.addChild(new Label(field.getName(), new ElementId("label-Bold"))).setFontSize(25);
// Add property details
Container propertyValuesContainer = card.addChild(new Container());
propertyValuesContainer.addChild(new Label("Grundstückswert: " + field.getPrice()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
propertyValuesContainer.addChild(new Label("Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("- mit 1 Haus: " + field.getAllRent().get(1)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("- mit 2 Häuser: " + field.getAllRent().get(2)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("- mit 3 Häuser: " + field.getAllRent().get(3)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("- mit 4 Häuser: " + field.getAllRent().get(4)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("- mit 1 Hotel: " + field.getAllRent().get(5)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("- 1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
Label hypo = new Label("Hypothek: " + field.getHypo()+ " EUR", new ElementId("label-Text"));
hypo.setFontSize(14);
if (field.isMortgaged()) hypo.setColor(ColorRGBA.Red);
propertyValuesContainer.addChild(hypo);
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
return card;
}
/**
* Creates a card for FoodField with dynamic pricing and rent details.
*/
private Container createFoodFieldCard(FoodField field) {
Container card = new Container();
card.setPreferredSize(new Vector3f(200, 300, 2)); // Adjust card size
card.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f))); // Dark background for card
card.setInsets(new Insets3f(5, 5, 5, 5)); // Add 5-pixel inset
// Title Section
Label title = card.addChild(new Label(field.getName(), new ElementId("label-Bold")));
title.setFontSize(30);
title.setColor(ColorRGBA.White); // Ensure readability on dark background
// Property Values Section
Container propertyValuesContainer = card.addChild(new Container());
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Grey background
propertyValuesContainer.addChild(new Label("Preis: " + field.getPrice()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
propertyValuesContainer.addChild(new Label("Wenn man Besitzer der", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label(field.getName() + " ist, so ist", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("die Miete 40x Würfelwert.", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
propertyValuesContainer.addChild(new Label("Besitzer beider", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("Restaurants zahlt", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("100x Würfelwert.", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
propertyValuesContainer.addChild(new Label("Hypothek: " + field.getHypo()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
return card;
}
/**
* Creates a card for GateField with rent details for owning multiple gates.
*/
private Container createGateFieldCard(GateField field) {
Container card = new Container();
card.setPreferredSize(new Vector3f(200, 300, 2)); // Adjust card size
card.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light grey background
card.setInsets(new Insets3f(5, 5, 5, 5)); // Add 5-pixel inset
// Title Section
Label title = card.addChild(new Label(field.getName(), new ElementId("label-Bold")));
title.setFontSize(30);
title.setColor(ColorRGBA.Black);
// Property Values Section
Container propertyValuesContainer = card.addChild(new Container());
propertyValuesContainer.addChild(new Label("Preis: " + field.getPrice()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("Miete: 250 EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("2 Bahnhof besitzt: 500 EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("3 Bahnhof besitzt: 1000 EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("4 Bahnhof besitzt: 2000 EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text"))).setFontSize(14);
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Dark grey background
return card;
}
/**
* Updates the visible cards in the displayContainer based on the slider value.
*
* @param startIndex The starting index of the visible cards.
*/
private void refreshVisibleCards(int startIndex) {
displayContainer.clearChildren(); // Remove all current children
int maxVisible = 5; // Number of cards to display at once
for (int i = startIndex; i < startIndex + maxVisible && i < cards.size(); i++) {
displayContainer.addChild(cards.get(i));
}
}
/**
* Custom listener for slider value changes.
*/
private class SliderValueChangeListener extends AbstractControl {
@Override
protected void controlUpdate(float tpf) {
// Get the slider's current value and refresh visible cards
int sliderValue = (int) ((Slider) getSpatial()).getModel().getValue();
refreshVisibleCards(sliderValue);
}
@Override
protected void controlRender(RenderManager renderManager, ViewPort viewPort) {
// No rendering logic needed
}
}
/**
* Closes the dialog and detaches it from the GUI node.
*/
@Override
public void close() {
app.getGuiNode().detachChild(mainContainer);
super.close();
}
}

View File

@@ -1,123 +1,91 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client.gui;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import java.util.prefs.Preferences;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.Slider;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import com.simsilica.lemur.ValueRenderer;
import com.simsilica.lemur.Selector;
import pp.dialog.Dialog;
import pp.monopoly.client.GameMusic;
import pp.monopoly.client.GameSound;
import pp.monopoly.client.MonopolyApp;
import pp.dialog.Dialog;
import pp.dialog.StateCheckboxModel;
import pp.monopoly.notification.Sound;
import static pp.util.PreferencesUtils.getPreferences;
/**
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
* The Menu class represents the main menu in the Battleship game application.
* It extends the Dialog class and provides functionalities for loading, saving,
* returning to the game, and quitting the application.
*/
public class SettingsMenu extends Dialog {
private static final Preferences PREFERENCES = getPreferences(SettingsMenu.class);
private static final String LAST_PATH = "last.file.path";
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container settingsContainer;
private final Container backgroundContainer;
private final VolumeSlider musicSlider;
private final SoundSlider soundSlider;
/**
* Constructs the Menu dialog for the Battleship application.
*
* @param app the MonopolyApp instance
*/
public SettingsMenu(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
musicSlider = new VolumeSlider(app.getStateManager().getState(GameMusic.class));
soundSlider = new SoundSlider(app.getStateManager().getState(GameSound.class));
addChild(new Label("Einstellungen", new ElementId("settings-title"))); //NON-NLS
addChild(new Label("Sound Effekte", new ElementId("label"))); //NON-NLS
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
addChild(soundSlider);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
addChild(new Checkbox("Soundeffekte an / aus", new StateCheckboxModel(app, GameSound.class)));
addChild(new Label("Hintergrund Musik", new ElementId("label"))); //NON-NLS
addChild(new Checkbox("Musik an / aus", new StateCheckboxModel(app, GameMusic.class)));
addChild(musicSlider);
// Hauptcontainer für das Menü
settingsContainer = new Container();
settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
// Titel
Label settingsTitle = settingsContainer.addChild(new Label("Einstellungen", new ElementId("settings-title")));
settingsTitle.setFontSize(48);
// Effekt-Sound: Slider und Checkbox
Container effectSoundContainer = settingsContainer.addChild(new Container());
effectSoundContainer.addChild(new Label("Effekt Sound", new ElementId("label")));
effectSoundContainer.addChild(new Slider());
effectSoundContainer.addChild(new Checkbox("Soundeffekte an")).setChecked(true);
effectSoundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Hintergrundmusik: Slider und Checkbox
Container backgroundMusicContainer = settingsContainer.addChild(new Container());
backgroundMusicContainer.addChild(new Label("Hintergrund Musik", new ElementId("label")));
backgroundMusicContainer.addChild(new Slider());
backgroundMusicContainer.addChild(new Checkbox("Musik an")).setChecked(true);
backgroundMusicContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button
Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("menu-button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> app.stop());
float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü
settingsContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2,
4
);
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2,
3
);
app.getGuiNode().attachChild(settingsContainer);
addChild(new Button("Zurück zum Spiel", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> {
this.close(); // Close the StartMenu dialog
app.getGameLogic().playSound(Sound.BUTTON);
}));
addChild(new Button("Beenden", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
app.closeApp();
}));
update();
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
* Updates the state of the load and save buttons based on the game logic.
*/
@Override
public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren
app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
public void update() {
}
@Override
public void update(float delta) {
musicSlider.update();
soundSlider.update();
}
/**
* As an escape action, this method closes the menu if it is the top dialog.
*/
@Override
public void escape() {
close();
}
}

View File

@@ -0,0 +1,31 @@
package pp.monopoly.client.gui;
import com.simsilica.lemur.Slider;
import pp.monopoly.client.GameSound;
public class SoundSlider extends Slider {
private final pp.monopoly.client.GameSound sound;
private double vol;
/**
* Constructs the Volume Slider for the Menu dialog
* @param sound the Effects sound instance
*/
public SoundSlider(GameSound sound) {
super();
this.sound = sound;
vol = GameSound.volumeInPreferences();
getModel().setPercent(vol);
}
/**
* when triggered it updates the volume to the value set with the slider
*/
public void update() {
if (vol != getModel().getPercent()) {
vol = getModel().getPercent();
sound.setVolume( (float) vol);
}
}
}

View File

@@ -1,4 +1,4 @@
package pp.monopoly.client;
package pp.monopoly.client.gui;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
@@ -13,8 +13,8 @@ import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.dialog.Dialog;
import pp.monopoly.client.gui.CreateGameMenu;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound;
/**
* Constructs the startup menu dialog for the Monopoly application.
@@ -22,8 +22,6 @@ import pp.monopoly.client.gui.GameMenu;
*/
public class StartMenu extends Dialog {
private final MonopolyApp app;
private Container logoContainer;
private Container unibwLogoContainer;
/**
* Constructs the Startup Menu dialog for the Monopoly application.
@@ -33,13 +31,7 @@ public class StartMenu extends Dialog {
public StartMenu(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
}
/**
* Creates and displays the Start Menu with buttons for starting the game,
* opening settings, and quitting the application.
*/
public static void createStartMenu(MonopolyApp app) {
int screenWidth = app.getContext().getSettings().getWidth();
int screenHeight = app.getContext().getSettings().getHeight();
@@ -53,9 +45,6 @@ public class StartMenu extends Dialog {
background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
app.getGuiNode().attachChild(background);
createMonopolyLogo(app);
createUnibwLogo(app);
// Center container for title and play button
Container centerMenu = new Container(new SpringGridLayout(Axis.Y, Axis.X));
@@ -64,7 +53,11 @@ public class StartMenu extends Dialog {
startButton.setFontSize(40); // Set the font size for the button text
startButton.setTextHAlignment(HAlignment.Center); // Center the text horizontally
startButton.addClickCommands(source -> startGame(app));
startButton.addClickCommands(s -> ifTopDialog(() -> {
close();
app.getGameLogic().playSound(Sound.BUTTON);
app.connect(); // Perform the connection logic
}));
centerMenu.addChild(startButton);
// Position the center container in the middle of the screen
@@ -73,34 +66,6 @@ public class StartMenu extends Dialog {
0));
app.getGuiNode().attachChild(centerMenu);
// Lower-left container for "Spiel beenden" button
Container lowerLeftMenu = new Container();
lowerLeftMenu.setLocalTranslation(new Vector3f(100, 90, 0));
Button quitButton = new Button("Spiel beenden");
quitButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height)
quitButton.setFontSize(18);
quitButton.addClickCommands(source -> quitGame());
lowerLeftMenu.addChild(quitButton);
app.getGuiNode().attachChild(lowerLeftMenu);
// Lower-right container for "Einstellungen" button
Container lowerRightMenu = new Container();
lowerRightMenu.setLocalTranslation(new Vector3f(screenWidth - 200, 90, 0));
Button settingsButton = new Button("Einstellungen");
settingsButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height)
settingsButton.setFontSize(18); // Increase the font size for the text
settingsButton.addClickCommands(source -> openSettings(app));
lowerRightMenu.addChild(settingsButton);
app.getGuiNode().attachChild(lowerRightMenu);
}
/**
* Creates and positions the Monopoly logo container in the center of the screen.
*/
private static void createMonopolyLogo(MonopolyApp app) {
int screenWidth = app.getContext().getSettings().getWidth();
int screenHeight = app.getContext().getSettings().getHeight();
// Load the Monopoly logo as a texture
Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopoly.png");
@@ -123,14 +88,6 @@ public class StartMenu extends Dialog {
// Attach the container to the GUI node
app.getGuiNode().attachChild(logoContainer);
}
/**
* Creates and positions the Unibw logo container in the center of the screen.
*/
private static void createUnibwLogo(MonopolyApp app) {
int screenWidth = app.getContext().getSettings().getWidth();
int screenHeight = app.getContext().getSettings().getHeight();
// Load the Unibw logo as a texture
Texture unibwTexture = app.getAssetManager().loadTexture("Pictures/logo-unibw.png");
@@ -156,26 +113,14 @@ public class StartMenu extends Dialog {
app.getGuiNode().attachChild(unibwContainer);
}
/**
* Starts the game by transitioning to the CreateGameMenu.
*/
private static void startGame(MonopolyApp app) {
app.getGuiNode().detachAllChildren();
new CreateGameMenu(app);
@Override
public void escape() {
new SettingsMenu(app).open();
}
/**
* Opens the settings menu.
*/
private static void openSettings(MonopolyApp app) {
@Override
public void close() {
app.getGuiNode().detachAllChildren();
new SettingsMenu(app);
}
/**
* Quits the game application.
*/
private static void quitGame() {
System.exit(0);
super.close();
}
}

View File

@@ -1,114 +1,416 @@
package pp.monopoly.client.gui;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.texture.Texture;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.popups.AcceptTrade;
import pp.monopoly.client.gui.popups.BuildingPropertyCard;
import pp.monopoly.client.gui.popups.ConfirmTrade;
import pp.monopoly.client.gui.popups.EventCardPopup;
import pp.monopoly.client.gui.popups.FoodFieldCard;
import pp.monopoly.client.gui.popups.GateFieldCard;
import pp.monopoly.client.gui.popups.Gulag;
import pp.monopoly.client.gui.popups.GulagInfo;
import pp.monopoly.client.gui.popups.LooserPopUp;
import pp.monopoly.client.gui.popups.NoMoneyWarning;
import pp.monopoly.client.gui.popups.RejectTrade;
import pp.monopoly.client.gui.popups.Rent;
import pp.monopoly.client.gui.popups.TimeOut;
import pp.monopoly.client.gui.popups.WinnerPopUp;
import pp.monopoly.game.server.Player;
import pp.monopoly.game.server.PlayerHandler;
import pp.monopoly.message.server.NotificationMessage;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.FoodField;
import pp.monopoly.model.fields.GateField;
import pp.monopoly.notification.EventCardEvent;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.PopUpEvent;
import pp.monopoly.notification.UpdatePlayerView;
/**
* TestWorld zeigt eine einfache Szene mit einem texturierten Quadrat.
* Die Kamera wird durch den CameraController gesteuert.
* TestWorld zeigt eine einfache Szene mit Spielfeld und Spielfiguren.
*/
public class TestWorld {
public class TestWorld implements GameEventListener {
private final MonopolyApp app;
private CameraController cameraController; // Steuert die Kamera
private Geometry cube; // Spielfigur
private PlayerHandler playerHandler;
private CameraController cameraController;
private Toolbar toolbar;
/**
* Konstruktor für TestWorld.
* Konstruktor für die TestWorld.
*
* @param app Die Hauptanwendung (MonopolyApp)
* @param app Die Hauptanwendung
* @param players Die Liste der Spieler mit ihren Figuren
*/
public TestWorld(MonopolyApp app) {
this.app = app;
this.playerHandler = app.getGameLogic().getPlayerHandler();
app.getGameLogic().addListener(this);
cameraController = new CameraController(app.getCamera());
}
/**
* Initialisiert die Szene und startet die Kamerabewegung.
* Initialisiert die Szene mit Spielfeld und Figuren.
*/
public void initializeScene() {
app.getGuiNode().detachAllChildren(); // Entferne GUI
app.getRootNode().detachAllChildren(); // Entferne andere Szenenobjekte
// Entferne bestehende Inhalte
app.getGuiNode().detachAllChildren();
app.getRootNode().detachAllChildren();
setSkyColor(); // Setze den Himmel auf hellblau
createBoard(); // Erstelle das Spielfeld
createCube(); // Füge den Würfel hinzu
System.out.println("Szene initialisiert.");
// Erstelle den CameraController
cameraController = new CameraController(
app.getCamera(), // Die Kamera der App
Vector3f.ZERO, // Fokus auf die Mitte des Spielfelds
4, // Radius des Kreises
15, // Höhe der Kamera
0 // Geschwindigkeit der Bewegung
);
// Füge die Toolbar hinzu
new Toolbar(app, cube);
cameraController.setPosition(0);
}
/**
* Aktualisiert die Kameraposition.
*
* @param tpf Zeit pro Frame
*/
public void update(float tpf) {
if (cameraController != null) {
cameraController.update(tpf);
}
//Füge Inhalte ein
setSkyColor();
createBoard();
createPlayerFigures();
toolbar = new Toolbar(app);
toolbar.open();
}
/**
* Setzt die Hintergrundfarbe der Szene auf hellblau.
*/
private void setSkyColor() {
app.getViewPort().setBackgroundColor(new ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f)); // Hellblauer Himmel
app.getViewPort().setBackgroundColor(new com.jme3.math.ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f));
}
/**
* Erstelle das Spielfeld.
* Erstellt das Spielfeld und fügt es zur Szene hinzu.
*/
private void createBoard() {
// Erstelle ein Quadrat
Box box = new Box(10, 0.1f, 10); // Dünnes Quadrat für die Textur
Geometry geom = new Geometry("Board", box);
try {
com.jme3.scene.shape.Box box = new com.jme3.scene.shape.Box(10, 0.1f, 10);
com.jme3.scene.Geometry geom = new com.jme3.scene.Geometry("Board", box);
// Setze das Material mit Textur
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
Texture texture = app.getAssetManager().loadTexture("Pictures/board2.png");
mat.setTexture("ColorMap", texture);
geom.setMaterial(mat);
com.jme3.material.Material mat = new com.jme3.material.Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
com.jme3.texture.Texture texture = app.getAssetManager().loadTexture("Pictures/board2.png");
mat.setTexture("ColorMap", texture);
geom.setMaterial(mat);
app.getRootNode().attachChild(geom);
geom.setLocalTranslation(0, -0.1f, 0);
com.jme3.math.Quaternion rotation = new com.jme3.math.Quaternion();
rotation.fromAngleAxis(FastMath.HALF_PI, com.jme3.math.Vector3f.UNIT_Y);
geom.setLocalRotation(rotation);
app.getRootNode().attachChild(geom);
System.out.println("Spielbrett erfolgreich erstellt, gedreht und hinzugefügt.");
} catch (Exception e) {
System.err.println("Fehler beim Erstellen des Spielfelds: " + e.getMessage());
}
}
/**
* Erstellt den Würfel (Spielfigur) in der Szene.
* Erstellt die Spielfiguren basierend auf der bereits bekannten Spielerliste.
*/
private void createCube() {
Box box = new Box(0.05f, 0.05f, 0.05f); // Kleinere Größe für Spielfigur
cube = new Geometry("Cube", box);
private void createPlayerFigures() {
for (int i = 0; i < playerHandler.getPlayers().size(); i++) {
Player player = playerHandler.getPlayers().get(i);
try {
com.jme3.scene.Spatial model = app.getAssetManager().loadModel(
"models/" + player.getFigure().getType() + "/" + player.getFigure().getType() + ".j3o"
);
model.setLocalScale(0.5f);
// Setze das Material für den Würfel
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue); // Blau gefärbter Würfel
cube.setMaterial(mat);
int playerIndexOnField = calculatePlayerIndexOnField(player.getFieldID(), player.getId());
Vector3f startPosition = calculateFieldPosition(player.getFieldID(), playerIndexOnField);
model.setLocalTranslation(startPosition);
// Setze den Startpunkt des Würfels
cube.setLocalTranslation(0.8999999f, 0.1f, -0.9f);
model.setName("PlayerFigure_" + player.getId());
app.getRootNode().attachChild(model);
app.getRootNode().attachChild(cube);
System.out.println("Figur für Spieler " + player.getId() + " erstellt bei " + startPosition);
} catch (Exception e) {
System.err.println("Fehler beim Laden des Modells für Spieler " + player.getId() + ": " + e.getMessage());
}
}
}
private Vector3f calculateFieldPosition(int fieldID, int playerIndex) {
float offset = 0.1f;
float baseX = 0.0f;
float baseZ = 0.0f;
switch (fieldID) {
case 0: baseX = -9.1f; baseZ = -9.1f; break;
case 1: baseX = -6.5f; baseZ = -9.1f; break;
case 2: baseX = -4.9f; baseZ = -9.1f; break;
case 3: baseX = -3.3f; baseZ = -9.1f; break;
case 4: baseX = -1.6f; baseZ = -9.1f; break;
case 5: baseX = 0.0f; baseZ = -9.1f; break;
case 6: baseX = 1.6f; baseZ = -9.1f; break;
case 7: baseX = 3.3f; baseZ = -9.1f; break;
case 8: baseX = 4.9f; baseZ = -9.1f; break;
case 9: baseX = 6.5f; baseZ = -9.1f; break;
case 10: baseX = 9.1f; baseZ = -9.1f; break;
case 11: baseX = 9.1f; baseZ = -6.5f; break;
case 12: baseX = 9.1f; baseZ = -4.9f; break;
case 13: baseX = 9.1f; baseZ = -3.3f; break;
case 14: baseX = 9.1f; baseZ = -1.6f; break;
case 15: baseX = 9.1f; baseZ = 0.0f; break;
case 16: baseX = 9.1f; baseZ = 1.6f; break;
case 17: baseX = 9.1f; baseZ = 3.3f; break;
case 18: baseX = 9.1f; baseZ = 4.9f; break;
case 19: baseX = 9.1f; baseZ = 6.5f; break;
case 20: baseX = 9.1f; baseZ = 9.1f; break;
case 21: baseX = 6.5f; baseZ = 9.1f; break;
case 22: baseX = 4.9f; baseZ = 9.1f; break;
case 23: baseX = 3.3f; baseZ = 9.1f; break;
case 24: baseX = 1.6f; baseZ = 9.1f; break;
case 25: baseX = 0.0f; baseZ = 9.1f; break;
case 26: baseX = -1.6f; baseZ = 9.1f; break;
case 27: baseX = -3.3f; baseZ = 9.1f; break;
case 28: baseX = -4.9f; baseZ = 9.1f; break;
case 29: baseX = -6.5f; baseZ = 9.1f; break;
case 30: baseX = -9.1f; baseZ = 9.1f; break;
case 31: baseX = -9.1f; baseZ = 6.5f; break;
case 32: baseX = -9.1f; baseZ = 4.9f; break;
case 33: baseX = -9.1f; baseZ = 3.3f; break;
case 34: baseX = -9.1f; baseZ = 1.6f; break;
case 35: baseX = -9.1f; baseZ = 0.0f; break;
case 36: baseX = -9.1f; baseZ = -1.6f; break;
case 37: baseX = -9.1f; baseZ = -3.3f; break;
case 38: baseX = -9.1f; baseZ = -4.9f; break;
case 39: baseX = -9.1f; baseZ = -6.5f; break;
default: throw new IllegalArgumentException("Ungültige Feld-ID: " + fieldID);
}
float xOffset = (playerIndex % 2) * offset;
float zOffset = (playerIndex / 2) * offset;
return new Vector3f(baseX + xOffset, 0, baseZ + zOffset);
}
private void movePlayerFigure(Player player) {
int playerIndexOnField = calculatePlayerIndexOnField(player.getFieldID(), player.getId());
String figureName = "PlayerFigure_" + player.getId();
com.jme3.scene.Spatial figure = app.getRootNode().getChild(figureName);
if (figure != null) {
// Berechne das aktuelle Feld basierend auf der Position der Figur
int startFieldID = getFieldIDFromPosition(figure.getLocalTranslation());
int targetFieldID = player.getFieldID();
// Bewege die Figur nur, wenn das Ziel-Feld unterschiedlich ist
if (startFieldID != targetFieldID) {
// Verzögerung vor Start der Animation (z.B. 3 Sekunden)
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// Berechne den Pfad basierend auf den Feld-IDs
List<Vector3f> pathPoints = calculatePath(startFieldID, targetFieldID, playerIndexOnField);
// Starte die Animation entlang des Pfads
animateMovementAlongPath(figure, pathPoints);
}
}, 3000); // Verzögerung von 3000ms (3 Sekunden)
} else {
System.out.println("Figur für Spieler " + player.getId() + " bleibt auf dem gleichen Feld.");
}
} else {
System.err.println("Figur für Spieler " + player.getId() + " nicht gefunden.");
}
}
private int getFieldIDFromPosition(Vector3f position) {
for (int fieldID = 0; fieldID < 40; fieldID++) {
Vector3f fieldPosition = calculateFieldPosition(fieldID, 0);
if (fieldPosition.distance(position) < 0.5f) { // Toleranz für Positionserkennung
return fieldID;
}
}
throw new IllegalArgumentException("Position entspricht keinem gültigen Feld: " + position);
}
/**
* Berechnet den Eckpunkt basierend auf Start- und Zielposition.
*
* @param startPosition Die Startposition der Figur.
* @param targetPosition Die Zielposition der Figur.
* @return Die Position der Ecke, die passiert werden muss.
*/
private Vector3f calculateCornerPosition(Vector3f startPosition, Vector3f targetPosition) {
// Ziel: Immer entlang der Spielfeldkante navigieren
float deltaX = targetPosition.x - startPosition.x;
float deltaZ = targetPosition.z - startPosition.z;
// Überprüfen, ob Bewegung entlang X oder Z-Koordinate zuerst erfolgen soll
if (deltaX != 0 && deltaZ != 0) {
if (Math.abs(deltaX) > Math.abs(deltaZ)) {
// Bewegung entlang X zuerst
return new Vector3f(targetPosition.x, 0, startPosition.z);
} else {
// Bewegung entlang Z zuerst
return new Vector3f(startPosition.x, 0, targetPosition.z);
}
} else {
// Bewegung ist bereits entlang einer Achse (keine Ecke erforderlich)
return targetPosition;
}
}
private List<Vector3f> calculatePath(int startFieldID, int targetFieldID, int playerIndex) {
List<Vector3f> pathPoints = new ArrayList<>();
// Bewegung im Uhrzeigersinn
if (startFieldID < targetFieldID) {
for (int i = startFieldID; i <= targetFieldID; i++) {
// Füge Ecken hinzu, falls sie überschritten werden
if (i == 10 || i == 20 || i == 30 || i == 0) {
pathPoints.add(calculateFieldPosition(i, playerIndex));
}
}
} else {
// Bewegung über das Ende des Spielfelds hinaus (z.B. von 39 zu 5)
for (int i = startFieldID; i < 40; i++) {
if (i == 10 || i == 20 || i == 30 || i == 0) {
pathPoints.add(calculateFieldPosition(i, playerIndex));
}
}
for (int i = 0; i <= targetFieldID; i++) {
if (i == 10 || i == 20 || i == 30 || i == 0) {
pathPoints.add(calculateFieldPosition(i, playerIndex));
}
}
}
// Füge das Ziel hinzu
pathPoints.add(calculateFieldPosition(targetFieldID, playerIndex));
return pathPoints;
}
private int calculatePlayerIndexOnField(int fieldID, int playerID) {
List<Player> playersOnField = playerHandler.getPlayers().stream()
.filter(p -> p.getFieldID() == fieldID)
.toList();
for (int i = 0; i < playersOnField.size(); i++) {
if (playersOnField.get(i).getId() == playerID) {
return i;
}
}
return 0;
}
private void animateMovementAlongPath(com.jme3.scene.Spatial figure, List<Vector3f> pathPoints) {
float animationDurationPerSegment = 2.5f; // Langsamere Animation (2.5 Sekunden pro Segment)
int[] currentSegment = {0};
app.enqueue(() -> {
figure.addControl(new AbstractControl() {
private float elapsedTime = 0.0f;
@Override
protected void controlUpdate(float tpf) {
if (currentSegment[0] >= pathPoints.size() - 1) {
this.setEnabled(false); // Animation abgeschlossen
return;
}
elapsedTime += tpf;
float progress = Math.min(elapsedTime / animationDurationPerSegment, 1.0f);
Vector3f start = pathPoints.get(currentSegment[0]);
Vector3f end = pathPoints.get(currentSegment[0] + 1);
Vector3f interpolatedPosition = start.interpolateLocal(end, progress);
figure.setLocalTranslation(interpolatedPosition);
if (progress >= 1.0f) {
elapsedTime = 0.0f;
currentSegment[0]++;
}
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
// Nicht benötigt
}
});
});
}
@Override
public void receivedEvent(PopUpEvent event) {
if (event.msg().equals("Buy")) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
app.enqueue(() -> {
int field = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
Object fieldObject = app.getGameLogic().getBoardManager().getFieldAtIndex(field);
if (fieldObject instanceof BuildingProperty) {
new BuildingPropertyCard(app).open();
} else if (fieldObject instanceof GateField) {
new GateFieldCard(app).open();
} else if (fieldObject instanceof FoodField) {
new FoodFieldCard(app).open();
}
});
}
}, 2500);
} else if (event.msg().equals("Winner")) {
new WinnerPopUp(app).open();
} else if (event.msg().equals("Looser")) {
new LooserPopUp(app).open();
} else if (event.msg().equals("timeout")) {
new TimeOut(app).open();
} else if (event.msg().equals("tradeRequest")) {
new ConfirmTrade(app).open();
} else if (event.msg().equals("goingToJail")) {
new Gulag(app).open();
} else if (event.msg().equals("NoMoneyWarning")) {
new NoMoneyWarning(app).open();
} else if(event.msg().equals("rent")) {
new Rent(app, ( (NotificationMessage) event.message()).getRentOwner(), ( (NotificationMessage) event.message()).getRentAmount() ).open();
} else if (event.msg().equals("jailtryagain")) {
new GulagInfo(app, 1).open();
} else if (event.msg().equals("jailpay")) {
new GulagInfo(app, 3).open();
} else if (event.msg().equals("tradepos")) {
new AcceptTrade(app, (TradeReply) event.message()).open();
} else if (event.msg().equals("tradeneg")) {
new RejectTrade(app, (TradeReply) event.message()).open();
}
}
@Override
public void receivedEvent(EventCardEvent event) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
app.enqueue(() -> new EventCardPopup(app, event.description()).open());
}
}, 2500);
}
@Override
public void receivedEvent(UpdatePlayerView event) {
this.playerHandler = app.getGameLogic().getPlayerHandler();
for (Player player : playerHandler.getPlayers()) {
movePlayerFigure(player);
}
}
}

View File

@@ -1,237 +1,334 @@
package pp.monopoly.client.gui;
import java.util.Random;
import com.jme3.font.BitmapText;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.simsilica.lemur.*;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.popups.Bankrupt;
import pp.monopoly.game.server.Player;
import pp.monopoly.game.server.PlayerHandler;
import pp.monopoly.message.client.EndTurn;
import pp.monopoly.message.client.RollDice;
import pp.monopoly.notification.ButtonStatusEvent;
import pp.monopoly.notification.DiceRollEvent;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.Sound;
import pp.monopoly.notification.UpdatePlayerView;
/**
* Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
* Die Buttons bewegen den Würfel auf dem Spielfeld.
*/
public class Toolbar extends Dialog {
public class Toolbar extends Dialog implements GameEventListener {
private final MonopolyApp app;
private final Container toolbarContainer;
private final Geometry cube; // Referenz auf den Würfel
private final BitmapText positionText; // Anzeige für die aktuelle Position
private final float boardLimit = 0.95f; // Grenzen des Bretts
private final float stepSize = 0.18f; // Schrittgröße pro Bewegung
private int currentPosition = 0; // Aktuelle Position auf dem Spielfeld
private final int positionsPerSide = 10; // Anzahl der Positionen pro Seite
private final Random random = new Random(); // Zufallsgenerator für den Würfelwurf
private Container overviewContainer;
private Container accountContainer;
private PlayerHandler playerHandler;
private Label imageLabel;
private Label imageLabel2;
private Button diceButton;
private Button tradeButton;
private Button propertyMenuButton;
private Button endTurnButton;
/**
* Konstruktor für die Toolbar.
*
* @param app Die Hauptanwendung (MonopolyApp)
* @param cube Der Würfel, der bewegt werden soll
*/
public Toolbar(MonopolyApp app, Geometry cube) {
private volatile boolean animatingDice = false;
private volatile DiceRollEvent latestDiceRollEvent = null;
public Toolbar(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
this.cube = cube;
// Erstelle die Toolbar
toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y), "toolbar");
app.getGameLogic().addListener(this);
this.playerHandler = app.getGameLogic().getPlayerHandler();
// Setze die Position am unteren Rand und die Breite
toolbarContainer.setLocalTranslation(
0, // Links bündig
200, // Höhe über dem unteren Rand
0 // Z-Ebene
);
toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 200, 0)); // Volle Breite
toolbarContainer = createToolbarContainer();
app.getGuiNode().attachChild(toolbarContainer);
}
private Container createToolbarContainer() {
// Erstelle den Hauptcontainer
Container container = new Container(new SpringGridLayout(Axis.X, Axis.Y), "toolbar");
container.setLocalTranslation(0, 200, 0);
container.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 200, 0));
// Spielerfarbe abrufen
Player currentPlayer = playerHandler.getPlayerById(app.getId());
ColorRGBA playerColor = currentPlayer.getColor().getColor();
// Oberer Balken
Container playerColorBar = new Container();
playerColorBar.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 15, 0)); // Höhe des oberen Balkens
playerColorBar.setBackground(new QuadBackgroundComponent(playerColor));
playerColorBar.setLocalTranslation(0, 210, 3); // Position über der Toolbar
app.getGuiNode().attachChild(playerColorBar);
// Füge Buttons zur Toolbar hinzu
//initializeButtons();
// unterer Balken
Container playerColorBarbot = new Container();
playerColorBarbot.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 10, 0)); // Höhe des oberen Balkens
playerColorBarbot.setBackground(new QuadBackgroundComponent(playerColor));
playerColorBarbot.setLocalTranslation(0, 10, 3); // Position über der Toolbar
app.getGuiNode().attachChild(playerColorBarbot);
// Linker Balken
Container leftBar = new Container();
leftBar.setPreferredSize(new Vector3f(10, 210, 0)); // Breite 10, Höhe 210
leftBar.setBackground(new QuadBackgroundComponent(playerColor));
leftBar.setLocalTranslation(0, 200, 3); // Position am linken Rand
app.getGuiNode().attachChild(leftBar);
// Rechter Balken
Container rightBar = new Container();
rightBar.setPreferredSize(new Vector3f(10, 210, 0)); // Breite 10, Höhe 210
rightBar.setBackground(new QuadBackgroundComponent(playerColor));
rightBar.setLocalTranslation(app.getCamera().getWidth() - 10, 200, 2); // Position am rechten Rand
app.getGuiNode().attachChild(rightBar);
// Übersicht und Konto
accountContainer = container.addChild(new Container());
overviewContainer = container.addChild(new Container());
receivedEvent(new UpdatePlayerView()); // Initiale Aktualisierung
// Würfel-Bereich
container.addChild(createDiceSection());
// Aktionsmenü
Container menuContainer = container.addChild(new Container());
menuContainer.addChild(createTradeButton());
menuContainer.addChild(createPropertyMenuButton());
menuContainer.addChild(createEndTurnButton());
menuContainer.setBackground(createBackground());
return container;
}
// Menü-Container: Ein Nested-Container für Kontostand und "Meine Gulag Frei Karten"
Container accountContainer = toolbarContainer.addChild(new Container());
accountContainer.addChild(new Label("Kontostand", new ElementId("label-Bold")));
accountContainer.addChild(new Label("6666€", new ElementId("label-Text"))); //TODO Variable hier einsetzen
accountContainer.addChild(new Label("Gulag Frei Karten", new ElementId("label-Bold")));
accountContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Add a spacer between accountContainer and overviewContainer
Panel spacer = new Panel(); // Create an empty panel as a spacer
spacer.setPreferredSize(new Vector3f(5, 0, 0)); // Adjust the width as needed
spacer.setBackground(null);
toolbarContainer.addChild(spacer);
// Menü-Container: Ein Container für Übersicht
Container overviewContainer = toolbarContainer.addChild(new Container());
overviewContainer.addChild(new Label("Übersicht", new ElementId("label-Bold")));
overviewContainer.addChild(new Label("„Spieler 1“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
overviewContainer.addChild(new Label("„Spieler 2“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
overviewContainer.addChild(new Label("„Spieler 3“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
overviewContainer.addChild(new Label("„Spieler 4“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
overviewContainer.addChild(new Label("„Spieler 5“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
overviewContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Menü-Container: Ein Container für Würfel
Container diceContainer = toolbarContainer.addChild(new Container());
diceContainer.setPreferredSize(new Vector3f(400, 150, 0));
diceContainer.addChild(new Label("Wo Würfel?", new ElementId("label")));
diceContainer.addChild(addDiceRollButton());
private Container createDiceSection() {
Container diceContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
diceContainer.addChild(createDiceDisplay());
diceContainer.setBackground(null);
diceButton = new Button("Würfeln", new ElementId("button-toolbar"));
diceButton.setPreferredSize(new Vector3f(200, 50, 0));
diceButton.addClickCommands(s -> ifTopDialog(() -> {
diceButton.setEnabled(false);
startDiceAnimation();
app.getGameLogic().send(new RollDice());
app.getGameLogic().playSound(Sound.BUTTON);
}));
diceContainer.addChild(diceButton);
// Menü-Container: Ein Nested-Container für Handeln, Grundstücke und Zug beenden
Container menuContainer = toolbarContainer.addChild(new Container());
menuContainer.addChild(new Button("Handeln"));
menuContainer.addChild(new Button("Grundstücke"));
menuContainer.addChild(new Button("Zug beenden"));
menuContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Füge die Toolbar zur GUI hinzu
app.getGuiNode().attachChild(toolbarContainer);
// Erstelle die Position-Anzeige
positionText = createPositionDisplay();
updatePositionDisplay(); // Initialisiere die Anzeige mit der Startposition
return diceContainer;
}
/**
* Initialisiert die Buttons in der Toolbar.
*/
private void initializeButtons() {
addTradeMenuButton(); // Bewegung nach vorne
addEndTurnButton(); // Bewegung nach hinten
addDiceRollButton(); // Würfel-Button
private Container createDiceDisplay() {
Container horizontalContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
horizontalContainer.setPreferredSize(new Vector3f(200, 150, 0));
horizontalContainer.setBackground(null);
imageLabel = createDiceLabel("Pictures/dice/one.png");
imageLabel2 = createDiceLabel("Pictures/dice/two.png");
horizontalContainer.addChild(createDiceContainer(imageLabel));
horizontalContainer.addChild(createDiceContainer(imageLabel2));
return horizontalContainer;
}
/**
* Fügt einen Button mit einer Bewegung hinzu.
*
* @param label Der Text des Buttons
* @param step Schrittweite (+1 für vorwärts, -1 für rückwärts)
*/
/*private void addButton(String label, int step) {
Button button = new Button(label);
button.setPreferredSize(new Vector3f(150, 50, 0)); // Größe der Buttons
button.addClickCommands(source -> moveCube(step));
toolbarContainer.addChild(button);
}*/
/**
* Fügt den Würfel-Button hinzu, der die Figur entsprechend der gewürfelten Zahl bewegt.
*/
private Button addDiceRollButton() {
Button diceButton = new Button("Würfeln");
diceButton.setPreferredSize(new Vector3f(50, 20, 0));
diceButton.addClickCommands(source -> rollDice());
toolbarContainer.addChild(diceButton);
return diceButton;
private Label createDiceLabel(String iconPath) {
Label label = new Label("");
IconComponent icon = new IconComponent(iconPath);
icon.setIconSize(new Vector2f(100, 100));
label.setIcon(icon);
return label;
}
private void addTradeMenuButton() {
Button diceButton = new Button("Handeln");
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
diceButton.addClickCommands(source -> rollDice());
toolbarContainer.addChild(diceButton);
private Container createDiceContainer(Label label) {
Container container = new Container();
container.setBackground(null);
container.setPreferredSize(new Vector3f(100, 150, 0));
container.addChild(label);
return container;
}
private void addEndTurnButton() {
Button diceButton = new Button("Grundstücke");
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
diceButton.addClickCommands(source -> rollDice());
toolbarContainer.addChild(diceButton);
private Button createTradeButton() {
tradeButton = new Button("Handeln", new ElementId("button-toolbar"));
tradeButton.setPreferredSize(new Vector3f(150, 50, 0));
tradeButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
new ChoosePartner(app).open();
}));
return tradeButton;
}
private void addPropertyMenuButton() {
Button diceButton = new Button("Zug beenden");
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
diceButton.addClickCommands(source -> rollDice());
toolbarContainer.addChild(diceButton);
private Button createPropertyMenuButton() {
propertyMenuButton = new Button("Grundstücke", new ElementId("button-toolbar"));
propertyMenuButton.setPreferredSize(new Vector3f(150, 50, 0));
propertyMenuButton.setFontSize(30);
propertyMenuButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
new BuildingAdminMenu(app).open();
}));
return propertyMenuButton;
}
/**
* Simuliert einen Würfelwurf und bewegt die Figur entsprechend.
*/
private void rollDice() {
int diceRoll = random.nextInt(6) + 1; // Zahl zwischen 1 und 6
System.out.println("Gewürfelt: " + diceRoll);
moveCube(diceRoll); // Bewege die Figur um die gewürfelte Zahl
private Button createEndTurnButton() {
endTurnButton = new Button("Zug beenden", new ElementId("button-toolbar"));
endTurnButton.setFontSize(28);
endTurnButton.setPreferredSize(new Vector3f(150, 50, 0));
endTurnButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
if (app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getAccountBalance() < 0) {
new Bankrupt(app).open();
} else {
app.getGameLogic().send(new EndTurn());
receivedEvent(new ButtonStatusEvent(false));
}
}));
return endTurnButton;
}
/**
* Bewegt den Würfel basierend auf der aktuellen Position auf dem Brett.
*
* @param step Schrittweite (+1 für vorwärts, -1 für rückwärts oder andere Werte)
*/
private void moveCube(int step) {
currentPosition = (currentPosition + step + 4 * positionsPerSide) % (4 * positionsPerSide);
Vector3f newPosition = calculatePosition(currentPosition);
cube.setLocalTranslation(newPosition);
updatePositionDisplay(); // Aktualisiere die Positionsanzeige
System.out.println("Würfelposition: " + newPosition + " (Feld-ID: " + currentPosition + ")");
private QuadBackgroundComponent createBackground() {
return new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f));
}
/**
* Berechnet die neue Position des Würfels basierend auf der aktuellen Brettseite und Position.
*
* @param position Aktuelle Position auf dem Spielfeld
* @return Die berechnete Position als Vector3f
*/
private Vector3f calculatePosition(int position) {
int side = position / positionsPerSide; // Seite des Bretts (0 = unten, 1 = rechts, 2 = oben, 3 = links)
int offset = position % positionsPerSide; // Position auf der aktuellen Seite
private void startDiceAnimation() {
animatingDice = true;
long startTime = System.currentTimeMillis();
new Thread(() -> {
try {
animateDice(startTime);
animatingDice = false;
if (latestDiceRollEvent != null) {
showFinalDiceResult(latestDiceRollEvent);
}
} catch (InterruptedException e) {
System.err.println("Dice animation interrupted: " + e.getMessage());
}
}).start();
}
private void animateDice(long startTime) throws InterruptedException {
int[] currentFace = {1};
while (System.currentTimeMillis() - startTime < 2000) { // Animation duration
currentFace[0] = (currentFace[0] % 6) + 1;
String rotatingImage1 = diceToString(currentFace[0]);
String rotatingImage2 = diceToString((currentFace[0] % 6) + 1);
app.enqueue(() -> {
setDiceIcon(imageLabel, rotatingImage1);
setDiceIcon(imageLabel2, rotatingImage2);
});
Thread.sleep(100); // Time between frame updates
}
}
private void showFinalDiceResult(DiceRollEvent event) {
app.enqueue(() -> {
setDiceIcon(imageLabel, diceToString(event.a()));
setDiceIcon(imageLabel2, diceToString(event.b()));
});
}
private void setDiceIcon(Label label, String imagePath) {
IconComponent icon = new IconComponent(imagePath);
icon.setIconSize(new Vector2f(80, 80)); // Set consistent dice size
label.setIcon(icon);
}
switch (side) {
case 0: // Unten (positive x-Achse)
return new Vector3f(-boardLimit + offset * stepSize, 0.1f, -boardLimit + 0.05f);
case 1: // Rechts (positive z-Achse)
return new Vector3f(boardLimit - 0.05f, 0.1f, -boardLimit + offset * stepSize);
case 2: // Oben (negative x-Achse)
return new Vector3f(boardLimit - offset * stepSize, 0.1f, boardLimit - 0.05f);
case 3: // Links (negative z-Achse)
return new Vector3f(-boardLimit + 0.05f, 0.1f, boardLimit - offset * stepSize);
default:
throw new IllegalArgumentException("Ungültige Position: " + position);
private String diceToString(int i) {
switch (i) {
case 1: return "Pictures/dice/one.png";
case 2: return "Pictures/dice/two.png";
case 3: return "Pictures/dice/three.png";
case 4: return "Pictures/dice/four.png";
case 5: return "Pictures/dice/five.png";
case 6: return "Pictures/dice/six.png";
default: throw new IllegalArgumentException("Invalid dice number: " + i);
}
}
/**
* Erstellt die Anzeige für die aktuelle Position.
*
* @return Das BitmapText-Objekt für die Anzeige
*/
private BitmapText createPositionDisplay() {
BitmapText text = new BitmapText(app.getAssetManager().loadFont("Interface/Fonts/Default.fnt"), false);
text.setSize(20); // Schriftgröße
text.setLocalTranslation(10, app.getCamera().getHeight() - 10, 0); // Oben links
app.getGuiNode().attachChild(text);
return text;
@Override
public void receivedEvent(DiceRollEvent event) {
latestDiceRollEvent = event;
}
/**
* Aktualisiert die Anzeige für die aktuelle Position.
*/
private void updatePositionDisplay() {
positionText.setText("Feld-ID: " + currentPosition);
@Override
public void receivedEvent(UpdatePlayerView event) {
playerHandler = app.getGameLogic().getPlayerHandler();
System.out.println("Update Player View");
accountContainer.clearChildren();
overviewContainer.clearChildren();
accountContainer.addChild(new Label("Kontostand", new ElementId("label-toolbar")));
accountContainer.addChild(new Label(
playerHandler.getPlayerById(app.getId()).getAccountBalance() + " EUR",
new ElementId("label-account")
));
accountContainer.addChild(new Label("Gulag Karten", new ElementId("label-toolbar")));
accountContainer.addChild(new Label(
playerHandler.getPlayerById(app.getId()).getNumJailCard() + "",
new ElementId("label-account")
));
accountContainer.setBackground(null);
overviewContainer.addChild(new Label("Übersicht", new ElementId("label-toolbar")));
for (Player player : playerHandler.getPlayers()) {
if (player.getId() != app.getId()) {
// Spielerfarbe abrufen
ColorRGBA playerColor = (player.getColor().getColor());
// Label für den Spieler erstellen
Label playerLabel = new Label(
player.getName() + ": " + player.getAccountBalance() + " EUR",
new ElementId("label-Text")
);
// Farbe setzen
playerLabel.setColor(playerColor);
// Label zum Container hinzufügen
overviewContainer.addChild(playerLabel);
}
}
overviewContainer.setBackground(null);
}
/**
* Entfernt die Toolbar.
*/
public void remove() {
@Override
public void receivedEvent(ButtonStatusEvent event) {
boolean enabled = event.buttonsEnabled();
diceButton.setEnabled(enabled);
tradeButton.setEnabled(enabled);
propertyMenuButton.setEnabled(enabled);
endTurnButton.setEnabled(enabled);
}
@Override
public void close() {
app.getGuiNode().detachChild(toolbarContainer);
app.getGuiNode().detachChild(positionText);
super.close();
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
@Override
public void update() {
receivedEvent(new UpdatePlayerView());
super.update();
}
}

View File

@@ -0,0 +1,309 @@
package pp.monopoly.client.gui;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList;
import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId;
import com.simsilica.lemur.text.DocumentModel;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.message.client.TradeOffer;
import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound;
import java.util.HashSet;
import java.util.Set;
public class TradeMenu extends Dialog {
private final MonopolyApp app;
private final TradeHandler tradeHandler;
private final Container mainContainer;
private Geometry background;
private Selector<String> leftBuildingSelector, leftSpecialCardSelector;
private Selector<String> rightBuildingSelector, rightSpecialCardSelector;
private TextField leftSelectionsField, rightSelectionsField;
private TextField leftCurrencyInput, rightCurrencyInput;
private VersionedReference<Set<Integer>> leftBuildingRef, rightBuildingRef;
private VersionedReference<DocumentModel> leftCurrencyRef, rightCurrencyRef;
private VersionedReference<Set<Integer>> leftCardRef, rightCardRef;
private Set<String> rightselBuildings = new HashSet<>();
private Set<String> leftselBuildings = new HashSet<>();
private static final ColorRGBA TRANSLUCENT_WHITE = new ColorRGBA(1, 1, 1, 0.5f);
public TradeMenu(MonopolyApp app, TradeHandler tradeHandler) {
super(app.getDialogManager());
this.app = app;
this.tradeHandler = tradeHandler;
addBackgroundImage();
mainContainer = createMainContainer();
app.getGuiNode().attachChild(mainContainer);
positionMainContainer();
initializeReferences();
}
private Container createMainContainer() {
Container container = new Container(new SpringGridLayout(Axis.Y, Axis.X));
container.setPreferredSize(new Vector3f(1200, 800, 0));
container.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE));
container.addChild(createHeader());
container.addChild(createMainContent());
return container;
}
private Label createHeader() {
Label header = new Label("Handelsmenü", new ElementId("label-Bold"));
header.setFontSize(50);
header.setInsets(new Insets3f(10, 10, 10, 10));
header.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE));
return header;
}
private Container createMainContent() {
Container mainContent = new Container(new SpringGridLayout(Axis.X, Axis.Y));
mainContent.setPreferredSize(new Vector3f(1200, 700, 0));
mainContent.addChild(createTradeColumn("Wähle Handelsobjekt:", true));
mainContent.addChild(createMiddleSection());
mainContent.addChild(createTradeColumn("Wähle Zielobjekt:", false));
return mainContent;
}
private void setTrades() {
tradeHandler.setOfferedAmount(Integer.parseInt(leftCurrencyInput.getText()));
tradeHandler.setRequestedAmount(Integer.parseInt(rightCurrencyInput.getText()));
tradeHandler.setOfferedJailCards(Integer.parseInt(leftSpecialCardSelector.getSelectedItem()));
tradeHandler.setRequestedJailCards(Integer.parseInt(rightSpecialCardSelector.getSelectedItem()));
Set<PropertyField> offeredProperties = new HashSet<>();
for (String propertyString : leftselBuildings) {
offeredProperties.add( (PropertyField) app.getGameLogic().getBoardManager().getFieldByName(propertyString));
}
Set<PropertyField> requestedProperties = new HashSet<>();
for (String propertyString : rightselBuildings) {
requestedProperties.add( (PropertyField) app.getGameLogic().getBoardManager().getFieldByName(propertyString));
}
tradeHandler.setOfferedProperties(offeredProperties);
tradeHandler.setRequestedProperties(requestedProperties);
}
private Container createTradeColumn(String label, boolean isLeft) {
Container column = new Container(new SpringGridLayout(Axis.Y, Axis.X));
column.setBackground(new QuadBackgroundComponent(ColorRGBA.White));
Label columnLabel = column.addChild(new Label(label));
columnLabel.setFontSize(24);
columnLabel.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE));
column.addChild(new Label("Gebäude:"));
Selector<String> buildingSelector = createPropertySelector(isLeft);
column.addChild(buildingSelector);
column.addChild(new Label("Währung:"));
TextField currencyInput = createCurrencyInput();
column.addChild(currencyInput);
column.addChild(new Label("Sonderkarten:"));
Selector<String> specialCardSelector = createSpecialCardSelector(isLeft);
styleSelector(specialCardSelector);
column.addChild(specialCardSelector);
assignSelectors(buildingSelector, specialCardSelector, currencyInput, isLeft);
return column;
}
private Selector<String> createPropertySelector(boolean isLeft) {
VersionedList<String> properties = new VersionedList<>();
for (PropertyField field : getPropertyFields(isLeft)) {
properties.add(field.getName());
}
Selector<String> selector = new Selector<>(properties, "glass");
styleSelector(selector);
return selector;
}
private Selector<String> createSpecialCardSelector(boolean isLeft) {
VersionedList<String> numbers = new VersionedList<>();
for (int i = 0; i <= app.getGameLogic().getPlayerHandler().getPlayerById(isLeft ? tradeHandler.getReceiver().getId() : tradeHandler.getSender().getId()).getNumJailCard(); i++) {
numbers.add(i + "");
}
Selector<String> selector = new Selector<>(numbers, "glass");
styleSelector(selector);
return selector;
}
private Iterable<PropertyField> getPropertyFields(boolean isLeft) {
return app.getGameLogic()
.getBoardManager()
.getPropertyFields(app.getGameLogic()
.getPlayerHandler()
.getPlayerById(isLeft ? tradeHandler.getReceiver().getId() : tradeHandler.getSender().getId())
.getProperties());
}
private TextField createCurrencyInput() {
TextField currencyInput = new TextField("0");
styleTextField(currencyInput);
return currencyInput;
}
private Container createMiddleSection() {
Container middleSection = new Container(new SpringGridLayout(Axis.Y, Axis.X));
middleSection.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)));
Label middleLabelTop = middleSection.addChild(new Label("Gebäude: Währung: Sonderkarten:"));
middleLabelTop.setFontSize(24);
middleLabelTop.setInsets(new Insets3f(5, 5, 5, 5));
leftSelectionsField = middleSection.addChild(new TextField(""));
leftSelectionsField.setPreferredSize(new Vector3f(600, 50, 0));
Container buttons = middleSection.addChild(new Container(new SpringGridLayout()));
Button cancel = new Button("Abbrechen");
cancel.addClickCommands(s -> ifTopDialog(() -> {
close();
app.getGameLogic().playSound(Sound.BUTTON);
}));
Button trade = new Button("Handeln");
trade.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
setTrades();
app.getGameLogic().send(new TradeOffer(tradeHandler));
close();
}));
buttons.addChild(cancel);
buttons.addChild(trade);
Label middleLabelBottom = middleSection.addChild(new Label("Gebäude: Währung: Sonderkarten:"));
middleLabelBottom.setFontSize(24);
middleLabelBottom.setInsets(new Insets3f(5, 5, 5, 5));
rightSelectionsField = middleSection.addChild(new TextField(""));
rightSelectionsField.setPreferredSize(new Vector3f(600, 50, 0));
return middleSection;
}
private void styleSelector(Selector<String> selector) {
selector.setInsets(new Insets3f(5, 10, 5, 10));
selector.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
}
private void styleTextField(TextField textField) {
textField.setInsets(new Insets3f(5, 10, 5, 10));
textField.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
textField.setPreferredSize(new Vector3f(300, 30, 0));
}
private void assignSelectors(Selector<String> buildingSelector, Selector<String> specialCardSelector, TextField currencyInput, boolean isLeft) {
if (isLeft) {
leftBuildingSelector = buildingSelector;
leftSpecialCardSelector = specialCardSelector;
leftCurrencyInput = currencyInput;
} else {
rightBuildingSelector = buildingSelector;
rightSpecialCardSelector = specialCardSelector;
rightCurrencyInput = currencyInput;
}
}
private void positionMainContainer() {
mainContainer.setLocalTranslation(
(app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + mainContainer.getPreferredSize().y) / 2,
7
);
}
private void addBackgroundImage() {
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
background = new Geometry("Background", quad);
Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
backgroundMaterial.setTexture("ColorMap", backgroundImage);
background.setMaterial(backgroundMaterial);
background.setLocalTranslation(0, 0, 6);
app.getGuiNode().attachChild(background);
}
private void initializeReferences() {
leftBuildingRef = leftBuildingSelector.getSelectionModel().createReference();
leftCardRef = leftSpecialCardSelector.getSelectionModel().createReference();
leftCurrencyRef = leftCurrencyInput.getDocumentModel().createReference();
rightBuildingRef = rightBuildingSelector.getSelectionModel().createReference();
rightCardRef = rightSpecialCardSelector.getSelectionModel().createReference();
rightCurrencyRef = rightCurrencyInput.getDocumentModel().createReference();
}
@Override
public void update(float delta) {
if (leftBuildingRef.update() || leftCardRef.update() || leftCurrencyRef.update()) {
updateSelections(leftSelectionsField, leftBuildingSelector, leftCurrencyInput, leftSpecialCardSelector, true);
}
if (rightBuildingRef.update() || rightCardRef.update() || rightCurrencyRef.update()) {
updateSelections(rightSelectionsField, rightBuildingSelector, rightCurrencyInput, rightSpecialCardSelector, false);
}
}
private void updateSelections(TextField target, Selector<String> building, TextField currency, Selector<String> card, boolean isLeft) {
StringBuilder buildingText = new StringBuilder();
if (isLeft) {
if (leftselBuildings.contains(building.getSelectedItem())) {
leftselBuildings.remove(building.getSelectedItem()); // Remove if already selected
} else {
leftselBuildings.add(building.getSelectedItem()); // Add if not already selected
}
for (String property : leftselBuildings) {
buildingText.append(property);
}
} else {
if (rightselBuildings.contains(building.getSelectedItem())) {
rightselBuildings.remove(building.getSelectedItem()); // Remove if already selected
} else {
rightselBuildings.add(building.getSelectedItem()); // Add if not already selected
}
for (String property : rightselBuildings) {
buildingText.append(property);
}
}
String currencyText = currency.getText() != null ? currency.getText().trim() : "";
String cardText = card.getSelectedItem() != null ? card.getSelectedItem() : "";
target.setText(String.join(" | ", buildingText, currencyText, cardText));
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
@Override
public void close() {
app.getGuiNode().detachChild(mainContainer);
app.getGuiNode().detachChild(background);
super.close();
}
}

View File

@@ -0,0 +1,37 @@
package pp.monopoly.client.gui;
import com.simsilica.lemur.Slider;
import pp.monopoly.client.GameMusic;
/**
* The VolumeSlider class represents the Volume Slider in the Menu.
* It extends the Slider class and provides functionalities for setting the music volume,
* with the help of the Slider in the GUI
*/
public class VolumeSlider extends Slider {
private final pp.monopoly.client.GameMusic music;
private double vol;
/**
* Constructs the Volume Slider for the Menu dialog
* @param music the music instance
*/
public VolumeSlider(GameMusic music) {
super();
this.music = music;
vol = GameMusic.volumeInPreferences();
getModel().setPercent(vol);
}
/**
* when triggered it updates the volume to the value set with the slider
*/
public void update() {
if (vol != getModel().getPercent()) {
vol = getModel().getPercent();
music.setVolume( (float) vol);
}
}
}

View File

@@ -0,0 +1,504 @@
/*
* $Id$
*
* Copyright (c) 2014, Simsilica, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package pp.monopoly.client.gui.hslider;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.FillMode;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.Panel;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.GuiControl;
import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.grid.GridModel;
import com.simsilica.lemur.style.Attributes;
import com.simsilica.lemur.style.ElementId;
import com.simsilica.lemur.style.StyleDefaults;
import com.simsilica.lemur.style.Styles;
/**
*
* @author Paul Speed
*/
public class GridPanel extends Panel {
public static final String ELEMENT_ID = "grid";
private GridModel<Panel> model;
private VersionedReference<GridModel<Panel>> modelRef;
private SpringGridLayout layout;
private int visibleRows = 5;
private int visibleColumns = 5;
private int row = 0;
private int column = 0;
private Float alpha; // for setting to new children
private Float[] columnwidths = null;
private Float[] rowheight = null;
private boolean widthsupdate = false;
private HAlignment [] columnHalignement = null;
public GridPanel(GridModel<Panel> model ) {
this(true, model, new ElementId(ELEMENT_ID), null);
}
public GridPanel(GridModel<Panel> model, String style ) {
this(true, model, new ElementId(ELEMENT_ID), style);
}
public GridPanel(GridModel<Panel> model, ElementId elementId, String style ) {
this(true, model, elementId, style);
}
protected GridPanel(boolean applyStyles, GridModel<Panel> model,
ElementId elementId, String style ) {
super(false, elementId, style);
this.layout = new SpringGridLayout(Axis.Y, Axis.X,
FillMode.ForcedEven,
FillMode.ForcedEven);
getControl(GuiControl.class).setLayout(layout);
if( applyStyles ) {
Styles styles = GuiGlobals.getInstance().getStyles();
styles.applyStyles(this, elementId, style);
}
setModel(model);
}
// change the layout if necessary
public void setLayout(SpringGridLayout lay) {
this.layout = lay;
getControl(GuiControl.class).getLayout().clearChildren();
getControl(GuiControl.class).setLayout(layout);
this.modelRef = null;
if( this.model != null ) {
this.modelRef = model.createReference();
refreshGrid();
}
}
@StyleDefaults(ELEMENT_ID)
public static void initializeDefaultStyles( Attributes attrs ) {
}
public void setModel( GridModel<Panel> model ) {
if( this.model == model ) {
return;
}
if( this.model != null ) {
// Clear the old panel
getControl(GuiControl.class).getLayout().clearChildren();
this.modelRef = null;
}
this.model = model;
if( this.model != null ) {
this.modelRef = model.createReference();
refreshGrid();
}
}
public GridModel<Panel> getModel() {
return model;
}
public void setRow( int row ) {
setLocation(row, column);
}
public int getRow() {
return row;
}
public void setColumn( int column ) {
setLocation(row, column);
}
public int getColumn() {
return column;
}
public Panel getCell( int r, int c ) {
r = r - row;
c = c - column;
if( r < 0 || c < 0 || r >= visibleRows || c >= visibleColumns ) {
return null;
}
return (Panel)layout.getChild(r, c);
}
public void setLocation( int row, int column ) {
if( this.row == row && this.column == column ) {
return;
}
this.row = row;
this.column = column;
refreshGrid();
}
public void setVisibleSize( int rows, int columns ) {
this.visibleRows = rows;
this.visibleColumns = columns;
getControl(GuiControl.class).getLayout().clearChildren();
refreshGrid();
}
public void setVisibleRows( int rows ) {
setVisibleSize(rows, visibleColumns);
}
public int getVisibleRows() {
return visibleRows;
}
public void setVisibleColumns( int columns ) {
setVisibleSize(visibleRows, columns);
}
public int getVisibleColumns() {
return visibleColumns;
}
public void setAlpha( float alpha, boolean recursive ) {
this.alpha = alpha;
super.setAlpha(alpha, recursive);
}
protected void refreshGrid() {
widthsupdate = false;
if( model == null ) {
getControl(GuiControl.class).getLayout().clearChildren();
return;
}
for( int r = row; r < row + visibleRows; r++ ) {
for( int c = column; c < column + visibleColumns; c++ ) {
Node existing = layout.getChild(r-row, c-column);
if( r < 0 || r >= model.getRowCount() || c < 0 || c >= model.getColumnCount() ) {
// Out of bounds
layout.addChild(null, r-row, c-column);
} else {
Panel child = model.getCell(r, c, (Panel)existing);
// we check if there is a size for either rowheight or columnwidth stored
Float ytemp = null;
Float xtemp = null;
if (columnwidths !=null) {
if (columnwidths.length > c) {
if (columnwidths[c] != null) xtemp = columnwidths[c];
}
}
if (rowheight != null) {
if (rowheight.length > r) {
if (rowheight[r] !=null) ytemp = rowheight[r];
}
}
// and only if, we set the preferred size
if (ytemp !=null || xtemp != null) {
child.setPreferredSize(null);
if (xtemp != null) child.setPreferredSize(child.getPreferredSize().clone().setX(xtemp));
if (ytemp !=null) child.setPreferredSize(child.getPreferredSize().clone().setY(ytemp));
}
if (columnHalignement != null) {
if (columnHalignement.length > c) {
if (columnHalignement[c] != null) {
// we only set the alignement for "text" elements attached to the listbox
// for others e.g. progressbar etc. we should call the element and do the changes there
if (child instanceof Button) ((Button) child).setTextHAlignment(columnHalignement[c]);
if (child instanceof Label) ((Label) child).setTextHAlignment(columnHalignement[c]);
if (child instanceof TextField)
((TextField) child).setTextHAlignment(columnHalignement[c]);
} else if (child instanceof Button) ((Button) child).setTextHAlignment(HAlignment.Left);
} else if (child instanceof Button) ((Button) child).setTextHAlignment(HAlignment.Left);
} else if (child instanceof Button) ((Button) child).setTextHAlignment(HAlignment.Left);
if( child != existing ) {
// Make sure new children pick up the alpha of the container
if( alpha != null && alpha != 1 ) {
child.setAlpha(alpha);
}
layout.addChild(child, r-row, c-column);
}
}
}
}
}
@Override
public void updateLogicalState( float tpf ) {
super.updateLogicalState(tpf);
if( modelRef.update() ) {
refreshGrid();
}
if (widthsupdate) refreshGrid();
}
@Override
public String toString() {
return getClass().getName() + "[elementId=" + getElementId() + "]";
}
public Float[] getColumnwidths() {
return columnwidths;
}
public Float[] getRowheights() {
return rowheight;
}
public void setRowheight(Float rowheight, int rownumber_starting_with_0){
// adds or replaces a columnwidth
if (rownumber_starting_with_0 < 0) return;
int size = rownumber_starting_with_0+1;
if (this.rowheight != null) {
size = Math.max(size, this.rowheight.length);
}
preparegridsizes(size,false);
setcheckedsize(rowheight,rownumber_starting_with_0,true,true);
}
public void setColumnwidths(Float columnwidth, int columnnumber_starting_with_0) {
// adds or replaces a columnwidth
if (columnnumber_starting_with_0 <0) return;
int size = columnnumber_starting_with_0+1;
if (this.columnwidths != null) {
size = Math.max(size, this.columnwidths.length);
}
preparegridsizes(size,true);
setcheckedsize(columnwidth,columnnumber_starting_with_0,true,false);
}
public void setRowheight (Float[] rowheights_or_null) {
// replaces the given rowheights and only keep the number of rows given
setRowheight(rowheights_or_null,true);
}
public void setColumnwidths (Float[] columnwidths_or_null) {
// replaces the given columnwidths and only keep the number of columns given
setColumnwidths(columnwidths_or_null,true);
}
public void setRowheight(Float[] rowheights_or_null, boolean write_null_values) {
// replaces the given rowheights and only keep the number of rows given
// null values either overwrite or will be ignored
Integer tmp = null;
if (rowheights_or_null != null) tmp = rowheights_or_null.length;
if (preparegridsizes(tmp,false)) {
for (int i = 0; i <tmp;i++) {
setcheckedsize(rowheights_or_null[i],i,write_null_values,true);
}
}
}
public void setColumnwidths(Float[] columnwidths_or_null, boolean write_null_values) {
// replaces the given columnwidths_or_null and only keep the number of columns given
// null values either overwrite or will be ignored
Integer tmp = null;
if (columnwidths_or_null != null) tmp = columnwidths_or_null.length;
if (preparegridsizes(tmp,true)) {
for (int i = 0; i <tmp;i++) {
setcheckedsize(columnwidths_or_null[i],i,write_null_values,false);
}
}
}
private boolean preparegridsizes(Integer givenfieldsize, boolean width) {
// prepares and adjust the size of the field(s) that hold columnwidth or rowheights
if (givenfieldsize == null) {
if (width) { //either columns or rows will be set null
columnwidths =null;
} else {
rowheight = null;
}
for (Spatial p: this.getChildren()) {
Panel x = (Panel) p;
x.setPreferredSize(null); //we set all sizes to 0 as we will recalculate them with next update
}
widthsupdate = true;
return false; // no more activity needed
} else {
Float[] tmp;
tmp = new Float[givenfieldsize];
if (width) {
if (columnwidths == null) {
columnwidths = tmp;
return true;
}
int i = 0;
for (Float z:columnwidths) {
tmp[i] =z;
i++;
if (i>= givenfieldsize) break;
}
columnwidths = tmp; // we get what we have
} else {
if (rowheight == null) {
rowheight = tmp;
return true;
}
int i = 0;
for (Float z:rowheight) {
tmp[i] =z;
i++;
if (i>= givenfieldsize) break;
}
rowheight = tmp; // we get what we have
}
return true;
}
}
private void setcheckedsize(Float size, int row_or_column, boolean override, boolean i_am_a_row) {
if (override || (size !=null)) {
if (i_am_a_row) {
rowheight[row_or_column] = size;
} else {
columnwidths[row_or_column] = size;
}
widthsupdate = true;
}
}
// public void setRowheight(Float rowheight_or_null){
// if (rowheight_or_null<=0) return;
// this.rowheight = rowheight_or_null;
// widthsupdate = true;
// }
public void setHalignements(HAlignment[] hals) {
setHalignements(hals,false);
}
public void setHalignements(HAlignment[] hals, boolean overridestandard) {
if (checkexistinghal(hals)) {
int i =0;
for (HAlignment z:hals) {
setHalignementchecked(z,i,overridestandard);
i++;
if (i>=columnHalignement.length) return; // we ignore given HAlignement that is out of column bound
}
if (!overridestandard ) return;
for (int u = i; u<columnHalignement.length;u++) {
setHalignementchecked(null,u,overridestandard); // override existing HAlignements
}
}
}
public void setHalignements(HAlignment hal, int column) {
checkexistinghal(new HAlignment[]{HAlignment.Center});
if (column < columnHalignement.length) setHalignementchecked(hal,column,true);
}
private void setHalignementchecked(HAlignment hal, int column,boolean override) {
if (override || (hal !=null)) {
columnHalignement[column] = hal;
widthsupdate = true;
}
}
private boolean checkexistinghal(HAlignment[] givenfield) {
// delete the given Halignements
if (givenfield == null) {
columnHalignement =null;
for (Spatial p: this.getChildren()) {
Button x = (Button)((Panel) p);
x.setTextHAlignment(HAlignment.Left); //standard HAlignement
}
widthsupdate = true;
return false;
}
// or prepare if we have no columnHalignement yet
HAlignment[] tmp;
if (columnHalignement == null) {
tmp = new HAlignment[model.getColumnCount()];
columnHalignement = tmp;
} else {
if (!(columnHalignement.length ==model.getColumnCount() )) {
tmp = new HAlignment[model.getColumnCount()];
int i = 0;
for (HAlignment z:columnHalignement) {
tmp[i] =z;
i++;
if (i>=model.getColumnCount()) break;
}
columnHalignement = tmp;
}
}
return true;
}
public HAlignment[] getColumnHalignement() {
return columnHalignement;
}
}

View File

@@ -0,0 +1,135 @@
/*
* $Id$
*
* Copyright (c) 2014, Simsilica, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package pp.monopoly.client.gui.hslider;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
import com.simsilica.lemur.core.VersionedObject;
import com.simsilica.lemur.core.VersionedReference;
/**
*
* @author Paul Speed
*/
public class VersionedList<T> extends AbstractList<T>
implements VersionedObject<List<T>> {
private long version = 0;
private List<T> list;
protected VersionedList(List<T> items, boolean copy ) {
if( copy ) {
list = new ArrayList<T>();
list.addAll(items);
} else {
this.list = items;
}
}
public VersionedList() {
this(new ArrayList<T>(), false);
}
public VersionedList(List<T> items ) {
this(items, true);
}
/**
* Wraps a list in a VersionedList instead of copying it.
* This is useful for cases where a VersionedList is required
* but strict versioning is not, for example, passing a static list
* to a ListBox. Changes to the wrapped list obviously don't
* trigger version changes in the wrapper. Only changes through
* the wrapper will increment the version.
*/
public static <T> VersionedList<T> wrap( List<T> list ) {
return new VersionedList<T>(list, false);
}
public void incrementVersion() { // changed this to public
version++;
}
@Override
public long getVersion() {
return version;
}
@Override
public List<T> getObject() {
return this;
}
@Override
public VersionedReference<List<T>> createReference() {
return new VersionedReference<List<T>>(this);
}
@Override
public T get( int i ) {
return list.get(i);
}
@Override
public int size() {
return list.size();
}
@Override
public T set( int i, T val ) {
T result = list.set(i, val);
incrementVersion();
return result;
}
@Override
public void add( int i, T val ) {
list.add(i, val);
incrementVersion();
}
@Override
public T remove( int i ) {
T result = list.remove(i);
incrementVersion();
return result;
}
}

View File

@@ -0,0 +1,125 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.notification.Sound;
/**
* Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn
*/
public class AcceptTrade extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container noMoneyWarningContainer;
private final Container backgroundContainer;
public AcceptTrade(MonopolyApp app, TradeReply msg) {
super(app.getDialogManager());
this.app = app;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Warnung
noMoneyWarningContainer = new Container();
noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Handel angenommen!", new ElementId("warning-title")));
gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der im Popup steht
Container textContainer = noMoneyWarningContainer.addChild(new Container());
textContainer.addChild(new Label("Du hast Spieler"+ msg.getTradeHandler().getReceiver().getName() + "einen Handel vorgeschlagen", new ElementId("label-Text")));
textContainer.addChild(new Label("", new ElementId("label-Text")));
textContainer.addChild(new Label("Der Handel wurde angenommen", new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Passt den textContainer an die Größe des bankruptContainers an
textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
// Beenden-Button
Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Popup
noMoneyWarningContainer.setLocalTranslation(
(app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(noMoneyWarningContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Closes the menu and removes the GUI elements.
*/
@Override
public void close() {
app.getGuiNode().detachChild(noMoneyWarningContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
super.close();
}
@Override
public void escape() {
close();
}
}

View File

@@ -0,0 +1,118 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
/**
* Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn
*/
public class Bankrupt extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container bankruptContainer;
private final Container backgroundContainer;
public Bankrupt(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Warnung
bankruptContainer = new Container();
bankruptContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
bankruptContainer.setPreferredSize(new Vector3f(550,250,10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
backgroundContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label gateFieldTitle = bankruptContainer.addChild(new Label("Vorsicht !", new ElementId("warning-title")));
gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der im Popup steht
Container textContainer = bankruptContainer.addChild(new Container());
textContainer.addChild(new Label("Du hast noch einen negativen Kontostand. Wenn du jetzt deinen Zug beendest, gehst du Bankrott und verlierst das Spiel!", new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Passt den textContainer an die Größe des bankruptContainers an
textContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(-250,-200,0));
// Beenden-Button
Button quitButton = bankruptContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> ifTopDialog(this::close));
// Zentriere das Popup
bankruptContainer.setLocalTranslation(
(app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(bankruptContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Closes the menu and removes the GUI elements.
*/
@Override
public void close() {
app.getGuiNode().detachChild(bankruptContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
super.close();
}
@Override
public void escape() {
close();
}
}

View File

@@ -1,10 +1,7 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
@@ -12,41 +9,43 @@ import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.message.client.BuyPropertyResponse;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.notification.Sound;
/**
* TODO Kommentare fixen
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
* BuildingPropertyCard creates the popup for field information
*/
public class BuildingPropertyCard extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container buildingPropertyContainer;
private final Container backgroundContainer;
private int index = 37;
public BuildingPropertyCard(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
//Generate the corresponfing field
BuildingProperty field = (BuildingProperty) app.getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
//Generate the corresponding field
int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
BuildingProperty field = (BuildingProperty) new BoardManager().getFieldAtIndex(index);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
attachChild(backgroundContainer);
// Hauptcontainer für die Gebäudekarte
buildingPropertyContainer = new Container();
buildingPropertyContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
float padding = 10; // Passt den backgroundContainer an die Größe des buildingPropertyContainer an
backgroundContainer.setPreferredSize(buildingPropertyContainer.getPreferredSize().addLocal(padding, padding, 0));
Label settingsTitle = buildingPropertyContainer.addChild(new Label( field.getName(), new ElementId("settings-title")));
//Titel
Label settingsTitle = buildingPropertyContainer.addChild(new Label( field.getName(), new ElementId("label-Bold")));
settingsTitle.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
settingsTitle.setFontSize(48);
// Text, der auf der Karte steht
@@ -65,28 +64,31 @@ public class BuildingPropertyCard extends Dialog {
propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
//TODO eventuell diese Stelle löschen, da nur die BuyCard Kaufen und beenden hat
/*
// Beenden-Button
Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
Button quitButton = buildingPropertyContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog(() -> {
System.err.println("Button does something?");
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Kaufen-Button
Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
Button buyButton = buildingPropertyContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32);
*/
buyButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
app.getGameLogic().send(new BuyPropertyResponse());
}));
float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(buildingPropertyContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü
// Zentriere das Popup
buildingPropertyContainer.setLocalTranslation(
(app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y+ padding) / 2,
@@ -96,38 +98,18 @@ public class BuildingPropertyCard extends Dialog {
app.getGuiNode().attachChild(buildingPropertyContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(buildingPropertyContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
}
public void setIndex(int index) {
this.index = index;
super.close();
}
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
}

View File

@@ -1,122 +0,0 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.model.fields.BuildingProperty;
/**
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
*/
public class BuyCard extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container buyCardContainer;
private final Container backgroundContainer;
private int index = 37;
public BuyCard(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
//Generate the corresponfing field
BuildingProperty field = (BuildingProperty) app.getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Gebäudekarte
buyCardContainer = new Container();
buyCardContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
Label settingsTitle = buyCardContainer.addChild(new Label( field.getName(), new ElementId("settings-title")));
settingsTitle.setFontSize(48);
// Text, der auf der Karte steht
// Die Preise werden dynamisch dem BoardManager entnommen
Container propertyValuesContainer = buyCardContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("„Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("„-mit 1 Haus: " + field.getAllRent().get(1) + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("„-mit 2 Häuser: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("„-mit 3 Häuser: " + field.getAllRent().get(3) + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("„-mit 4 Häuser: " + field.getAllRent().get(4) + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("„-mit 1 Hotel: " + field.getAllRent().get(5) + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("„-1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button
Button quitButton = buyCardContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32);
// Kaufen-Button
Button buyButton = buyCardContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32);
float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(buyCardContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü
buyCardContainer.setLocalTranslation(
(app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y) / 2,
8
);
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(buyCardContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(buyCardContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
}
}

View File

@@ -0,0 +1,214 @@
package pp.monopoly.client.gui.popups;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList;
import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.notification.Sound;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* BuyHouse is a popup which appears when a player clicks on the "Buy House"-button in the BuildingAdminMenu
*/
public class BuyHouse extends Dialog {
private final MonopolyApp app;
private final Container buyHouseContainer;
private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
private VersionedReference<Set<Integer>> selectionRef;
private Selector<String> propertySelector;
private Set<String> selectedProperties = new HashSet<>();
private Label cost = new Label("0", new ElementId("label-Text"));
public BuyHouse(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
attachChild(backgroundContainer);
// Main container for the menu
buyHouseContainer = new Container();
buyHouseContainer.setPreferredSize(new Vector3f(800, 600, 0));
float padding = 10; // Adjust backgroundContainer size to match buyHouseContainer
backgroundContainer.setPreferredSize(buyHouseContainer.getPreferredSize().addLocal(padding, padding, 0));
// Title
Label title = buyHouseContainer.addChild(new Label("Gebäude Kaufen", new ElementId("warning-Bold")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
// Divide buyHouseContainer into three sub-containers
Container upContainer = buyHouseContainer.addChild(new Container());
Container middleContainer = buyHouseContainer.addChild(new Container());
Container downContainer = buyHouseContainer.addChild(new Container());
// Upper section text
upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
upContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
// Add the property selector dropdown
middleContainer.addChild(createPropertyDropdown());
downContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
downContainer.addChild(new Label("Kosten:", new ElementId("label-Text"))); // Label for cost
downContainer.addChild(cost); // Cost details
downContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Cancel button
Button cancelButton = buyHouseContainer.addChild(new Button("Abbrechen", new ElementId("button")));
cancelButton.setFontSize(32);
cancelButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Confirm button
Button confirmButton = buyHouseContainer.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
AlterProperty msg = new AlterProperty("BuyHouse");
msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
app.getGameLogic().send(msg);
close();
}));
// Center the popup
buyHouseContainer.setLocalTranslation(
(app.getCamera().getWidth() - buyHouseContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + buyHouseContainer.getPreferredSize().y) / 2,
9
);
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - buyHouseContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + buyHouseContainer.getPreferredSize().y + padding) / 2,
8
);
app.getGuiNode().attachChild(buyHouseContainer);
}
/**
* Creates a dropdown menu for selecting a property.
*
* @return The dropdown container.
*/
private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
VersionedList<String> propertyOptions = new VersionedList<>();
List<BuildingProperty> playerProperties = getPlayerProperties();
// Populate the dropdown with property names
for (BuildingProperty property : playerProperties) {
propertyOptions.add(property.getName());
}
propertySelector = new Selector<>(propertyOptions, "glass");
dropdownContainer.addChild(propertySelector);
// Track selection changes
selectionRef = propertySelector.getSelectionModel().createReference();
// Initialize the selection display here
selectionDisplay = new TextField(""); // Create TextField for displaying selections
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection
if (!propertyOptions.isEmpty()) {
onDropdownSelectionChanged(propertySelector);
}
return dropdownContainer;
}
/**
* Retrieves the list of properties owned by the current player.
*
* @return List of BuildingProperty objects owned by the player.
*/
private List<BuildingProperty> getPlayerProperties() {
Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
BoardManager boardManager = app.getGameLogic().getBoardManager();
return boardManager.getPropertyFields(self.getProperties()).stream()
.filter(property -> property instanceof BuildingProperty)
.map(property -> (BuildingProperty) property)
.filter(property -> app.getGameLogic().getBoardManager().canBuild(property))
.collect(Collectors.toList());
}
@Override
public void update(float delta) {
if(selectionRef.update()) {
onDropdownSelectionChanged(propertySelector);
}
}
/**
* Handles property selection changes.
*/
private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem();
app.getGameLogic().playSound(Sound.BUTTON);
if (selectedProperties.contains(selected)) {
selectedProperties.remove(selected);
} else {
selectedProperties.add(selected);
}
int cost = 0;
for (String s : selectedProperties) {
cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice();
}
String display = String.join(" | ", selectedProperties);
selectionDisplay.setText(display);
this.cost.setText(cost+"");
}
@Override
public void close() {
app.getGuiNode().detachChild(buyHouseContainer);
app.getGuiNode().detachChild(backgroundContainer);
super.close();
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
}

View File

@@ -0,0 +1,138 @@
package pp.monopoly.client.gui.popups;
import com.jme3.math.ColorRGBA;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.client.gui.TradeMenu;
import pp.monopoly.message.client.TradeResponse;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound;
/**
* ConfirmTrade is a popup which appears when a trade is proposed to this certain player.
*/
public class ConfirmTrade extends Dialog {
private final MonopolyApp app;
private final Container confirmTradeContainer;
private final Container backgroundContainer;
private TradeHandler tradeHandler;
public ConfirmTrade(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
tradeHandler = app.getGameLogic().getTradeHandler();
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
attachChild(backgroundContainer);
// Hauptcontainer für das Bestätigungspopup
confirmTradeContainer = new Container();
float padding = 10; // Passt den backgroundContainer an die Größe des confirmTradeContainer an
backgroundContainer.setPreferredSize(confirmTradeContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label title = confirmTradeContainer.addChild(new Label( "Handel", new ElementId("warning-title")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
StringBuilder offeredProperties = new StringBuilder();
for (PropertyField field : tradeHandler.getOfferedProperties()) {
offeredProperties.append(field.getName());
offeredProperties.append(", ");
}
StringBuilder requestedProperties = new StringBuilder();
for (PropertyField field : tradeHandler.getRequestedProperties()) {
requestedProperties.append(field.getName());
requestedProperties.append(", ");
}
// Text, der auf der Karte steht
// Die Werte werden dem Handel entnommen (Iwas auch immer da dann ist)
Container propertyValuesContainer = confirmTradeContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Spieler " + tradeHandler.getSender().getName() + " möchte:", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("- " + offeredProperties, new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedAmount() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedJailCards() +" Sonderkaten", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("gegen:", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("- "+ requestedProperties, new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedAmount() +" EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedJailCards() +" Sonderkaten", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("tauschen, willst du das Angebot annehmen?", new ElementId("label-Text")));
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Ablehnen-Button
Button declineButton = confirmTradeContainer.addChild(new Button("Ablehnen", new ElementId("button")));
declineButton.setFontSize(32);
declineButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new TradeResponse(false, tradeHandler));
close();
}));
// Verhandeln-Button
Button negotiateButton = confirmTradeContainer.addChild(new Button("Verhandeln", new ElementId("button")));
negotiateButton.setFontSize(32);
negotiateButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
TradeHandler t = new TradeHandler(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getSender().getId()));
t.setReceiver(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getReceiver().getId()));
new TradeMenu(app, t).open();
}));
// Confirm-Button
Button confirmButton = confirmTradeContainer.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new TradeResponse(true, tradeHandler));
close();
}));
// Zentriere das Menü
confirmTradeContainer.setLocalTranslation(
(app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Menü
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(confirmTradeContainer);
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
app.getGuiNode().detachChild(confirmTradeContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
super.close();
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
}

View File

@@ -3,6 +3,7 @@ package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
@@ -13,23 +14,21 @@ import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.model.card.Card; // TODO für den Import der Queue notwendig
/**
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
* EventCardPopup is a popup which appears when a certain EventCard is triggered by entering a EventCardField
*/
public class EventCard extends Dialog {
public class EventCardPopup extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container eventCardContainer;
private final Container backgroundContainer;
private final String description;
public EventCard(MonopolyApp app) {
public EventCardPopup(MonopolyApp app, String description) {
super(app.getDialogManager());
this.app = app;
//Generate the corresponfing field
Card card = app.getDeckHelper().drawCard(); // TODO nimmt die Karten gerade unabhängig aus dem DeckHelper
this.description = description;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
@@ -40,47 +39,43 @@ public class EventCard extends Dialog {
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Gebäudekarte
// Hauptcontainer für die Eventcard
eventCardContainer = new Container();
eventCardContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
eventCardContainer.setPreferredSize(new Vector3f(550,400,10));
float padding = 10; // Passt den backgroundContainer an die Größe des eventCardContainers an
backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
// Die Namen werden dynamisch dem BoardManager entnommen
Label gateFieldTitle = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title")));
gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der auf der Karte steht
// Die Preise werden dynamisch dem BoardManager entnommen
// Die Erklärungsfelder werden automatisch den descriptions der Message entnommen
Container propertyValuesContainer = eventCardContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label(card.getDescription(), new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label(description, new ElementId("label-Text")));
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
propertyValuesContainer.setPreferredSize(new Vector3f(300,200,10));
// Beenden-Button
Button quitButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close());
// TODO Kaufen-Button wird nicht mehr benötigt, prüfen ob weg kann
//Button buyButton = buyCardContainer.addChild(new Button("Kaufen", new ElementId("button")));
//buyButton.setFontSize(32);
float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü
// Zentriere das Popup
eventCardContainer.setLocalTranslation(
(app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y) / 2,
8
10
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y+ padding) / 2,
7
9
);
app.getGuiNode().attachChild(eventCardContainer);
@@ -107,12 +102,14 @@ public class EventCard extends Dialog {
*/
@Override
public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(eventCardContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setBuyCardPopupOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
super.close();
}
@Override
public void escape() {
close();
}
}

View File

@@ -13,24 +13,27 @@ import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.message.client.BuyPropertyResponse;
import pp.monopoly.model.fields.FoodField;
import pp.monopoly.notification.Sound;
/**
* FoodFieldCard erstellt die Geböudekarte vom Brandl und der Truppenküche
* FoodFieldCard creates the popup for field information
*/
public class FoodFieldCard extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container foodFieldContainer;
private final Container backgroundContainer;
private int index = 12;
public FoodFieldCard(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
//Generate the corresponfing field
FoodField field = (FoodField) app.getBoardManager().getFieldAtIndex(index);
int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
@@ -39,19 +42,22 @@ public class FoodFieldCard extends Dialog {
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
attachChild(backgroundContainer);
// Hauptcontainer für die Gebäudekarte
foodFieldContainer = new Container();
foodFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
float padding = 10; // Passt den backgroundContainer an die Größe des foodFieldContainers an
backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe
Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title")));
Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
settingsTitle.setFontSize(48);
settingsTitle.setColor(ColorRGBA.White);
// Text, der auf der Karte steht
// Die Preise werden dynamisch dem BoardManager entnommen
Container propertyValuesContainer = foodFieldContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile
@@ -68,29 +74,30 @@ public class FoodFieldCard extends Dialog {
propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
//TODO eventuell diese Stelle löschen, da nur die BuyCard Kaufen und beenden hat
/*
// Beenden-Button
Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Kaufen-Button
Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32);
*/
buyButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new BuyPropertyResponse());
close();
}));
float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü
// Zentriere das Popup
foodFieldContainer.setLocalTranslation(
(app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y+ padding) / 2,
@@ -121,17 +128,15 @@ public class FoodFieldCard extends Dialog {
*/
@Override
public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(foodFieldContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
super.close();
}
public void setIndex(int index) {
this.index = index;
@Override
public void escape() {
new SettingsMenu(app).open();
}
}

View File

@@ -5,47 +5,48 @@ import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.message.client.BuyPropertyResponse;
import pp.monopoly.model.fields.GateField;
import pp.monopoly.notification.Sound;
/**
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
* GateFieldCard creates the popup for field information
*/
public class GateFieldCard extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container gateFieldContainer;
private final Container backgroundContainer;
private int index = 5;
public GateFieldCard(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
//Generate the corresponfing field
GateField field = (GateField) app.getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
GateField field = (GateField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
attachChild(backgroundContainer);
// Hauptcontainer für die Gebäudekarte
gateFieldContainer = new Container();
gateFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
// Titel
// Die Namen werden dynamisch dem BoardManager entnommen
Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title")));
float padding = 10; // Passt den backgroundContainer an die Größe des gateFieldContainers an
backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe
Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black);
@@ -54,36 +55,41 @@ public class GateFieldCard extends Dialog {
Container propertyValuesContainer = gateFieldContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man 1 Bahnhof besitzt: 250 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man 2 Bahnhöfe besitzt: 500 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man 3 Bahnhöfe besitzt: 1000 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man 4 Bahnhöfe besitzt: 2000 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Miete: 250 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("2 Bahnhof besitzt: 500 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("3 Bahnhof besitzt: 1000 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("4 Bahnhof besitzt: 2000 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
//TODO eventuell diese Stelle löschen, da nur die BuyCard Kaufen und beenden hat
/*
// Beenden-Button
Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
Button quitButton = gateFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Kaufen-Button
Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
Button buyButton = gateFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32);
*/
buyButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new BuyPropertyResponse());
close();
}));
float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü
// Zentriere das Popup
gateFieldContainer.setLocalTranslation(
(app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2,
8
(app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y+ padding) / 2,
@@ -114,16 +120,13 @@ public class GateFieldCard extends Dialog {
*/
@Override
public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(gateFieldContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
super.close();
}
public void setIndex(int index) {
this.index = index;
@Override
public void escape() {
new SettingsMenu(app).open();
}
}

View File

@@ -0,0 +1,119 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
/**
* Gulag is a warning popup that is triggered when a certain player enters the "Wache" field
*/
public class Gulag extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container gulagContainer;
private final Container backgroundContainer;
public Gulag(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Warnung
gulagContainer = new Container();
gulagContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
gulagContainer.setPreferredSize(new Vector3f(550,250,10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
backgroundContainer.setPreferredSize(gulagContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label gateFieldTitle = gulagContainer.addChild(new Label("Du kommst ins Gulag!", new ElementId("warning-title")));
gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der auf der Karte steht
/* Container textContainer = gulagContainer.addChild(new Container());
textContainer.addChild(new Label("Du hast die Verbindung verloren und kannst nichts dagegen machen. Akzeptiere einfach, dass du verloren hast!", new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(gulagContainer.getPreferredSize().addLocal(-250,-200,0));
*/
// Beenden-Button
Button quitButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close());
// Zentriere das Popup
gulagContainer.setLocalTranslation(
(app.getCamera().getWidth() - gulagContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + gulagContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - gulagContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + gulagContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(gulagContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
app.getGuiNode().detachChild(gulagContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
super.close();
}
@Override
public void escape() {
close();
}
}

View File

@@ -0,0 +1,120 @@
package pp.monopoly.client.gui.popups;
import com.jme3.math.ColorRGBA;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.message.client.NotificationAnswer;
import pp.monopoly.notification.Sound;
/**
* ConfirmTrade is a popup which appears when a trade is proposed to this certain player.
*/
public class GulagInfo extends Dialog {
private final MonopolyApp app;
private final Container gulagInfoContainer;
private final Container backgroundContainer;
public GulagInfo(MonopolyApp app, int trys) {
super(app.getDialogManager());
this.app = app;
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
attachChild(backgroundContainer);
// Hauptcontainer für das Bestätigungspopup
gulagInfoContainer = new Container();
float padding = 10; // Passt den backgroundContainer an die Größe des confirmTradeContainer an
backgroundContainer.setPreferredSize(gulagInfoContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label title = gulagInfoContainer.addChild(new Label( "Gulag", new ElementId("warning-title")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
// Text, der auf der Karte steht
// Die Werte werden dem Handel entnommen (Iwas auch immer da dann ist)
Container propertyValuesContainer = gulagInfoContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Du sitzt im Gefänginis und kommst nicht raus ...", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Es sei denn, du ...", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- bestichst die Wache mit 500 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- löst eine Gulag-Frei-Karte ein", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- wartest 3 Runden und bezahlst dann", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("- oder du würfelst einen Pasch", new ElementId("label-Text")));
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Bezahlen-Button
Button payButton = gulagInfoContainer.addChild(new Button("Bestechungsgeld bezahlen", new ElementId("button")));
payButton.setFontSize(32);
payButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new NotificationAnswer("PayJail"));
close();
}));
// Ereigniskarte-Button
Button eventCardButton = gulagInfoContainer.addChild(new Button("Ereigniskarte nutzen", new ElementId("button")));
eventCardButton.setFontSize(32);
eventCardButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new NotificationAnswer("UseJailCard"));
close();
}));
// Schließen-Button
Button closeButton = gulagInfoContainer.addChild(new Button("Schließen", new ElementId("button")));
closeButton.setFontSize(32);
closeButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Menü
gulagInfoContainer.setLocalTranslation(
(app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Menü
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y+ padding) / 2,
7
);
if(app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getNumJailCard() == 0) {
eventCardButton.setEnabled(false);
}
if(trys == 3) {
closeButton.setEnabled(false);
}
app.getGuiNode().attachChild(gulagInfoContainer);
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
app.getGuiNode().detachChild(gulagInfoContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
super.close();
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
}

View File

@@ -0,0 +1,129 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound;
public class LooserPopUp extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container LooserContainer;
private final Container backgroundContainer;
/**
* Constructs a new WinnerPopUp dialog.
*
* @param app The MonopolyApp instance.
*/
public LooserPopUp(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Warnung
LooserContainer = new Container();
LooserContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
LooserContainer.setPreferredSize(new Vector3f(355,600,10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
backgroundContainer.setPreferredSize(LooserContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label looserTitle = LooserContainer.addChild(new Label("Schade, du hast leider verloren, die nächste Runde wird besser!", new ElementId("header")));
looserTitle.setFontSize(25);
// looserTitle.setColor(ColorRGBA.Black);
// Create the image container
Container imageContainer = LooserContainer.addChild(new Container());
imageContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Dark gray background
imageContainer.setPreferredSize(LooserContainer.getPreferredSize().addLocal(-250, -200, 0)); // Adjust size for layout
// Add the image to the container
Label imageLabel = new Label(""); // Create a label for the image
IconComponent icon = new IconComponent("Pictures/MonopolyLooser.png"); // Load the image as an icon
icon.setIconScale(0.7f); // Scale the image appropriately
imageLabel.setIcon(icon);
imageContainer.addChild(imageLabel); // Add the image label to the container
//Beenden Button
Button quitButton = LooserContainer.addChild(new Button("Spiel Beenden", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
app.closeApp();
}));
// Zentriere das Popup
LooserContainer.setLocalTranslation(
(app.getCamera().getWidth() - LooserContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + LooserContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - LooserContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + LooserContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(LooserContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
app.getGuiNode().detachChild(LooserContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
super.close();
}
@Override
public void escape() {
close();
}
}

View File

@@ -1,55 +0,0 @@
package pp.monopoly.client.gui.popups;
import com.jme3.asset.TextureKey;
import com.jme3.math.Vector2f;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.IconComponent;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
public class LoserPopUp extends Dialog {
private final MonopolyApp app;
/**
* Constructs a new NetworkDialog.
*
* @param network The NetworkSupport instance to be used for network operations.
*/
public LoserPopUp(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
initializeDialog();
}
/**
* Initializes the dialog with input fields and connection buttons.
*/
private void initializeDialog() {
Container inputContainer = new Container();
// Titel und Eingabefelder für Host und Port
inputContainer.addChild(new Label("Schade, du hast leider verloren!"));
inputContainer.addChild(new Label("Die nächste Runde wird besser!"));
Label imageLabel = new Label("");
TextureKey key = new TextureKey("Pictures/MonopolyLoser.png", true);
Texture texture = app.getAssetManager().loadTexture(key);
IconComponent icon = new IconComponent(texture.toString()); // Icon mit Textur erstellen
icon.setIconSize(new Vector2f(155f, 120f)); // Skalierung des Bildes
imageLabel.setIcon(icon); // Setze das Icon im Label
inputContainer.addChild(imageLabel);
Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
inputContainer.setLocalTranslation(300,500,0);
attachChild(inputContainer);
}
}

View File

@@ -0,0 +1,118 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
/**
* Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn
*/
public class NoMoneyWarning extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container noMoneyWarningContainer;
private final Container backgroundContainer;
public NoMoneyWarning(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Warnung
noMoneyWarningContainer = new Container();
noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Na, schon wieder Pleite?", new ElementId("warning-title")));
gateFieldTitle.setFontSize(38);
gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der im Popup steht
Container textContainer = noMoneyWarningContainer.addChild(new Container());
textContainer.addChild(new Label("Du hast nicht genug Geld, um dieses Gebäude zu kaufen", new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Passt den textContainer an die Größe des bankruptContainers an
textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
// Beenden-Button
Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close());
// Zentriere das Popup
noMoneyWarningContainer.setLocalTranslation(
(app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(noMoneyWarningContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Closes the menu and removes the GUI elements.
*/
@Override
public void close() {
app.getGuiNode().detachChild(noMoneyWarningContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
super.close();
}
@Override
public void escape() {
close();
}
}

View File

@@ -0,0 +1,125 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.notification.Sound;
/**
* Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn
*/
public class RejectTrade extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container noMoneyWarningContainer;
private final Container backgroundContainer;
public RejectTrade(MonopolyApp app, TradeReply msg) {
super(app.getDialogManager());
this.app = app;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Warnung
noMoneyWarningContainer = new Container();
noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Handel abgelehnt!", new ElementId("warning-title")));
gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der im Popup steht
Container textContainer = noMoneyWarningContainer.addChild(new Container());
textContainer.addChild(new Label("Du hast Spieler"+ msg.getTradeHandler().getReceiver().getName() + "einen Handel vorgeschlagen", new ElementId("label-Text")));
textContainer.addChild(new Label("", new ElementId("label-Text")));
textContainer.addChild(new Label("Der Handel wurde abgelehnt", new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Passt den textContainer an die Größe des bankruptContainers an
textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
// Beenden-Button
Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Popup
noMoneyWarningContainer.setLocalTranslation(
(app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(noMoneyWarningContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Closes the menu and removes the GUI elements.
*/
@Override
public void close() {
app.getGuiNode().detachChild(noMoneyWarningContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
super.close();
}
@Override
public void escape() {
close();
}
}

View File

@@ -0,0 +1,149 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound;
/**
* Rent popup is triggered when a player enters a field owned by another player and needs to pay rent.
*/
public class Rent extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container rentContainer;
private final Container backgroundContainer;
public Rent(MonopolyApp app, String playerName, int amount) {
super(app.getDialogManager());
this.app = app;
// Create the overlay
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create and position the background container
backgroundContainer = createBackgroundContainer();
app.getGuiNode().attachChild(backgroundContainer);
// Create and position the rent container
rentContainer = createRentContainer(playerName, amount);
app.getGuiNode().attachChild(rentContainer);
centerContainers();
}
/**
* Creates a semi-transparent overlay background.
*
* @return the overlay geometry
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Creates the background container with styling.
*
* @return the styled background container
*/
private Container createBackgroundContainer() {
Container container = new Container();
container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
return container;
}
/**
* Creates the main rent container with title, text, and button.
*
* @param playerName the name of the player to whom the rent is owed
* @param amount the rent amount
* @return the rent container
*/
private Container createRentContainer(String playerName, int amount) {
Container container = new Container();
container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
container.setPreferredSize(new Vector3f(550, 250, 10));
// Title
Label title = container.addChild(new Label("Miete!", new ElementId("warning-title")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
// Rent message
Container textContainer = container.addChild(new Container());
textContainer.addChild(new Label("Du musst Spieler " + playerName + " " + amount + " EUR Miete zahlen",
new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
// Payment button
Button payButton = container.addChild(new Button("Überweisen", new ElementId("button")));
payButton.setFontSize(32);
payButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
return container;
}
/**
* Centers the rent and background containers on the screen.
*/
private void centerContainers() {
float padding = 10;
// Center rent container
rentContainer.setLocalTranslation(
(app.getCamera().getWidth() - rentContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + rentContainer.getPreferredSize().y) / 2,
8
);
// Center background container with padding
backgroundContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(padding, padding, 0));
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
7
);
}
/**
* Closes the popup and removes GUI elements.
*/
@Override
public void close() {
app.getGuiNode().detachChild(rentContainer);
app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(overlayBackground);
super.close();
}
/**
* Handles the escape action to close the dialog.
*/
@Override
public void escape() {
close();
}
}

View File

@@ -0,0 +1,217 @@
package pp.monopoly.client.gui.popups;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList;
import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* RepayMortage is a popup which appears when a player clicks on the "Repay Mortage"-button in the BuildingAdminMenu
*/
public class RepayMortage extends Dialog {
private final MonopolyApp app;
private final Container repayMortageContainer;
private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
private VersionedReference<Set<Integer>> selectionRef;
private Selector<String> propertySelector;
private Set<String> selectedProperties = new HashSet<>();
private Label cost = new Label("0", new ElementId("label-Text"));
public RepayMortage(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
attachChild(backgroundContainer);
// Hauptcontainer für das Menü
repayMortageContainer = new Container();
repayMortageContainer.setPreferredSize(new Vector3f(800, 600, 0));
float padding = 10; // Passt den backgroundContainer an die Größe des sellhouseContainers an
backgroundContainer.setPreferredSize(repayMortageContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label title = repayMortageContainer.addChild(new Label( "Hypothek Abbezahlen", new ElementId("warining-Bold")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
//Unterteilund des sellHouseContainer in drei "Untercontainer"
Container upContainer = repayMortageContainer.addChild(new Container());
Container middleContainer = repayMortageContainer.addChild(new Container());
Container downContainer = repayMortageContainer.addChild(new Container());
// Text, der auf der Karte steht
upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
middleContainer.addChild(createPropertyDropdown());
downContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
downContainer.addChild(new Label("Kosten:", new ElementId("label-Text")));// Leerzeile
downContainer.addChild(cost);
downContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button
Button cancelButton = repayMortageContainer.addChild(new Button("Abbrechen", new ElementId("button")));
cancelButton.setFontSize(32);
cancelButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Kaufen-Button
Button confirmButton = repayMortageContainer.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
AlterProperty msg = new AlterProperty("RepayMortage");
msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
app.getGameLogic().send(msg);
close();
}));
// Zentriere das Popup
repayMortageContainer.setLocalTranslation(
(app.getCamera().getWidth() - repayMortageContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + repayMortageContainer.getPreferredSize().y) / 2,
9
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - repayMortageContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + repayMortageContainer.getPreferredSize().y+ padding) / 2,
8
);
app.getGuiNode().attachChild(repayMortageContainer);
}
/**
* Creates a dropdown menu for selecting a property.
*
* @return The dropdown container.
*/
private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
VersionedList<String> propertyOptions = new VersionedList<>();
List<PropertyField> playerProperties = getPlayerProperties();
// Populate the dropdown with property names
for (PropertyField property : playerProperties) {
propertyOptions.add(property.getName());
}
propertySelector = new Selector<>(propertyOptions, "glass");
dropdownContainer.addChild(propertySelector);
// Track selection changes
selectionRef = propertySelector.getSelectionModel().createReference();
// Initialize the selection display here
selectionDisplay = new TextField(""); // Create TextField for displaying selections
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection
if (!propertyOptions.isEmpty()) {
onDropdownSelectionChanged(propertySelector);
}
return dropdownContainer;
}
/**
* Retrieves the list of properties owned by the current player.
*
* @return List of PropertyField objects owned by the player.
*/
private List<PropertyField> getPlayerProperties() {
Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
BoardManager boardManager = app.getGameLogic().getBoardManager();
return boardManager.getPropertyFields(self.getProperties()).stream()
.filter(property -> property instanceof PropertyField)
.map(property -> (PropertyField) property)
.filter(p -> p.isMortgaged())
.collect(Collectors.toList());
}
@Override
public void update(float delta) {
if(selectionRef.update()) {
onDropdownSelectionChanged(propertySelector);
}
}
/**
* Handles property selection changes.
*/
private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem();
app.getGameLogic().playSound(Sound.BUTTON);
if (selectedProperties.contains(selected)) {
selectedProperties.remove(selected);
} else {
selectedProperties.add(selected);
}
int cost = 0;
for (String s : selectedProperties) {
cost += ((PropertyField) app.getGameLogic().getBoardManager().getFieldByName(s)).getHypo();
}
String display = String.join(" | ", selectedProperties);
selectionDisplay.setText(display);
this.cost.setText(cost+"");
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
app.getGuiNode().detachChild(repayMortageContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
super.close();
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
}

View File

@@ -0,0 +1,227 @@
package pp.monopoly.client.gui.popups;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.ListBox;
import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList;
import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.notification.Sound;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* SellHouse is a popup which appears when a player clicks on the "demolish"-button in the BuildingAdminMenu
*/
public class SellHouse extends Dialog {
private final MonopolyApp app;
private final Container sellhouseContainer;
private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
private VersionedReference<Set<Integer>> selectionRef;
private Selector<String> propertySelector;
private Set<String> selectedProperties = new HashSet<>();
private Label cost = new Label("0", new ElementId("label-Text"));
public SellHouse(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
attachChild(backgroundContainer);
// Hauptcontainer für das Menü
sellhouseContainer = new Container();
sellhouseContainer.setPreferredSize(new Vector3f(800, 600, 0));
float padding = 10; // Passt den backgroundContainer an die Größe des sellhouseContainers an
backgroundContainer.setPreferredSize(sellhouseContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label title = sellhouseContainer.addChild(new Label( "Gebäude Abreißen", new ElementId("warining-Bold")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
//Unterteilund des sellHouseContainer in drei "Untercontainer"
Container upContainer = sellhouseContainer.addChild(new Container());
Container middleContainer = sellhouseContainer.addChild(new Container());
Container downContainer = sellhouseContainer.addChild(new Container());
// Text, der auf der Karte steht
upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
middleContainer.addChild(createPropertyDropdown());
downContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
downContainer.addChild(new Label("Erstattung:", new ElementId("label-Text")));// Leerzeile
downContainer.addChild(cost); // Cost details
downContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button
Button cancelButton = sellhouseContainer.addChild(new Button("Abbrechen", new ElementId("button")));
cancelButton.setFontSize(32);
cancelButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Kaufen-Button
Button confirmButton = sellhouseContainer.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
AlterProperty msg = new AlterProperty("SellHouse");
for (String string : selectedProperties) {
System.out.println(string);
}
msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
for (Integer integer : msg.getProperties()) {
System.out.println("ID des verkaufs: "+integer);
}
app.getGameLogic().send(msg);
close();
}));
// Zentriere das Popup
sellhouseContainer.setLocalTranslation(
(app.getCamera().getWidth() - sellhouseContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + sellhouseContainer.getPreferredSize().y) / 2,
9
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - sellhouseContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + sellhouseContainer.getPreferredSize().y+ padding) / 2,
8
);
app.getGuiNode().attachChild(sellhouseContainer);
}
/**
* Creates a dropdown menu for selecting a property.
*
* @return The dropdown container.
*/
private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
VersionedList<String> propertyOptions = new VersionedList<>();
List<BuildingProperty> playerProperties = getPlayerProperties();
// Populate the dropdown with property names
for (BuildingProperty property : playerProperties) {
propertyOptions.add(property.getName());
}
propertySelector = new Selector<>(propertyOptions, "glass");
dropdownContainer.addChild(propertySelector);
// Track selection changes
selectionRef = propertySelector.getSelectionModel().createReference();
// Initialize the selection display here
selectionDisplay = new TextField(""); // Create TextField for displaying selections
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection
if (!propertyOptions.isEmpty()) {
onDropdownSelectionChanged(propertySelector);
}
return dropdownContainer;
}
/**
* Retrieves the list of properties owned by the current player.
*
* @return List of BuildingProperty objects owned by the player.
*/
private List<BuildingProperty> getPlayerProperties() {
Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
BoardManager boardManager = app.getGameLogic().getBoardManager();
return boardManager.getPropertyFields(self.getProperties()).stream()
.filter(property -> property instanceof BuildingProperty)
.map(property -> (BuildingProperty) property)
.filter(p -> app.getGameLogic().getBoardManager().canSell(p))
.collect(Collectors.toList());
}
@Override
public void update(float delta) {
if(selectionRef.update()) {
onDropdownSelectionChanged(propertySelector);
}
}
/**
* Handles property selection changes.
*/
private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem();
app.getGameLogic().playSound(Sound.BUTTON);
if (selectedProperties.contains(selected)) {
selectedProperties.remove(selected);
} else {
selectedProperties.add(selected);
}
int cost = 0;
for (String s : selectedProperties) {
cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice();
}
String display = String.join(" | ", selectedProperties);
selectionDisplay.setText(display);
this.cost.setText(cost+"");
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
app.getGuiNode().detachChild(sellhouseContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
super.close();
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
}

View File

@@ -0,0 +1,218 @@
package pp.monopoly.client.gui.popups;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList;
import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* TakeMortage is a popup which appears when a player clicks on the "TakeMortage"-button in the BuildingAdminMenu
*/
public class TakeMortage extends Dialog {
private final MonopolyApp app;
private final Container takeMortageContainer;
private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
private VersionedReference<Set<Integer>> selectionRef;
private Selector<String> propertySelector;
private Set<String> selectedProperties = new HashSet<>();
private Label cost = new Label("0", new ElementId("label-Text"));
public TakeMortage(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
attachChild(backgroundContainer);
// Hauptcontainer für das Menü
takeMortageContainer = new Container();
takeMortageContainer.setPreferredSize(new Vector3f(800, 600, 0));
float padding = 10; // Passt den backgroundContainer an die Größe des sellhouseContainers an
backgroundContainer.setPreferredSize(takeMortageContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label title = takeMortageContainer.addChild(new Label( "Hypothek aufnehmen", new ElementId("warining-Bold")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
//Unterteilund des sellHouseContainer in drei "Untercontainer"
Container upContainer = takeMortageContainer.addChild(new Container());
Container middleContainer = takeMortageContainer.addChild(new Container());
Container downContainer = takeMortageContainer.addChild(new Container());
// Text, der auf der Karte steht
upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
middleContainer.addChild(createPropertyDropdown());
downContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
downContainer.addChild(new Label("Erstattung:", new ElementId("label-Text")));// Leerzeile
downContainer.addChild(cost);
downContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button
Button cancelButton = takeMortageContainer.addChild(new Button("Abbrechen", new ElementId("button")));
cancelButton.setFontSize(32);
cancelButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Kaufen-Button
Button confirmButton = takeMortageContainer.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
AlterProperty msg = new AlterProperty("TakeMortage");
msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
app.getGameLogic().send(msg);
close();
}));
// Zentriere das Popup
takeMortageContainer.setLocalTranslation(
(app.getCamera().getWidth() - takeMortageContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + takeMortageContainer.getPreferredSize().y) / 2,
9
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - takeMortageContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + takeMortageContainer.getPreferredSize().y+ padding) / 2,
8
);
app.getGuiNode().attachChild(takeMortageContainer);
}
/**
* Creates a dropdown menu for selecting a property.
*
* @return The dropdown container.
*/
private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
VersionedList<String> propertyOptions = new VersionedList<>();
List<PropertyField> playerProperties = getPlayerProperties();
// Populate the dropdown with property names
for (PropertyField property : playerProperties) {
propertyOptions.add(property.getName());
}
propertySelector = new Selector<>(propertyOptions, "glass");
dropdownContainer.addChild(propertySelector);
// Track selection changes
selectionRef = propertySelector.getSelectionModel().createReference();
// Initialize the selection display here
selectionDisplay = new TextField(""); // Create TextField for displaying selections
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection
if (!propertyOptions.isEmpty()) {
onDropdownSelectionChanged(propertySelector);
}
return dropdownContainer;
}
/**
* Retrieves the list of properties owned by the current player.
*
* @return List of PropertyField objects owned by the player.
*/
private List<PropertyField> getPlayerProperties() {
Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
BoardManager boardManager = app.getGameLogic().getBoardManager();
return boardManager.getPropertyFields(self.getProperties()).stream()
.filter(property -> property instanceof PropertyField)
.map(property -> (PropertyField) property)
.filter(p -> !p.isMortgaged())
.collect(Collectors.toList());
}
@Override
public void update(float delta) {
if(selectionRef.update()) {
onDropdownSelectionChanged(propertySelector);
}
}
/**
* Handles property selection changes.
*/
private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem();
app.getGameLogic().playSound(Sound.BUTTON);
if (selectedProperties.contains(selected)) {
selectedProperties.remove(selected);
} else {
selectedProperties.add(selected);
}
int cost = 0;
for (String s : selectedProperties) {
cost += ((PropertyField) app.getGameLogic().getBoardManager().getFieldByName(s)).getHypo();
}
String display = String.join(" | ", selectedProperties);
selectionDisplay.setText(display);
this.cost.setText(cost+"");
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
app.getGuiNode().detachChild(takeMortageContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
super.close();
}
@Override
public void escape() {
new SettingsMenu(app).open();
}
}

View File

@@ -0,0 +1,120 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound;
import static pp.monopoly.Resources.lookup;
/**
* TimeOut is a warning popup that is triggered when the connection to the server is interrupted.
*/
public class TimeOut extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container timeOutContainer;
private final Container backgroundContainer;
public TimeOut(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Warnung
timeOutContainer = new Container();
timeOutContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
timeOutContainer.setPreferredSize(new Vector3f(550,250,10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
backgroundContainer.setPreferredSize(timeOutContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label gateFieldTitle = timeOutContainer.addChild(new Label("Vorsicht !", new ElementId("warning-title")));
gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der auf der Karte steht
Container textContainer = timeOutContainer.addChild(new Container());
textContainer.addChild(new Label("Du hast die Verbindung verloren und kannst nichts dagegen machen. Akzeptiere einfach, dass du verloren hast!", new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(timeOutContainer.getPreferredSize().addLocal(-250,-200,0));
// Beenden-Button
Button quitButton = timeOutContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close());
// Zentriere das Popup
timeOutContainer.setLocalTranslation(
(app.getCamera().getWidth() - timeOutContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + timeOutContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - timeOutContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + timeOutContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(timeOutContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
app.getGuiNode().detachChild(timeOutContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
super.close();
}
@Override
public void escape() {
close();
}
}

View File

@@ -1,56 +1,128 @@
package pp.monopoly.client.gui.popups;
import com.jme3.asset.TextureKey;
import com.jme3.math.Vector2f;
import com.jme3.texture.Texture;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound;
public class WinnerPopUp extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container WinnerContainer;
private final Container backgroundContainer;
/**
* Constructs a new NetworkDialog.
* Constructs a new WinnerPopUp dialog.
*
* @param app The NetworkSupport instance to be used for network operations.
* @param app The MonopolyApp instance.
*/
public WinnerPopUp(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
initializeDialog();
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Warnung
WinnerContainer = new Container();
WinnerContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
WinnerContainer.setPreferredSize(new Vector3f(440,600,10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
backgroundContainer.setPreferredSize(WinnerContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel
Label winnerTitle = WinnerContainer.addChild(new Label("Herzlichen Glückwunsch, du bist der neue Monopoly Champion!", new ElementId("header")));
winnerTitle.setFontSize(25);
// winnerTitle.setColor(ColorRGBA.Black);
// Create the image container
Container imageContainer = WinnerContainer.addChild(new Container());
imageContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Dark gray background
imageContainer.setPreferredSize(WinnerContainer.getPreferredSize().addLocal(-250, -200, 0)); // Adjust size for layout
// Add the image to the container
Label imageLabel = new Label(""); // Create a label for the image
IconComponent icon = new IconComponent("Pictures/MonopolyWinner.png"); // Load the image as an icon
icon.setIconScale(1); // Scale the image appropriately
imageLabel.setIcon(icon);
imageContainer.addChild(imageLabel); // Add the image label to the container
Button quitButton = WinnerContainer.addChild(new Button("Spiel Beenden", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
app.closeApp();
}));
// Zentriere das Popup
WinnerContainer.setLocalTranslation(
(app.getCamera().getWidth() - WinnerContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + WinnerContainer.getPreferredSize().y) / 2,
8
);
// Zentriere das Popup
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - WinnerContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + WinnerContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(WinnerContainer);
}
/**
* Initializes the dialog with input fields and connection buttons.
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private void initializeDialog() {
Container inputContainer = new Container();
// Titel und Eingabefelder für Host und Port
inputContainer.addChild(new Label("Herlichen Glückwunsch!"));
inputContainer.addChild(new Label("Du,bist der Monopoly Champion!!!"));
Label imageLabel = new Label("");
TextureKey key = new TextureKey("Pictures/MonopolyWinner.png", true);
Texture texture = app.getAssetManager().loadTexture(key);
IconComponent icon = new IconComponent(texture.toString()); // Icon mit Textur erstellen
icon.setIconSize(new Vector2f(150f, 100f)); // Skalierung des Bildes
imageLabel.setIcon(icon);
// Setze das Icon im Label
inputContainer.addChild(imageLabel);
Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
inputContainer.setLocalTranslation(300, 500, 0);
attachChild(inputContainer);
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
app.getGuiNode().detachChild(WinnerContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
super.close();
}
@Override
public void escape() {
close();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -7,4 +7,9 @@ description = 'Monopoly common model'
dependencies {
api project(":common")
api libs.jme3.networking
}
testImplementation libs.mockito.core
testImplementation project(":monopoly:client")
testImplementation project(":monopoly:model")
testImplementation project(":monopoly:server")
}

View File

@@ -28,19 +28,19 @@ public class MonopolyConfig extends Config {
* The default port number for the Monopoly server.
*/
@Property("port")
private int port = 4321;
private int port = 42069;
/**
* The width of the game map in terms of grid units.
*/
@Property("map.width")
private int mapWidth = 12;
private int mapWidth = 10;
/**
* The height of the game map in terms of grid units.
*/
@Property("map.height")
private int mapHeight = 12;
private int mapHeight = 10;
/**
* Creates an instance of {@code MonopolyConfig} with default settings.

View File

@@ -7,13 +7,14 @@ import java.util.List;
import pp.monopoly.game.server.PlayerHandler;
import pp.monopoly.message.client.ClientMessage;
import pp.monopoly.message.server.BuyPropertyResponse;
import pp.monopoly.message.server.BuyPropertyRequest;
import pp.monopoly.message.server.DiceResult;
import pp.monopoly.message.server.EventDrawCard;
import pp.monopoly.message.server.GameOver;
import pp.monopoly.message.server.GameStart;
import pp.monopoly.message.server.JailEvent;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.NotificationMessage;
import pp.monopoly.message.server.PlayerStatusUpdate;
import pp.monopoly.message.server.ServerInterpreter;
import pp.monopoly.message.server.TimeOutWarning;
@@ -22,13 +23,20 @@ import pp.monopoly.message.server.TradeRequest;
import pp.monopoly.message.server.ViewAssetsResponse;
import pp.monopoly.model.Board;
import pp.monopoly.model.IntPoint;
import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.notification.ClientStateEvent;
import pp.monopoly.notification.DiceRollEvent;
import pp.monopoly.notification.ButtonStatusEvent;
import pp.monopoly.notification.EventCardEvent;
import pp.monopoly.notification.GameEvent;
import pp.monopoly.notification.GameEventBroker;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent;
import pp.monopoly.notification.PopUpEvent;
import pp.monopoly.notification.Sound;
import pp.monopoly.notification.SoundEvent;
import pp.monopoly.notification.UpdatePlayerView;
/**
* Controls the client-side game logic for Monopoly.
@@ -51,7 +59,12 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
/** The current state of the client game logic. */
private ClientState state = new LobbyState(this);
private static PlayerHandler playerHandler;
private PlayerHandler playerHandler;
private BoardManager boardManager = new BoardManager();
private TradeHandler tradeHandler;
/**
* Constructs a ClientGameLogic with the specified sender object.
@@ -62,6 +75,14 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
this.clientSender = clientSender;
}
/**
* Reutns the BoardManager
* @return the boardManager
*/
public BoardManager getBoardManager() {
return boardManager;
}
/**
* Returns the current state of the game logic.
*
@@ -83,7 +104,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
state.entry();
}
public static PlayerHandler getPlayerHandler() {
public PlayerHandler getPlayerHandler() {
return playerHandler;
}
@@ -96,6 +117,10 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
return board;
}
public TradeHandler getTradeHandler() {
return tradeHandler;
}
/**
* Moves the preview figure to the specified position.
*
@@ -128,7 +153,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*
* @param msg the message to be sent
*/
void send(ClientMessage msg) {
public void send(ClientMessage msg) {
if (clientSender == null) {
LOGGER.log(Level.ERROR, "trying to send {0} with sender==null", msg); //NON-NLS
} else {
@@ -179,21 +204,6 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
state.update(delta);
}
/**
* Handles the response for buying a property.
*
* @param msg the message containing the buy property response
*/
@Override
public void received(BuyPropertyResponse msg) {
if (msg.isSuccessful()) {
setInfoText("You successfully bought " + msg.getPropertyName() + "!");
playSound(Sound.MONEY_LOST);
} else {
setInfoText("Unable to buy " + msg.getPropertyName() + ". Reason: " + msg.getReason());
}
}
/**
* Handles the result of a dice roll.
*
@@ -201,9 +211,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*/
@Override
public void received(DiceResult msg) {
setInfoText("You rolled a " + msg.calcTotal() + "!");
//Set the dice images
playSound(Sound.DICE_ROLL);
notifyListeners(new DiceRollEvent(msg.getRollResult().get(0), msg.getRollResult().get(1)));
}
/**
@@ -213,9 +222,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*/
@Override
public void received(EventDrawCard msg) {
setInfoText("Event card drawn: " + msg.getCardDescription());
// Kartenlogik
playSound(Sound.EVENT_CARD);
notifyListeners(new EventCardEvent(msg.getCardDescription()));
}
/**
@@ -226,12 +233,10 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
@Override
public void received(GameOver msg) {
if (msg.isWinner()) {
setInfoText("Congratulations! You have won the game!");
//Winner popup
notifyListeners(new PopUpEvent("Winner", msg));
playSound(Sound.WINNER);
} else {
setInfoText("Game over. Better luck next time!");
// Looser popup
notifyListeners(new PopUpEvent("Looser", msg));
playSound(Sound.LOSER);
}
}
@@ -244,8 +249,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
@Override
public void received(GameStart msg) {
playerHandler = msg.getPlayerHandler();
setInfoText("The game has started! Good luck!");
setState(new WaitForTurnState(this));
notifyListeners(new ButtonStatusEvent(false));
}
/**
@@ -256,10 +261,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
@Override
public void received(JailEvent msg) {
if (msg.isGoingToJail()) {
setInfoText("You are sent to jail!");
playSound(Sound.GULAG);
} else {
setInfoText("You are out of jail!");
notifyListeners(new PopUpEvent("goingToJail", msg));
}
}
@@ -270,8 +273,9 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*/
@Override
public void received(PlayerStatusUpdate msg) {
setInfoText("Player " + msg.getPlayerName() + " status updated: " + msg.getStatus());
playerHandler = msg.getPlayerHandler();
System.out.println("Update Player");
notifyListeners(new UpdatePlayerView());
}
/**
@@ -281,7 +285,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*/
@Override
public void received(TimeOutWarning msg) {
setInfoText("Warning! Time is running out. You have " + msg.getRemainingTime() + " seconds left.");
notifyListeners(new PopUpEvent("timeout", msg));
}
/**
@@ -291,7 +295,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*/
@Override
public void received(ViewAssetsResponse msg) {
setInfoText("Your current assets are being displayed.");
boardManager = msg.getboard();
}
/**
@@ -301,12 +305,12 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*/
@Override
public void received(TradeReply msg) {
if (msg.getTradeHandler().getStatus()) {
setInfoText("Trade accepted by " + msg.getTradeHandler().getReceiver().getName() + ".");
if (msg.isAccepted()) {
playSound(Sound.TRADE_ACCEPTED);
notifyListeners(new PopUpEvent("tradepos", msg));
} else {
setInfoText("Trade rejected by " + msg.getTradeHandler().getReceiver().getName() + ".");
playSound(Sound.TRADE_REJECTED);
notifyListeners(new PopUpEvent("tradeneg", msg));
}
}
@@ -317,9 +321,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*/
@Override
public void received(TradeRequest msg) {
setInfoText("Trade offer received from " + msg.getTradeHandler().getSender().getName());
// playSound(Sound.TRADE_REQUEST); no sound effect
// notifyListeners();
tradeHandler = msg.getTradeHandler();
notifyListeners(new PopUpEvent("tradeRequest", msg));
}
/**
@@ -329,7 +332,27 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*/
@Override
public void received(NextPlayerTurn msg) {
setInfoText("It's your turn!");
notifyListeners(new ButtonStatusEvent(true));
setState(new ActiveState(this));
}
@Override
public void received(BuyPropertyRequest msg) {
notifyListeners(new PopUpEvent("Buy", msg));
}
@Override
public void received(NotificationMessage msg) {
if (msg.getKeyWord().equals("rent")) {
notifyListeners(new PopUpEvent("rent", msg));
} else if (msg.getKeyWord().equals("jailpay")) {
notifyListeners(new PopUpEvent(msg.getKeyWord(), msg));
} else if(msg.getKeyWord().equals("NoMoneyWarning")) {
notifyListeners(new PopUpEvent("NoMoneyWarning", msg));
} else if (msg.getKeyWord().equals("jailpay")) {
notifyListeners(new PopUpEvent("jailpay", msg));
} else if (msg.getKeyWord().equals("jailtryagain")) {
notifyListeners(new PopUpEvent("jailtryagain", msg));
}
}
}

View File

@@ -7,10 +7,21 @@
package pp.monopoly.game.server;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.message.server.BuyPropertyRequest;
import pp.monopoly.message.server.DiceResult;
import pp.monopoly.message.server.EventDrawCard;
import pp.monopoly.message.server.JailEvent;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.NotificationMessage;
import pp.monopoly.message.server.PlayerStatusUpdate;
import pp.monopoly.model.FieldVisitor;
import pp.monopoly.model.Figure;
import pp.monopoly.model.card.Card;
@@ -28,17 +39,26 @@ import pp.monopoly.model.fields.WacheField;
/**
* Class representing a player
*/
@Serializable
public class Player implements FieldVisitor<Void>{
private final int id;
private String name;
private int accountBalance = 15000;
private Figure figure;
private List<PropertyField> properties;
private Set<Integer> properties = new HashSet<>();
private int getOutOfJailCard;
private int fieldID;
private DiceResult rollResult;
private final PlayerHandler handler;
private PlayerState state = new LobbyState();
private transient final PlayerHandler handler;
private transient PlayerState state = new WaitForTurnState();
/**
* Default constructor for serialization purposes.
*/
private Player(){
id = 0;
handler = null;
}
/**
* Constructs a player with the speciefied params
@@ -65,15 +85,19 @@ public class Player implements FieldVisitor<Void>{
public void setFigure(Figure figure) {
this.figure = figure;
}
public Figure getFigure(){
return figure;
}
public PlayerColor getColor() {
switch ((id%6)+1) {
case 1: return PlayerColor.BLUE;
case 2: return PlayerColor.GREEN_DARK;
case 3: return PlayerColor.GREEN_LIGHT;
case 1: return PlayerColor.CYAN;
case 2: return PlayerColor.YELLOW;
case 3: return PlayerColor.RED;
case 4: return PlayerColor.PINK;
case 5: return PlayerColor.RED;
case 6: return PlayerColor.YELLOW;
case 5: return PlayerColor.GREEN;
case 6: return PlayerColor.PURPLE;
default:
return null;
@@ -111,53 +135,96 @@ public class Player implements FieldVisitor<Void>{
public int getFieldID() {
return fieldID;
}
void setActive() {
state = new ActiveState();
System.out.println("State: "+state.getClass().getName());
if(!(state instanceof JailState)) {
state = new ActiveState();
} else {
String message = (((JailState)state).remainingAttempts <= 0) ? "jailpay" : "jailtryagain";
handler.getLogic().send(this, new NotificationMessage(message));
}
}
boolean finishTurn() {
if(canFinishTurn()) {
state = new WaitForTurnState();
if (state instanceof ActiveState) state = new WaitForTurnState();
return true;
}
else return false;
else {
bankrupt();
return false;
}
}
boolean canFinishTurn() {
return accountBalance >= 0;
}
/**
* Moves by the specified amount of steps
* @param steps the number of steps to move
* @return the new position
*/
public int move(int steps){
return movePos(fieldID+steps);
public PlayerState getState() {
return state;
}
public void setState(PlayerState state) {
this.state = state;
}
/**
* Moves the player to the specified Position on the board
* @param position the position to move to
* Moves the player by a given number of steps, handling board wrapping.
*
* @param steps number of steps to move
* @return the new position
*/
public int movePos(int position){
fieldID = fieldID+position;
if(fieldID >= 40) {
fieldID = fieldID%40;
earnMoney(2000);
public int move(int steps) {
if (fieldID + steps >= 40) {
earnMoney(2000); // Passing GO gives money
}
fieldID = (fieldID + steps) % 40;
figure.moveTo(fieldID);
handler.getLogic().send(this, new PlayerStatusUpdate(handler));
handler.getLogic().getBoardManager().getFieldAtIndex(fieldID).accept(this);
return fieldID;
}
/**
* Sets the player to the specified Position on the board
* @param position the position to move to
* @return the new position
*/
public int setPosition(int position){
if(position < 40 && position >= 0) {
fieldID = position;
figure.moveTo(fieldID);
handler.getLogic().send(this, new PlayerStatusUpdate(handler));
handler.getLogic().getBoardManager().getFieldAtIndex(fieldID).accept(this);
}
return fieldID;
}
/**
* Sets the player to the specified Position on the board
* @param position the position to move to
* @return the new position
*/
public int setPositionWithMoney(int position){
if(position < 40 && position >= 0) {
if(position < fieldID) {
earnMoney(2000);
}
fieldID = position;
figure.moveTo(fieldID);
handler.getLogic().send(this, new PlayerStatusUpdate(handler));
handler.getLogic().getBoardManager().getFieldAtIndex(fieldID).accept(this);
}
return fieldID;
}
/**
* Gets all the properties owned by this player
* @return List of all properties owned by this player
*/
public List<PropertyField> getProperties() {
return properties;
public List<Integer> getProperties() {
return new ArrayList<>(properties);
}
/**
@@ -167,7 +234,7 @@ public class Player implements FieldVisitor<Void>{
*/
public void buyProperty(PropertyField property) {
if (property.getOwner() == null && accountBalance >= property.getPrice()) {
properties.add(property);
properties.add(property.getId());
property.setOwner(this);
pay(property.getPrice());
}
@@ -266,36 +333,60 @@ public class Player implements FieldVisitor<Void>{
@Override
public Void visit(BuildingProperty field) {
int rent = field.calcRent();
field.getOwner().earnMoney(rent);
pay(rent);
if(field.getOwner() == null) {
if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest());
else getHandler().getLogic().send(this, new NotificationMessage("NoMoneyWarning"));
} else if (field.getOwner() != this){
int rent = field.calcRent();
field.getOwner().earnMoney(rent);
pay(rent);
NotificationMessage msg = new NotificationMessage("rent");
msg.setRentAmount(rent);
msg.setRentOwnerId(field.getOwner().getName());
getHandler().getLogic().send(this, msg);
}
return null;
}
@Override
public Void visit(FoodField field) {
int factor = 4;
if (field.getOwner().getNumProp(field) == 2) {
factor = 10;
if(field.getOwner() == null) {
if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest());
} else {
int factor = 4;
if (field.getOwner().getNumProp(field) == 2) {
factor = 10;
}
int rent = rollResult.calcTotal()*factor;
field.getOwner().earnMoney(rent);
pay(rent);
NotificationMessage msg = new NotificationMessage("rent");
msg.setRentAmount(rent);
msg.setRentOwnerId(field.getOwner().getName());
getHandler().getLogic().send(this, msg);
}
field.getOwner().earnMoney(rollResult.calcTotal()*factor);
pay(rollResult.calcTotal()*factor);
return null;
}
@Override
public Void visit(GateField field) {
int rent = field.calcRent() * field.getOwner().getNumProp(field);
if(field.getOwner() == null) {
if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest());
} else {
int rent = field.calcRent() * field.getOwner().getNumProp(field);
field.getOwner().earnMoney(rent);
pay(rent);
field.getOwner().earnMoney(rent);
pay(rent);
NotificationMessage msg = new NotificationMessage("rent");
msg.setRentAmount(rent);
msg.setRentOwnerId(field.getOwner().getName());
getHandler().getLogic().send(this, msg);
}
return null;
}
@Override
public Void visit(GulagField field) {
state = new JailState();
return null;
}
@@ -308,21 +399,21 @@ public class Player implements FieldVisitor<Void>{
@Override
public Void visit(EventField field) {
Card c = getHandler().getLogic().getDeckHelper().drawCard();
getHandler().getLogic().getDeckHelper().visit(c, this);
getHandler().getLogic().getDeckHelper().visit(c, this); //Logic
getHandler().getLogic().send(this, new EventDrawCard(c.getDescription())); // Card notification
getHandler().getLogic().send(this, new PlayerStatusUpdate(getHandler())); //update view
return null;
}
@Override
public Void visit(WacheField field) {
movePos(10);
moveToJail();
return null;
}
@Override
public Void visit(GoField field) {
earnMoney(2000);
GulagField res = (GulagField) handler.getLogic().getBoardManager().getFieldAtIndex(10);
res.accept(this);
return null;
}
@@ -335,6 +426,25 @@ public class Player implements FieldVisitor<Void>{
return null;
}
public List<PropertyField> getPropertyFields() {
List<PropertyField> properties = new ArrayList<>();
for (Integer i : this.properties) {
properties.add((PropertyField)getHandler().getLogic().getBoardManager().getFieldAtIndex(i));
}
return properties;
}
/**
* Sends the player to jail by setting position and state.
*/
public void moveToJail() {
setPosition(10); // Jail position on the board
state = new JailState();
handler.getLogic().send(this, new JailEvent(true));
}
/**
* Return the number of Properties of the speciefied fild type
* @param field the type of field to search for
@@ -342,7 +452,9 @@ public class Player implements FieldVisitor<Void>{
*/
public int getNumProp(PropertyField field) {
int count = 0;
for (PropertyField propertyField : properties) {
if (properties.isEmpty()) return 0;
for (PropertyField propertyField : getPropertyFields()) {
if (propertyField.getClass() == field.getClass()) {
count++;
}
@@ -353,7 +465,7 @@ public class Player implements FieldVisitor<Void>{
public int getNumHouses() {
int total = 0;
for (PropertyField field : properties) {
for (PropertyField field : getPropertyFields()) {
if (field.getClass() == BuildingProperty.class) {
total += ((BuildingProperty) field).getHouses();
}
@@ -363,7 +475,7 @@ public class Player implements FieldVisitor<Void>{
public int getNumHotels() {
int total = 0;
for (PropertyField field : properties) {
for (PropertyField field : getPropertyFields()) {
if (field.getClass() == BuildingProperty.class) {
total += ((BuildingProperty) field).getHotel();
}
@@ -371,7 +483,8 @@ public class Player implements FieldVisitor<Void>{
return total;
}
/**
// private static int c = 0;
/**
* Inner class for dice functionality in the game.
* Rolls random dice values.
*/
@@ -385,18 +498,31 @@ public class Player implements FieldVisitor<Void>{
*/
private static int rollDice() {
return random.nextInt(6) + 1;
// c++;
// if(c < 7) {
// return 3;
// } else {
// return (c%4)+1;
// }
}
}
/**
* Rolls two dice and returns a list with the results.
* Rolls two dice, handles movement logic, and checks for doublets.
*
* @return a List of two integers representing the dice roll results
* @return the DiceResult of the roll
*/
DiceResult rollDice() {
return state.rollDice();
}
private void bankrupt() {
for (PropertyField field : getPropertyFields()) {
field.setOwner(null);
}
}
/**
* A interface representing the PlayerStates
*/
@@ -425,10 +551,39 @@ public class Player implements FieldVisitor<Void>{
*/
private class ActiveState implements PlayerState {
private int doubletscounter = 3;
private boolean mayRollDice = true;
@Override
public DiceResult rollDice() {
if (!mayRollDice) {
throw new IllegalStateException("Player is not allowed to roll dice at this moment.");
}
List<Integer> roll = List.of(Dice.rollDice(), Dice.rollDice());
rollResult = new DiceResult(roll);
rollResult = new DiceResult(roll.get(0), roll.get(1));
mayRollDice = false;
// Check for doublets
if (rollResult.isDoublets()) {
doubletscounter--; // Decrement doublets counter
if (doubletscounter <= 0) {
// Player rolls third doublet -> move to jail
moveToJail();
doubletscounter = 3; // Reset doublets counter
} else {
// Player rolls doublets but can roll again
mayRollDice = true;
move(rollResult.calcTotal()); // Move player for this roll
getHandler().getLogic().send(Player.this, new NextPlayerTurn());
}
} else {
// No doublets -> move normally and reset doublets counter
move(rollResult.calcTotal());
}
return rollResult;
}
@@ -444,71 +599,53 @@ public class Player implements FieldVisitor<Void>{
}
/**
* A class to represent the Lobby PlayerState
* Set when in Lobby
*/
private class LobbyState implements PlayerState{
@Override
public DiceResult rollDice() {
//do nothing
return null;
}
@Override
public void payBail() {
//do nothing
}
@Override
public void useJailCard() {
// do nothing
}
}
/**
* A class to represent the Jailed PlayerState
* Set when in Gulag
*/
private class JailState implements PlayerState {
private int DoubletsCounter = 3;
private int remainingAttempts = 3;
@Override
public DiceResult rollDice() {
List<Integer> roll = List.of(Dice.rollDice(), Dice.rollDice());
rollResult = new DiceResult(roll);
if (rollResult.isDoublets()) {
state = new ActiveState();
} else if (DoubletsCounter == 0) {
} else {
DoubletsCounter--;
if (remainingAttempts <= 0) {
return null;
}
List<Integer> roll = List.of(Dice.rollDice(), Dice.rollDice());
rollResult = new DiceResult(roll.get(0), roll.get(1));
handler.getLogic().send(Player.this, new DiceResult (rollResult.getRollResult().get(0), rollResult.getRollResult().get(1)));
if (rollResult.isDoublets()) {
handler.getLogic().send(Player.this, new JailEvent(false));
state = new ActiveState();
} else {
remainingAttempts--;
}
System.out.println("Feld:"+fieldID);
return rollResult;
}
@Override
public void payBail() {
pay(500);
state = new ActiveState();
pay(500);
state = new ActiveState();
}
@Override
public void useJailCard() {
getOutOfJailCard--;
state = new ActiveState();
if (getOutOfJailCard > 0) {
removeJailCard();
state = new ActiveState();
}
}
}
private class WaitForTurnState implements PlayerState {
@Override
public DiceResult rollDice() {
throw new UnsupportedOperationException("not allowed");
return null;
}
@Override
@@ -518,6 +655,19 @@ public class Player implements FieldVisitor<Void>{
@Override
public void useJailCard() {
}
}
@Override
public String toString() {
return "Player{name=" + name + ", figure=" + figure + "}";
}
public void addProperty(Integer id) {
properties.add(id);
}
public void removeProperty(Integer id) {
properties.remove(id);
}
}

View File

@@ -6,12 +6,12 @@ import com.jme3.math.ColorRGBA;
* Enum representing six distinct colors for players in the game.
*/
public enum PlayerColor {
GREEN_LIGHT(new ColorRGBA(0 / 255f, 204 / 255f, 0 / 255f, 1)), // Hex: 00cc00
RED(new ColorRGBA(255 / 255f, 0 / 255f, 0 / 255f, 1)), // Hex: ff0000
BLUE(new ColorRGBA(0 / 255f, 0 / 255f, 204 / 255f, 1)), // Hex: 0000cc
PINK(new ColorRGBA(255 / 255f, 77 / 255f, 166 / 255f, 1)), // Hex: ff4da6
GREEN_DARK(new ColorRGBA(0 / 255f, 102 / 255f, 0 / 255f, 1)), // Hex: 006600
YELLOW(new ColorRGBA(255 / 255f, 255 / 255f, 0 / 255f, 1)); // Hex: ffff00
CYAN(new ColorRGBA(1 / 255f, 190 / 255f, 254 / 255f, 1)),
YELLOW(new ColorRGBA(255 / 255f, 255 / 255f, 0 / 255f, 1)),
RED(new ColorRGBA(255 / 255f, 0 / 255f, 0 / 255f, 1)),
PINK(new ColorRGBA(255 / 255f, 77 / 255f, 166 / 255f, 1)),
GREEN(new ColorRGBA(0 / 255f, 204 / 255f, 0 / 255f, 1)),
PURPLE(new ColorRGBA(143 / 255f, 0 / 255f, 255 / 255f, 1));
private final ColorRGBA color;

View File

@@ -1,24 +1,31 @@
package pp.monopoly.game.server;
import java.util.LinkedList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.model.LimitedLinkedList;
/**
* A class for helping with player actions and managing thier turns
*/
@Serializable
public class PlayerHandler {
private List<Player> players = new LimitedLinkedList<>(6);
private List<Player> players = new LinkedList<>();
private Set<Player> readyPlayers = new HashSet<>();
private ServerGameLogic logic;
private Player hostPlayer;
private transient ServerGameLogic logic;
private Player extra = null;
/**
* Default constructor for serialization purposes.
*/
private PlayerHandler() {}
/**
* Contructs a PlayerHandler
* @param logic the {@link ServerGameLogic} this PlayerHandler is a part of
@@ -47,14 +54,6 @@ public class PlayerHandler {
players.addAll(players);
}
/**
* Return the host player
* @return the host player
*/
public Player getHostPlayer() {
return hostPlayer;
}
/**
* Return the number of players
* @return number of players in the game
@@ -106,9 +105,6 @@ public class PlayerHandler {
throw new IllegalArgumentException("Player already registered");
}
players.add(player);
if(hostPlayer == null) {
hostPlayer = player;
}
}
/**

View File

@@ -2,16 +2,25 @@ package pp.monopoly.game.server;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import pp.monopoly.MonopolyConfig;
import pp.monopoly.message.client.BuyPropertyRequest;
import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.message.client.BuyPropertyResponse;
import pp.monopoly.message.client.ClientInterpreter;
import pp.monopoly.message.client.EndTurn;
import pp.monopoly.message.client.NotificationAnswer;
import pp.monopoly.message.client.PlayerReady;
import pp.monopoly.message.client.RollDice;
import pp.monopoly.message.client.TradeOffer;
import pp.monopoly.message.client.TradeResponse;
import pp.monopoly.message.client.ViewAssetsRequest;
import pp.monopoly.message.server.GameOver;
import pp.monopoly.message.server.GameStart;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.PlayerStatusUpdate;
@@ -19,11 +28,12 @@ import pp.monopoly.message.server.ServerMessage;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.message.server.TradeRequest;
import pp.monopoly.message.server.ViewAssetsResponse;
import pp.monopoly.model.Board;
import pp.monopoly.model.Figure;
import pp.monopoly.model.Rotation;
import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.card.DeckHelper;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.PropertyField;
/**
@@ -132,7 +142,6 @@ public class ServerGameLogic implements ClientInterpreter {
playerHandler.addPlayer(player);
LOGGER.log(Level.DEBUG, "Player added: {0}", player.getId());
System.out.println("Anzahl Spieler verbunden:"+ playerHandler.getPlayerCount());
return player;
}
@@ -145,20 +154,16 @@ public class ServerGameLogic implements ClientInterpreter {
* @param from the connection ID of the player who sent the request
*/
@Override
public void received(BuyPropertyRequest msg, int from) {
public void received(BuyPropertyResponse msg, int from) {
Player player = playerHandler.getPlayerById(from);
if (player != null && state == ServerState.INGAME) {
PropertyField property = (PropertyField) boardManager.getFieldAtIndex(player.move(0)); // Assuming player position for property
if (player != null) {
PropertyField property = (PropertyField) boardManager.getFieldAtIndex(player.getFieldID()); // Assuming player position for property
if (property.getOwner() == null && player.getAccountBalance() >= property.getPrice()) {
player.buyProperty(property);
property.setOwner(player);
player.earnMoney(-property.getPrice());
LOGGER.log(Level.INFO, "Player {0} bought property {1}", player.getName(), property.getName());
} else {
LOGGER.log(Level.WARNING, "Player {0} cannot buy property {1}", player.getName(), property.getName());
}
player.buyProperty(property);
System.out.println("Properties:" +player.getProperties().toString());
LOGGER.log(Level.INFO, "Player {0} bought property {1}", player.getName(), property.getName());
}
updateAllPlayers();
}
/**
@@ -170,14 +175,23 @@ public class ServerGameLogic implements ClientInterpreter {
@Override
public void received(EndTurn msg, int from) {
Player player = playerHandler.getPlayerById(from);
if (player != null && state == ServerState.INGAME) {
if (player != null && player == playerHandler.getPlayerAtIndex(0)) {
if (player.finishTurn()) {
LOGGER.log(Level.DEBUG, "Ending turn for player {0}", player.getName());
Player next = playerHandler.nextPlayer();
next.setActive();
send(next, new NextPlayerTurn(next));
send(next, new NextPlayerTurn());
send(next, new PlayerStatusUpdate(playerHandler));
send(player, new PlayerStatusUpdate(playerHandler));
} else {
send(player, new GameOver(false));
playerHandler.removePlayer(player);
}
}
if(playerHandler.getPlayers().size() == 1) {
send(playerHandler.getPlayerAtIndex(0), new GameOver(true));
}
updateAllPlayers();
}
/**
@@ -189,7 +203,7 @@ public class ServerGameLogic implements ClientInterpreter {
@Override
public void received(PlayerReady msg, int from) {
Player player = playerHandler.getPlayerById(from);
if(player == playerHandler.getHostPlayer()) {
if(player.getId() == 0) {
startMoney = msg.getStartMoney();
}
@@ -207,7 +221,7 @@ public class ServerGameLogic implements ClientInterpreter {
send(p, new GameStart(playerHandler));
}
playerHandler.randomOrder();
send(playerHandler.getPlayerAtIndex(0), new NextPlayerTurn(playerHandler.getPlayerAtIndex(0)));
send(playerHandler.getPlayerAtIndex(0), new NextPlayerTurn());
}
}
@@ -220,8 +234,9 @@ public class ServerGameLogic implements ClientInterpreter {
@Override
public void received(RollDice msg, int from) {
Player player = playerHandler.getPlayerById(from);
if (player != null && state == ServerState.INGAME) {
if (player != null && player == playerHandler.getPlayerAtIndex(0)) {
send(player, player.rollDice());
updateAllPlayers();
}
}
@@ -234,11 +249,11 @@ public class ServerGameLogic implements ClientInterpreter {
@Override
public void received(TradeOffer msg, int from) {
Player sender = playerHandler.getPlayerById(from);
Player receiver = playerHandler.getPlayerById(msg.getReceiverId());
Player receiver = msg.getTradeHandler().getReceiver();
if (sender != null && receiver != null) {
LOGGER.log(Level.INFO, "Player {0} offers a trade to player {1}", sender.getName(), receiver.getName());
send(playerHandler.getPlayerById(msg.getReceiverId()), new TradeRequest(msg.getReceiverId(), msg.getTradeHandler()));
send(receiver, new TradeRequest(msg.getTradeHandler()));
}
}
@@ -250,15 +265,79 @@ public class ServerGameLogic implements ClientInterpreter {
*/
@Override
public void received(TradeResponse msg, int from) {
Player responder = playerHandler.getPlayerById(from);
Player initiator = playerHandler.getPlayerById(msg.getInitiatorId());
TradeHandler tradeHandler = msg.getTradeHandler();
if (responder != null && initiator != null) {
LOGGER.log(Level.INFO, "Player {0} responded to trade with player {1}", responder.getName(), initiator.getName());
send(initiator, new TradeReply(msg.getInitiatorId(), msg.getTradeHandler()));
Player receiver = playerHandler.getPlayerById(tradeHandler.getReceiver().getId());
Player sender = playerHandler.getPlayerById(tradeHandler.getSender().getId());
if(msg.isAccepted()) {
Set<PropertyField> offered = new HashSet<>();
for (PropertyField propertyField : tradeHandler.getOfferedProperties()) {
offered.add( (PropertyField) boardManager.getFieldAtIndex(propertyField.getId()));
}
Set<PropertyField> requested = new HashSet<>();
for (PropertyField propertyField : tradeHandler.getRequestedProperties()) {
requested.add( (PropertyField) boardManager.getFieldAtIndex(propertyField.getId()));
}
executeTrade(sender, receiver, offered, requested);
sender.earnMoney(tradeHandler.getRequestedAmount());
sender.pay(tradeHandler.getOfferedAmount());
receiver.earnMoney(tradeHandler.getOfferedAmount());
receiver.pay(tradeHandler.getRequestedAmount());
for (int i = 0; i < tradeHandler.getOfferedJailCards(); i++) {
sender.removeJailCard();
receiver.addJailCard();
}
for (int i = 0; i < tradeHandler.getRequestedAmount(); i++) {
sender.addJailCard();
receiver.removeJailCard();
}
}
updateAllPlayers();
if (receiver != null && sender != null) {
LOGGER.log(Level.INFO, "Player {0} responded to trade with player {1}", receiver.getName(), sender.getName());
send(sender, new TradeReply(msg.isAccepted(), msg.getTradeHandler()));
}
}
/**
* Executes the trade by transferring requested properties from the receiver
* to the sender and offered properties from the sender to the receiver.
*/
public void executeTrade(Player sender, Player receiver, Set<PropertyField> requestedProperties, Set<PropertyField> offeredProperties) {
// Transfer requested properties from receiver to sender
for (PropertyField field : requestedProperties) {
receiver.removeProperty(field.getId());
sender.addProperty(field.getId());
field.setOwner(sender); // Update ownership
System.out.printf("Property %s transferred from %s to %s.\n",
field.getName(), receiver.getName(), sender.getName());
}
// Transfer offered properties from sender to receiver
for (PropertyField field : offeredProperties) {
sender.removeProperty(field.getId());
receiver.addProperty(field.getId());
field.setOwner(receiver); // Update ownership
System.out.printf("Property %s transferred from %s to %s.\n",
field.getName(), sender.getName(), receiver.getName());
}
}
/**
* Handles a ViewAssetsRequest message, sending the player a response containing their assets.
*
@@ -268,11 +347,17 @@ public class ServerGameLogic implements ClientInterpreter {
@Override
public void received(ViewAssetsRequest msg, int from) {
Player sender = playerHandler.getPlayerById(from);
Player player = msg.getPlayer();
if (sender != null && player != null) {
LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", sender.getName());
send(sender, new ViewAssetsResponse(boardManager, player.getProperties(), player.getAccountBalance(), player.getNumJailCard()));
if (sender != null) {
LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", sender.getName());
send(sender, new ViewAssetsResponse(boardManager));
updateAllPlayers();
}
}
private void updateAllPlayers() {
for (Player player : playerHandler.getPlayers()) {
send(player, new PlayerStatusUpdate(playerHandler));
send(player, new ViewAssetsResponse(boardManager));
}
}
@@ -292,4 +377,61 @@ public class ServerGameLogic implements ClientInterpreter {
public DeckHelper getDeckHelper() {
return deckHelper;
}
@Override
public void received(AlterProperty msg, int from) {
Player sender = playerHandler.getPlayerById(from);
Set<PropertyField> properties = new HashSet<>();
for (Integer integer : msg.getProperties()) {
properties.add( (PropertyField)boardManager.getFieldAtIndex(integer));
}
if (msg.getKeyword().equals("TakeMortage")) {
for (PropertyField field : properties) {
field.setMortgaged(true);
sender.earnMoney(field.getHypo());
}
} else if (msg.getKeyword().equals("RepayMortage")) {
for (PropertyField field : properties) {
if(sender.getAccountBalance() >= field.getHypo()) {
field.setMortgaged(false);
sender.pay(field.getHypo());
}
}
} else if(msg.getKeyword().equals("BuyHouse")) {
for (BuildingProperty field : properties.stream().map(p -> (BuildingProperty) p).collect(Collectors.toList())) {
if (boardManager.canBuild(field) && sender.getAccountBalance() >= field.getHousePrice()) {
field.build();
sender.pay(field.getHousePrice());
}
}
} else if(msg.getKeyword().equals("SellHouse")) {
for (BuildingProperty field : properties.stream().map(p -> (BuildingProperty) p).collect(Collectors.toList())) {
if (boardManager.canSell(field)) {
field.sell();
sender.earnMoney(field.getHousePrice());
}
}
}
updateAllPlayers();
}
@Override
public void received(NotificationAnswer msg, int from) {
if(msg.getA().equals("UseJailCard")) {
playerHandler.getPlayerById(from).useJailCard();
} else if (msg.getA().equals("PayJail")) {
playerHandler.getPlayerById(from).payBail();
} else if(msg.getA().equals("hack")) {
for (BuildingProperty bp : boardManager.getPropertyFields( List.of(1,3)).stream().filter(p -> p instanceof BuildingProperty).map(p -> (BuildingProperty) p).collect(Collectors.toList())) {
bp.setOwner(playerHandler.getPlayerById(0));
playerHandler.getPlayerById(0).addProperty(bp.getId());
}
playerHandler.getPlayerAtIndex(0).earnMoney(20000);
}
updateAllPlayers();
}
}

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