177 Commits

Author SHA1 Message Date
Johannes Schmelz
eb54fb1d14 build correct 2024-12-10 14:12:28 +01:00
Johannes Schmelz
40c550cc4d mortage 2024-12-10 14:10:17 +01:00
Johannes Schmelz
18300987a4 demo 2024-12-10 12:13:40 +01:00
Johannes Schmelz
df4a81cbf2 disable snow 2024-12-10 11:23:49 +01:00
Johannes Schmelz
c635df9369 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-10 11:23:10 +01:00
Johannes Schmelz
c6ad605021 basic camera movement 2024-12-10 11:22:21 +01:00
Luca Puderbach
1e20a2ac6e Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-10 10:32:08 +01:00
Luca Puderbach
36a9a7addf Karten add 2024-12-10 10:29:51 +01:00
Johannes Schmelz
e1190cd4a2 cleanup 2024-12-10 10:23:33 +01:00
Johannes Schmelz
34ecd2277b cleanup 2024-12-10 10:19:59 +01:00
Johannes Schmelz
5959f36a21 new background 2024-12-10 10:14:06 +01:00
Simon Wilkening
1db2d9ebac Fixed "Spieler" in ...Trade-Popups 2024-12-10 08:27:23 +01:00
Yvonne Schmidt
54bac50a7e Merge remote-tracking branch 'origin/gui' into gui 2024-12-10 07:17:33 +01:00
Yvonne Schmidt
274ed2b25d added new background 2024-12-10 07:17:18 +01:00
Johannes Schmelz
371fa83319 remove deck cards 2024-12-10 06:15:13 +01:00
Simon Wilkening
c1faf91188 Fixed Containers for Buildings 2024-12-10 04:36:55 +01:00
Johannes Schmelz
617d707df8 fixed GateFieldPopUp 2024-12-10 04:07:30 +01:00
Johannes Schmelz
d18cea435c Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-10 03:56:01 +01:00
Johannes Schmelz
1543f0dcea more models 2024-12-10 03:55:57 +01:00
Johannes Schmelz
ae181e4eff more models 2024-12-10 03:55:44 +01:00
Johannes Schmelz
fa96324c15 mode models 2024-12-10 03:55:33 +01:00
Johannes Schmelz
9f559fe0d7 more models 2024-12-10 03:55:08 +01:00
Johannes Schmelz
cf6ee535b8 remove old textures 2024-12-10 03:54:56 +01:00
Johannes Schmelz
be89bf1a27 haus models 2024-12-10 03:54:29 +01:00
Yvonne Schmidt
6f2027c2fb added toolbar spacer 2024-12-10 03:45:08 +01:00
Yvonne Schmidt
6e99f17787 adjusted font 2024-12-10 03:40:04 +01:00
Yvonne Schmidt
b7e2e3213a Merge remote-tracking branch 'origin/gui' into gui 2024-12-10 03:27:59 +01:00
Yvonne Schmidt
3ea6452d6d fixed font 2024-12-10 03:27:36 +01:00
Luca Puderbach
fd3c141967 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-10 03:27:06 +01:00
Luca Puderbach
b3d2dfed08 Kamera Update T1 2024-12-10 03:26:55 +01:00
Simon Wilkening
5306208107 Containers PropertyCards 2024-12-10 03:22:26 +01:00
Yvonne Schmidt
2a7cbeed89 fixed bankrupt warning 2024-12-10 03:08:36 +01:00
Yvonne Schmidt
0a34751825 resized startmenu logos 2024-12-10 02:40:32 +01:00
Johannes Schmelz
996bc0118a Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-10 02:32:11 +01:00
Johannes Schmelz
bbcb12c131 working tank model 2024-12-10 02:32:07 +01:00
Yvonne Schmidt
1969afc58f Merge remote-tracking branch 'origin/gui' into gui 2024-12-10 02:24:41 +01:00
Yvonne Schmidt
ad0c432102 added greyed button 2024-12-10 02:24:29 +01:00
Johannes Schmelz
315739646c free cam 2024-12-10 01:12:56 +01:00
Luca Puderbach
330e788498 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-10 00:52:41 +01:00
Luca Puderbach
fc5a2809c8 Jägermeister 2024-12-10 00:52:30 +01:00
Luca Puderbach
0acb63adb6 Mac Blocker 2024-12-10 00:48:43 +01:00
Johannes Schmelz
b4c664927b Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-09 23:57:49 +01:00
Johannes Schmelz
ed27e0aaf1 popUp 2024-12-09 23:57:45 +01:00
Yvonne Schmidt
98f453d7f8 added javadoc 2024-12-09 22:38:02 +01:00
Yvonne Schmidt
8de7499c21 added spacer to toolbar 2024-12-09 22:16:53 +01:00
Johannes Schmelz
b680d7bc58 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-09 21:37:58 +01:00
Yvonne Schmidt
30559bf443 set all popups to same layer 2024-12-09 21:22:07 +01:00
Johannes Schmelz
8774c4246d added panzer 2024-12-09 21:10:57 +01:00
Luca Puderbach
7b82b20736 HoHoHo 2024-12-09 20:22:17 +01:00
Luca Puderbach
698937e77c Bayblade Mode activated 2024-12-09 19:53:47 +01:00
Yvonne Schmidt
7cbf000c44 readjusted popup layering 2024-12-09 17:57:00 +01:00
Johannes Schmelz
e98e17f6d7 cleanup 2024-12-09 13:55:04 +01:00
Johannes Schmelz
e337303408 fixed offset 2024-12-09 13:37:30 +01:00
Johannes Schmelz
97619fe662 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-09 13:29:03 +01:00
Johannes Schmelz
246566a211 aussetzen 2024-12-09 13:28:59 +01:00
Luca Puderbach
96a78ee61b Animation Hinzugefügt 2024-12-09 08:17:07 +01:00
Yvonne Schmidt
c9e99ee9ff Merge remote-tracking branch 'origin/gui' into gui 2024-12-09 05:53:08 +01:00
Yvonne Schmidt
111f2b1283 rescaled dice 2024-12-09 05:52:52 +01:00
Johannes Schmelz
93386fa77a Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-09 05:32:16 +01:00
Johannes Schmelz
6cdf0eee53 disable buttons when having to pause one round 2024-12-09 05:32:11 +01:00
Yvonne Schmidt
b6803c562c recolored selection containers 2024-12-09 05:31:22 +01:00
Johannes Schmelz
38699ac07a added App icon 2024-12-09 05:23:52 +01:00
Luca Puderbach
f396ef52f2 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-09 05:15:14 +01:00
Luca Puderbach
73bf147817 uniman2 2024-12-09 05:15:10 +01:00
Yvonne Schmidt
80f9054add recolored selection containers 2024-12-09 04:56:28 +01:00
Luca Puderbach
b819e1ca9b Figurenbewegung 2024-12-09 04:19:00 +01:00
Luca Puderbach
c4955e0b57 uniman 2024-12-09 04:14:34 +01:00
Johannes Schmelz
008cb1ebe4 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-09 03:25:44 +01:00
Johannes Schmelz
723c934d73 added cards and changed camera 2024-12-09 03:25:39 +01:00
Yvonne Schmidt
4eac2e3312 adjusted sound effects 2024-12-09 02:58:56 +01:00
Yvonne Schmidt
fef881f42c Merge remote-tracking branch 'origin/gui' into gui 2024-12-09 02:46:03 +01:00
Yvonne Schmidt
eeaf29a646 resolved popup overlap 2024-12-09 02:45:46 +01:00
Johannes Schmelz
2eae0fce2a Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-09 02:31:45 +01:00
Johannes Schmelz
aa9e8ed3f0 add and remove houses and hotel models 2024-12-09 02:31:41 +01:00
Yvonne Schmidt
3e14a2674f resolved popup overlap 2024-12-09 02:30:45 +01:00
Luca Puderbach
815899fa8d Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-09 01:47:35 +01:00
Luca Puderbach
793e93ef24 Map Update 2024-12-09 01:47:29 +01:00
Dennis_Malkmus
43d0549e9e Hotel und Hauser Texturen hinzugefuegt. 2024-12-09 01:07:04 +01:00
Johannes Schmelz
170afe2718 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-08 21:36:08 +01:00
Johannes Schmelz
17220c228b load predefined game state 2024-12-08 21:36:03 +01:00
Yvonne Schmidt
0f1be83064 added generic buttons 2024-12-08 21:35:50 +01:00
Johannes Schmelz
e0ab09295d adjusted tests 2024-12-08 21:09:58 +01:00
Johannes Schmelz
758e9b8397 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-08 20:59:12 +01:00
Johannes Schmelz
b3fe289fbe ImageButtons in Toolbar 2024-12-08 20:59:08 +01:00
Luca Puderbach
42fefb2899 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-08 19:23:15 +01:00
Luca Puderbach
5da86117c8 Anpassung Farbe 2024-12-08 19:23:10 +01:00
Yvonne Schmidt
1376da3ba6 added documentation 2024-12-08 19:00:08 +01:00
Yvonne Schmidt
fb280101a5 Merge remote-tracking branch 'origin/gui' into gui 2024-12-08 18:40:48 +01:00
Yvonne Schmidt
844495ebbb modified toolbar 2024-12-08 18:40:28 +01:00
Johannes Schmelz
e14f6bbef7 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-08 18:38:15 +01:00
Johannes Schmelz
4839ddd497 clean up and doc 2024-12-08 18:38:06 +01:00
Yvonne Schmidt
b901323e2f added color changes for buttons 2024-12-08 18:30:18 +01:00
Yvonne Schmidt
640665fd29 fixed layering issue 2024-12-08 18:29:14 +01:00
Johannes Schmelz
ba8791d9fe update Toolbar view 2024-12-08 18:08:16 +01:00
Johannes Schmelz
f8fe0b9877 fixed property trade 2024-12-08 17:34:19 +01:00
Johannes Schmelz
48913356e3 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-08 16:05:39 +01:00
Johannes Schmelz
e498c6f179 refactor 2024-12-08 16:03:21 +01:00
Johannes Schmelz
31fe60807f spelling 2024-12-08 15:57:32 +01:00
Yvonne Schmidt
c758ba9735 corrected toolbar labels 2024-12-08 15:05:47 +01:00
Yvonne Schmidt
650dcb85db toolbar frame has playercolor 2024-12-08 14:53:41 +01:00
Luca Puderbach
6b110c81c8 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-08 04:57:09 +01:00
Luca Puderbach
93ef00870b update toolbar + background 2024-12-08 04:57:04 +01:00
Johannes Schmelz
645433610f added control for figures 2024-12-08 02:43:58 +01:00
Johannes Schmelz
10a5b6b4d4 cleanup 2024-12-08 02:39:05 +01:00
Johannes Schmelz
69fccefed9 file path updated 2024-12-08 02:23:21 +01:00
Johannes Schmelz
14aecdd929 changed images 2024-12-08 02:21:54 +01:00
Johannes Schmelz
48f18dd468 Merge branch 'reworkedGui' into 'gui'
Reworked gui and client states

See merge request progproj/gruppen-ht24/Gruppe-02!19
2024-12-08 01:19:34 +00:00
Johannes Schmelz
96fe09c6fa Reworked gui and client states 2024-12-08 01:19:34 +00:00
Luca Puderbach
14c68f55d9 ltl backgrounds 2024-12-08 01:16:26 +01:00
Yvonne Schmidt
392a81b2d8 fixed background music overlap 2024-12-07 18:29:41 +01:00
Yvonne Schmidt
944b6b674e replaced text displays with labels 2024-12-07 14:54:55 +01:00
Simon Wilkening
5f4c6be7b8 adjusted test in ReceivedRent 2024-12-06 17:04:00 +01:00
Johannes Schmelz
aca92cd7f1 clean up 2024-12-06 16:21:12 +01:00
Johannes Schmelz
b50b5e64d1 can only trade fields without buildings 2024-12-06 16:06:40 +01:00
Johannes Schmelz
551786bf30 fixed enabled pref in GameMusic 2024-12-06 15:56:42 +01:00
Simon Wilkening
2aca94100e adjusted test in ReceivedRent 2024-12-06 13:20:40 +01:00
Simon Wilkening
9e81fb8549 TopDialog in Propertyoverview eingefügt 2024-12-06 13:17:57 +01:00
Simon Wilkening
3c6e519e77 Rent/ReceivedRent text changed 2024-12-06 13:12:56 +01:00
Simon Wilkening
9be00ab848 renamed IgfPadubrin and Rent/ReceivedRent 2024-12-06 12:35:57 +01:00
Simon Wilkening
c2c22f9ae5 NoMoneywarning and TimeOut use Dialogmanager now 2024-12-06 11:57:20 +01:00
Johannes Schmelz
e65c2661f7 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-05 02:48:00 +01:00
Johannes Schmelz
88db193b5e choose your charakter 2024-12-05 02:47:55 +01:00
Yvonne Schmidt
38824895bb set new toolbar background 2024-12-05 02:05:47 +01:00
Johannes Schmelz
a78261594d ImageButton for new Button design 2024-12-05 01:43:01 +01:00
Yvonne Schmidt
646d301554 added toolbar icons 2024-12-05 01:16:06 +01:00
Johannes Schmelz
e49b22c022 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-04 18:51:19 +01:00
Luca Puderbach
8821602728 kamera 2024-12-04 16:44:26 +01:00
Luca Puderbach
eb19e290bb Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-04 16:39:37 +01:00
Luca Puderbach
b477077b9b Kamera Teil1 2024-12-04 16:39:32 +01:00
Yvonne Schmidt
02cfc1d21a fixed formating errors 2024-12-04 16:00:24 +01:00
Yvonne Schmidt
4c40b447a5 fixed formating errors 2024-12-04 12:16:04 +01:00
Yvonne Schmidt
eaff7b6c5d fixed formating error in RejectTrade 2024-12-04 01:52:30 +01:00
Yvonne Schmidt
9ee1b5b81b simplified representation of trade 2024-12-04 01:48:18 +01:00
Yvonne Schmidt
49b9972ade replaced textinput with dynamic label 2024-12-04 01:10:12 +01:00
Johannes Schmelz
aae003823d trigger money sounds 2024-12-03 12:34:56 +01:00
Johannes Schmelz
1369de865a can no longer build if already has hotel 2024-12-03 12:30:34 +01:00
Johannes Schmelz
8e3cf9c31e now allowed to roll dice after getting out of jail 2024-12-03 12:24:55 +01:00
Johannes Schmelz
bc31c61fb3 bigger hack 2024-12-03 12:24:25 +01:00
Johannes Schmelz
975e4a2737 gym card text 2024-12-03 12:16:03 +01:00
Johannes Schmelz
8d638158e4 fixed Miete popup 2024-12-03 12:15:00 +01:00
Johannes Schmelz
1f37eb9962 refactor PlayerColor
fixed default playermodel selection
2024-12-03 12:07:09 +01:00
Johannes Schmelz
09ea8a046e mortage house interaction 2024-12-03 11:37:36 +01:00
Johannes Schmelz
0acb23ab8b price settings 2024-12-03 01:09:00 +01:00
Johannes Schmelz
831974cb63 miete erhalten popup 2024-12-03 00:58:01 +01:00
Johannes Schmelz
031ac52670 foodfield rent calc 2024-12-03 00:40:43 +01:00
Johannes Schmelz
14ceb9dc67 fixed GateField rent 2024-12-03 00:39:36 +01:00
Johannes Schmelz
aa86c25e7c fixed sell house payment 2024-12-03 00:30:54 +01:00
Johannes Schmelz
cb0788e44c lock endTurnButton when player needs to roll dice 2024-12-03 00:29:27 +01:00
Johannes Schmelz
9e88353bd5 show bankrupt popup once 2024-12-03 00:17:23 +01:00
Johannes Schmelz
6db96f0a1d trigger demo mode 2024-12-03 00:12:22 +01:00
Johannes Schmelz
b01bb3cf7b update for jar export 2024-12-02 16:29:57 +01:00
Johannes Schmelz
95b9da9377 server doc 2024-12-02 09:06:00 +01:00
Luca Puderbach
30822e3f4d Java Docs 2024-12-02 09:02:41 +01:00
Yvonne Schmidt
957bf8ffcc Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 09:00:57 +01:00
Yvonne Schmidt
446ecfd4b5 added documentation for NoMoneyWarning 2024-12-02 09:00:43 +01:00
Yvonne Schmidt
821c9ec3fb added documentation for SellHouse 2024-12-02 08:58:41 +01:00
Yvonne Schmidt
531a3e263c added documentation for TakeMortage 2024-12-02 08:54:49 +01:00
Yvonne Schmidt
4917208818 added documentation for TimeOut 2024-12-02 08:51:22 +01:00
Yvonne Schmidt
e81cdf3b40 added documentation for WinnerPopUp 2024-12-02 08:49:26 +01:00
Yvonne Schmidt
bffe614b54 added documentation for LooserPopUp 2024-12-02 08:47:36 +01:00
Yvonne Schmidt
69ad19757d added documentation for GulagInfo 2024-12-02 08:44:23 +01:00
Yvonne Schmidt
a4c0afe277 added documentation for Gulag 2024-12-02 08:42:08 +01:00
Yvonne Schmidt
cc157a3cf3 added documentation for Rent 2024-12-02 08:40:02 +01:00
Johannes Schmelz
ff2b64d476 removed errors in java doc 2024-12-02 08:39:47 +01:00
Yvonne Schmidt
459a54ac5d added documentation for Rent 2024-12-02 08:36:54 +01:00
Yvonne Schmidt
a50821f2e6 added documentation for RejectTrade 2024-12-02 08:34:53 +01:00
Yvonne Schmidt
72e0fc7cbd added documentation for GateFieldCard 2024-12-02 08:31:14 +01:00
Johannes Schmelz
3260d06bc8 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 08:28:09 +01:00
Johannes Schmelz
e07db0129f completed tests 2024-12-02 08:28:05 +01:00
Yvonne Schmidt
3bfa7ff69f added documentation for FoodFieldCard 2024-12-02 08:26:08 +01:00
Yvonne Schmidt
160fff88ea added documentation for EventCardPopup 2024-12-02 08:23:13 +01:00
Yvonne Schmidt
7a658cb3d6 added documentation for EventCardPopup 2024-12-02 08:15:54 +01:00
Yvonne Schmidt
25361933d7 added documentation for ConfirmTrade 2024-12-02 08:13:06 +01:00
Yvonne Schmidt
4ac02a1a7b added documentation for BuyHouse 2024-12-02 08:10:08 +01:00
Yvonne Schmidt
6f15f12b49 added documentation for BuildingPropertyCard 2024-12-02 08:05:00 +01:00
Yvonne Schmidt
9e50c1afe2 added documentation for Bankrupt 2024-12-02 07:59:24 +01:00
Yvonne Schmidt
3a43ea10d9 added documentation for AcceptTrade 2024-12-02 07:55:07 +01:00
178 changed files with 5373 additions and 3201 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

View File

@@ -0,0 +1,152 @@
# Blender 4.2.2 LTS MTL File: 'Hotel.V.1.2.blend'
# www.blender.org
newmtl Material
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0.6 0 -s 3.8 4 0 Hotel_texture2.png
newmtl Material.002
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.799099 0.004025 0.021219
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
newmtl Material.008
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.215859 0.215861 0.215861
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
newmtl Material.010
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0 -15 -s 4.28 4 0 Hotel_texture3.jpeg
newmtl Material.011
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0.6 0 -s 3.8 4 0 Hotel_texture2.png
newmtl Material.012
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0 -15 -s 4.28 4 0 Hotel_texture3.jpeg
newmtl Material.013
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.799099 0.004025 0.021219
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
newmtl Material.014
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0.6 0 -s 3.8 4 0 Hotel_texture2.png
newmtl Material.015
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0 -15 -s 4.28 4 0 Hotel_texture3.jpeg
newmtl Material.016
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.799099 0.004025 0.021219
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
newmtl Material.019
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0.6 0 -s 4.15 3.9 0 Hotel_texture1.jpeg
newmtl Material.022
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0.6 0 -s 4.15 3.8 0 Hotel_texture1.jpeg
newmtl Material.023
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0.6 0 -s 4.15 3.8 0 Hotel_texture1.jpeg
newmtl Material.024
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd -o 0 0.6 0 -s 4.15 3.9 0 Hotel_texture1.jpeg
newmtl Material.025
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.215859 0.215861 0.215861
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2

View File

@@ -0,0 +1,558 @@
# Blender 4.2.2 LTS
# www.blender.org
mtllib Hotel.V.1.2.mtl
o Korridor
v 1.832325 0.743096 0.449194
v 1.832325 0.295686 0.449194
v 0.271347 0.743096 0.429009
v 0.271347 0.295686 0.429009
v 1.837850 0.743096 0.022004
v 1.837850 0.295686 0.022004
v 0.276871 0.743096 0.001818
v 0.276871 0.295686 0.001818
vn -0.0129 -0.0000 0.9999
vn -0.9999 -0.0000 -0.0129
vn 0.0129 -0.0000 -0.9999
vn 0.9999 -0.0000 0.0129
vn -0.0000 1.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.008
f 1/1/1 3/4/1 4/3/1 2/2/1
f 3/4/2 7/6/2 8/5/2 4/3/2
f 7/6/3 5/8/3 6/7/3 8/5/3
f 5/8/4 1/10/4 2/9/4 6/7/4
f 3/11/5 1/12/5 5/8/5 7/6/5
f 8/5/6 6/7/6 2/14/6 4/13/6
o Dach300.002
v 2.503119 1.817345 1.102498
v 2.142795 1.919807 1.102498
v 2.503119 1.817345 -0.809905
v 2.142795 1.919807 -0.809905
v 1.831221 1.817345 1.102498
v 2.138520 1.919807 1.102498
v 1.831221 1.817345 -0.809905
v 2.138520 1.919807 -0.809905
vn 0.2735 0.9619 -0.0000
vn -0.0000 -0.0000 -1.0000
vn -0.3163 0.9487 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.002
f 9/15/7 11/18/7 12/17/7 10/16/7
f 11/18/8 15/20/8 16/19/8 12/17/8
f 15/20/9 13/22/9 14/21/9 16/19/9
f 13/22/10 9/24/10 10/23/10 14/21/10
f 11/25/11 9/26/11 13/22/11 15/20/11
f 16/19/12 14/21/12 10/28/12 12/27/12
o neu1
v 1.833977 0.294749 1.094962
v 1.833977 1.817107 1.094962
v 1.833977 0.294749 -0.825603
v 1.833977 1.817107 -0.825603
v 2.517500 0.294749 1.094962
v 2.517500 1.817107 1.094962
v 2.517500 0.294749 -0.825603
v 2.517500 1.817107 -0.825603
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material
f 17/29/13 18/30/13 20/31/13 19/32/13
f 19/32/14 20/31/14 24/33/14 23/34/14
f 23/34/15 24/33/15 22/35/15 21/36/15
f 21/36/16 22/35/16 18/37/16 17/38/16
f 19/39/17 23/34/17 21/36/17 17/40/17
f 24/33/18 20/41/18 18/42/18 22/35/18
o Frontfassade
v 1.837487 0.305766 1.101834
v 1.837487 1.807752 1.101834
v 1.837487 0.305766 1.092930
v 1.837487 1.807752 1.092930
v 2.509542 0.305766 1.101834
v 2.509542 1.807752 1.101834
v 2.509542 0.305766 1.092930
v 2.509542 1.807752 1.092930
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.010
f 25/43/19 26/44/19 28/45/19 27/46/19
f 27/46/20 28/45/20 32/47/20 31/48/20
f 31/48/21 32/47/21 30/49/21 29/50/21
f 29/50/22 30/49/22 26/51/22 25/52/22
f 27/53/23 31/48/23 29/50/23 25/54/23
f 32/47/24 28/55/24 26/56/24 30/49/24
o neu1.001
v -2.645782 0.310702 1.102233
v -2.645782 1.833060 1.102233
v -2.645782 0.310702 -0.818333
v -2.645782 1.833060 -0.818333
v -1.962258 0.310702 1.102233
v -1.962258 1.833060 1.102233
v -1.962258 0.310702 -0.818333
v -1.962258 1.833060 -0.818333
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.011
f 33/57/25 34/58/25 36/59/25 35/60/25
f 35/60/26 36/59/26 40/61/26 39/62/26
f 39/62/27 40/61/27 38/63/27 37/64/27
f 37/64/28 38/63/28 34/65/28 33/66/28
f 35/67/29 39/62/29 37/64/29 33/68/29
f 40/61/30 36/69/30 34/70/30 38/63/30
o Frontfassade.001
v -2.642272 0.321718 1.109104
v -2.642272 1.823704 1.109104
v -2.642272 0.321718 1.100200
v -2.642272 1.823704 1.100200
v -1.970217 0.321718 1.109104
v -1.970217 1.823704 1.109104
v -1.970217 0.321718 1.100200
v -1.970217 1.823704 1.100200
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.012
f 41/71/31 42/72/31 44/73/31 43/74/31
f 43/74/32 44/73/32 48/75/32 47/76/32
f 47/76/33 48/75/33 46/77/33 45/78/33
f 45/78/34 46/77/34 42/79/34 41/80/34
f 43/81/35 47/76/35 45/78/35 41/82/35
f 48/75/36 44/83/36 42/84/36 46/77/36
o Dach300.001
v -1.976640 1.833298 1.092314
v -2.336963 1.935760 1.092314
v -1.976640 1.833298 -0.785180
v -2.336963 1.935760 -0.785180
v -2.648537 1.833298 1.092314
v -2.341239 1.935760 1.092314
v -2.648537 1.833298 -0.785180
v -2.341239 1.935760 -0.785180
vn 0.2735 0.9619 -0.0000
vn -0.0000 -0.0000 -1.0000
vn -0.3163 0.9487 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.013
f 49/85/37 51/88/37 52/87/37 50/86/37
f 51/88/38 55/90/38 56/89/38 52/87/38
f 55/90/39 53/92/39 54/91/39 56/89/39
f 53/92/40 49/94/40 50/93/40 54/91/40
f 51/95/41 49/96/41 53/92/41 55/90/41
f 56/89/42 54/91/42 50/98/42 52/97/42
o neu1.002
v -0.141720 0.277559 1.245076
v -0.141720 1.799917 1.245076
v -0.526580 0.277559 -0.636534
v -0.526580 1.799917 -0.636534
v 0.527939 0.277559 1.108105
v 0.527939 1.799917 1.108105
v 0.143079 0.277559 -0.773505
v 0.143079 1.799917 -0.773505
vn -0.9797 -0.0000 0.2004
vn -0.2004 -0.0000 -0.9797
vn 0.9797 -0.0000 -0.2004
vn 0.2004 -0.0000 0.9797
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.014
f 57/99/43 58/100/43 60/101/43 59/102/43
f 59/102/44 60/101/44 64/103/44 63/104/44
f 63/104/45 64/103/45 62/105/45 61/106/45
f 61/106/46 62/105/46 58/107/46 57/108/46
f 59/109/47 63/104/47 61/106/47 57/110/47
f 64/103/48 60/111/48 58/112/48 62/105/48
o Frontfassade.002
v -0.136904 0.288576 1.251104
v -0.136904 1.790561 1.251104
v -0.138688 0.288576 1.242381
v -0.138688 1.790561 1.242381
v 0.521519 0.288576 1.116432
v 0.521519 1.790561 1.116432
v 0.519735 0.288576 1.107709
v 0.519735 1.790561 1.107709
vn -0.9797 -0.0000 0.2004
vn -0.2004 -0.0000 -0.9797
vn 0.9797 -0.0000 -0.2004
vn 0.2004 -0.0000 0.9797
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.015
f 65/113/49 66/114/49 68/115/49 67/116/49
f 67/116/50 68/115/50 72/117/50 71/118/50
f 71/118/51 72/117/51 70/119/51 69/120/51
f 69/120/52 70/119/52 66/121/52 65/122/52
f 67/123/53 71/118/53 69/120/53 65/124/53
f 72/117/54 68/125/54 66/126/54 70/119/54
o Dach300.003
v 0.511862 1.800155 1.101269
v 0.158847 1.902617 1.173474
v 0.135633 1.800155 -0.738143
v -0.217382 1.902617 -0.665938
v -0.146407 1.800155 1.235910
v 0.154658 1.902617 1.174331
v -0.522636 1.800155 -0.603502
v -0.221571 1.902617 -0.665081
vn 0.2680 0.9619 -0.0548
vn -0.2004 -0.0000 -0.9797
vn -0.3099 0.9487 0.0634
vn 0.2004 -0.0000 0.9797
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.016
f 73/127/55 75/130/55 76/129/55 74/128/55
f 75/130/56 79/132/56 80/131/56 76/129/56
f 79/132/57 77/134/57 78/133/57 80/131/57
f 77/134/58 73/136/58 74/135/58 78/133/58
f 75/137/59 73/138/59 77/134/59 79/132/59
f 80/131/60 78/133/60 74/140/60 76/139/60
o Korridor.002
v 0.294809 0.748953 0.441551
v 0.294809 0.301543 0.441551
v 1.816918 0.748953 0.453486
v 1.816918 0.301543 0.453486
v 0.294640 0.748953 0.463026
v 0.294640 0.301543 0.463026
v 1.816749 0.748953 0.474962
v 1.816749 0.301543 0.474962
vn 0.0078 -0.0000 -1.0000
vn 1.0000 -0.0000 0.0078
vn -0.0078 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0078
vn -0.0000 1.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.019
f 81/141/61 83/144/61 84/143/61 82/142/61
f 83/144/62 87/146/62 88/145/62 84/143/62
f 87/146/63 85/148/63 86/147/63 88/145/63
f 85/148/64 81/150/64 82/149/64 86/147/64
f 83/151/65 81/152/65 85/148/65 87/146/65
f 88/145/66 86/147/66 82/154/66 84/153/66
o Korridor.003
v 0.295923 0.753172 -0.007372
v 0.295923 0.305763 -0.007372
v 1.818032 0.753172 0.004563
v 1.818032 0.305763 0.004563
v 0.295755 0.753172 0.014104
v 0.295755 0.305763 0.014104
v 1.817863 0.753172 0.026039
v 1.817863 0.305763 0.026039
vn 0.0078 -0.0000 -1.0000
vn 1.0000 -0.0000 0.0078
vn -0.0078 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0078
vn -0.0000 1.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.022
f 89/155/67 91/158/67 92/157/67 90/156/67
f 91/158/68 95/160/68 96/159/68 92/157/68
f 95/160/69 93/162/69 94/161/69 96/159/69
f 93/162/70 89/164/70 90/163/70 94/161/70
f 91/165/71 89/166/71 93/162/71 95/160/71
f 96/159/72 94/161/72 90/168/72 92/167/72
o Korridor.004
v -2.035452 0.753172 0.001578
v -2.035452 0.305763 0.001578
v -0.305429 0.753172 0.015144
v -0.305429 0.305763 0.015144
v -2.035621 0.753172 0.023054
v -2.035621 0.305763 0.023054
v -0.305598 0.753172 0.036620
v -0.305598 0.305763 0.036620
vn 0.0078 -0.0000 -1.0000
vn 1.0000 -0.0000 0.0078
vn -0.0078 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0078
vn -0.0000 1.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.023
f 97/169/73 99/172/73 100/171/73 98/170/73
f 99/172/74 103/174/74 104/173/74 100/171/74
f 103/174/75 101/176/75 102/175/75 104/173/75
f 101/176/76 97/178/76 98/177/76 102/175/76
f 99/179/77 97/180/77 101/176/77 103/174/77
f 104/173/78 102/175/78 98/182/78 100/181/78
o Korridor.005
v -2.036718 0.748953 0.450501
v -2.036718 0.301543 0.450501
v -0.306695 0.748953 0.464067
v -0.306695 0.301543 0.464067
v -2.036887 0.748953 0.471977
v -2.036887 0.301543 0.471977
v -0.306864 0.748953 0.485542
v -0.306864 0.301543 0.485542
vn 0.0078 -0.0000 -1.0000
vn 1.0000 -0.0000 0.0078
vn -0.0078 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0078
vn -0.0000 1.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.024
f 105/183/79 107/186/79 108/185/79 106/184/79
f 107/186/80 111/188/80 112/187/80 108/185/80
f 111/188/81 109/190/81 110/189/81 112/187/81
f 109/190/82 105/192/82 106/191/82 110/189/82
f 107/193/83 105/194/83 109/190/83 111/188/83
f 112/187/84 110/189/84 106/196/84 108/195/84
o Korridor.006
v -0.288805 0.743096 0.460344
v -0.288805 0.295686 0.460344
v -2.062986 0.743096 0.437401
v -2.062986 0.295686 0.437401
v -0.283281 0.743096 0.033143
v -0.283281 0.295686 0.033143
v -2.057462 0.743096 0.010200
v -2.057462 0.295686 0.010200
vn -0.0129 -0.0000 0.9999
vn -0.9999 -0.0000 -0.0129
vn 0.0129 -0.0000 -0.9999
vn 0.9999 -0.0000 0.0129
vn -0.0000 1.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
usemtl Material.025
f 113/197/85 115/200/85 116/199/85 114/198/85
f 115/200/86 119/202/86 120/201/86 116/199/86
f 119/202/87 117/204/87 118/203/87 120/201/87
f 117/204/88 113/206/88 114/205/88 118/203/88
f 115/207/89 113/208/89 117/204/89 119/202/89
f 120/201/90 118/203/90 114/210/90 116/209/90

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

View File

@@ -19,6 +19,8 @@ import java.util.Deque;
import static java.lang.Math.max; import static java.lang.Math.max;
import java.lang.System.Logger;
/** /**
* Manages dialog boxes within the application, handling their display, positioning, and focus. * Manages dialog boxes within the application, handling their display, positioning, and focus.
*/ */
@@ -28,11 +30,15 @@ public class DialogManager {
*/ */
private final SimpleApplication app; private final SimpleApplication app;
private final static Logger LOGGER = System.getLogger(DialogManager.class.getName());
/** /**
* A stack to keep track of the dialogs. * A stack to keep track of the dialogs.
*/ */
private final Deque<Dialog> dialogStack = new ArrayDeque<>(); private final Deque<Dialog> dialogStack = new ArrayDeque<>();
private final Deque<PopupDialog> popUpStack = new ArrayDeque<>();
/** /**
* Constructs a DialogManager for the specified application. * Constructs a DialogManager for the specified application.
* *
@@ -112,11 +118,45 @@ public class DialogManager {
* @param dialog the dialog to open * @param dialog the dialog to open
*/ */
public void open(Dialog dialog) { public void open(Dialog dialog) {
if(dialog instanceof PopupDialog) {
popUpStack.push((PopupDialog) dialog);
processPopUps();
} else {
showDialog(dialog);
}
}
private void showDialog(Dialog dialog) {
dialogStack.push(dialog); dialogStack.push(dialog);
if(dialog instanceof PopupDialog) {
((PopupDialog)dialog).show();
}
dialog.update(); dialog.update();
app.getGuiNode().attachChild(dialog); app.getGuiNode().attachChild(dialog);
} }
private void processPopUps() {
if (popUpStack.isEmpty()) {
return; // Nothing to process
}
// Check if a popup dialog is already on top
if (dialogStack.peek() instanceof PopupDialog) {
LOGGER.log(Logger.Level.DEBUG, "Popup dialog already on top");
return; // Already a popup dialog on top
} else {
// Pop the next popup from the stack and validate before showing
PopupDialog popUp = popUpStack.pop();
showDialog( (Dialog) popUp);
}
}
/** /**
* Checks if the specified dialog is the topmost dialog in the dialog stack. * Checks if the specified dialog is the topmost dialog in the dialog stack.
* *
@@ -140,6 +180,8 @@ public class DialogManager {
if (!dialogStack.isEmpty()) if (!dialogStack.isEmpty())
dialogStack.peek().update(); dialogStack.peek().update();
app.getGuiNode().detachChild(dialog); app.getGuiNode().detachChild(dialog);
processPopUps();
} }
/** /**

View File

@@ -0,0 +1,5 @@
package pp.dialog;
public interface PopupDialog {
void show();
}

View File

@@ -3,6 +3,7 @@
// https://github.com/jMonkeyEngine-Contributions/Lemur/wiki/Styling // https://github.com/jMonkeyEngine-Contributions/Lemur/wiki/Styling
import com.jme3.math.ColorRGBA import com.jme3.math.ColorRGBA
import com.jme3.texture.Texture
import com.simsilica.lemur.* import com.simsilica.lemur.*
import com.simsilica.lemur.component.QuadBackgroundComponent import com.simsilica.lemur.component.QuadBackgroundComponent
import com.simsilica.lemur.Button import com.simsilica.lemur.Button
@@ -12,6 +13,8 @@ import com.simsilica.lemur.HAlignment
import com.simsilica.lemur.Insets3f import com.simsilica.lemur.Insets3f
import com.simsilica.lemur.component.QuadBackgroundComponent import com.simsilica.lemur.component.QuadBackgroundComponent
import com.simsilica.lemur.component.TbtQuadBackgroundComponent import com.simsilica.lemur.component.TbtQuadBackgroundComponent
import pp.monopoly.client.MonopolyApp
import pp.monopoly.game.server.Player
def bgColor = color(1, 1, 1, 1) def bgColor = color(1, 1, 1, 1)
def buttonEnabledColor = color(0, 0, 0, 1) def buttonEnabledColor = color(0, 0, 0, 1)
@@ -47,6 +50,23 @@ def orangeBorder = TbtQuadBackgroundComponent.create(
1f, false) 1f, false)
orangeBorder.color = color(1, 0.5, 0, 1) // Orange color orangeBorder.color = color(1, 0.5, 0, 1) // Orange color
def createCustomBackground(app) {
// Load the texture from the assets
Texture texture = app.getAssetManager().loadTexture("Pictures/kontobg.png")
// Create the TbtQuadBackgroundComponent
def backgroundCustom = TbtQuadBackgroundComponent.create(
texture, // The texture to use
1, 1, 1, // Insets for the 9-patch behavior
126, 126, // The size of the texture
1f, // The scale factor
false // No tiling
)
return backgroundCustom
}
selector("pp") { selector("pp") {
font = font("Interface/Fonts/Metropolis/Metropolis-Regular-32.fnt") font = font("Interface/Fonts/Metropolis/Metropolis-Regular-32.fnt")
} }
@@ -69,7 +89,7 @@ selector("label-Bold", "pp") {
selector("label-toolbar", "pp") { selector("label-toolbar", "pp") {
insets = new Insets3f(2, 2, 2, 2) insets = new Insets3f(2, 2, 2, 2)
font = font("Interface/Fonts/Metropolis/Metropolis-Bold-32.fnt") font = font("Interface/Fonts/Metropolis/Metropolis-Bold-32.fnt")
fontSize = 30 fontSize = 25
color = new ColorRGBA(ColorRGBA.White) color = new ColorRGBA(ColorRGBA.White)
textHAlignment = HAlignment.Center textHAlignment = HAlignment.Center
textVAlignment = VAlignment.Center textVAlignment = VAlignment.Center
@@ -81,6 +101,13 @@ selector("label-Text", "pp") {
color = buttonEnabledColor color = buttonEnabledColor
} }
selector("label-player", "pp") {
insets = new Insets3f(2, 2, 2, 2)
font = font("Interface/Fonts/Metropolis/Metropolis-Bold-32.fnt")
fontSize = 20
color = buttonEnabledColor
}
selector("label-account", "pp") { selector("label-account", "pp") {
insets = new Insets3f(2, 2, 2, 2) insets = new Insets3f(2, 2, 2, 2)
fontSize = 25 fontSize = 25
@@ -198,7 +225,6 @@ selector("button", "pp") {
insets = new Insets3f(3, 3, 3, 3) // Adjust the border thickness insets = new Insets3f(3, 3, 3, 3) // Adjust the border thickness
textHAlignment = HAlignment.Center textHAlignment = HAlignment.Center
textVAlignment = VAlignment.Center textVAlignment = VAlignment.Center
buttonCommands = stdButtonCommands
} }
selector("slider", "pp") { selector("slider", "pp") {
@@ -325,22 +351,23 @@ selector("selector.item.label", "hover") {
background = new QuadBackgroundComponent(new ColorRGBA(0.2f, 0.6f, 1.0f, 0.9f)) // Highlighted background background = new QuadBackgroundComponent(new ColorRGBA(0.2f, 0.6f, 1.0f, 0.9f)) // Highlighted background
} }
def enabledCommandToolbar = new Command<Button>() { def enabledCommandToolbar = new Command<Button>() {
MonopolyApp app // Pass the app instance to access player details
void execute(Button source) { void execute(Button source) {
if (source.isEnabled()){ // Get the current player's color
source.setColor(ColorRGBA.White) Player currentPlayer = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
def orangeBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)); // Orange background ColorRGBA playerColor = Player.getColor(currentPlayer.getId()).getColor();
source.setBackground(orangeBackground);
} else{ if (source.isEnabled()) {
source.setColor(ColorRGBA.White) source.setColor(ColorRGBA.White);
def grayBackground = new QuadBackgroundComponent(ColorRGBA.Gray); // Gray background def playerBackground = new QuadBackgroundComponent(playerColor); // Use player's color
source.setBackground(playerBackground);
} else {
source.setColor(ColorRGBA.White);
def grayBackground = new QuadBackgroundComponent(ColorRGBA.Gray); // Use gray when disabled
source.setBackground(grayBackground); source.setBackground(grayBackground);
} }
} }
} }
@@ -366,3 +393,56 @@ selector("button-toolbar", "pp") {
} }
selector("button-clear", "pp") { playerColor ->
def validColor = playerColor ?: new ColorRGBA(0, 0, 0, 0) // Vollständig transparent
def playerGradientBackground = new QuadBackgroundComponent(validColor)
// Kein Hintergrundbild, komplett transparent
playerGradientBackground.setColor(new ColorRGBA(0, 0, 0, 0)) // RGBA (Rot, Grün, Blau, Alpha)
background = playerGradientBackground.clone() // Setze den Hintergrund
insets = new Insets3f(-3, -3, -3, -3) // Optional: Ränder
textHAlignment = HAlignment.Center // Text-Zentrierung
textVAlignment = VAlignment.Center // Text-Zentrierung
}
def enabledCommandToolbar2= 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 stdButtonCommandsToolbar2 =[
(ButtonAction.Down) : [pressedCommand],
(ButtonAction.Up) : [pressedCommand],
(ButtonAction.Enabled) : [enabledCommandToolbar2],
(ButtonAction.Disabled): [enabledCommandToolbar2]
]
selector("button-toolbar2", "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 = stdButtonCommandsToolbar2
}

View File

@@ -1,5 +1,6 @@
plugins { plugins {
id 'buildlogic.jme-application-conventions' id 'buildlogic.jme-application-conventions'
id 'com.github.johnrengelman.shadow' version '8.1.1'
} }
description = 'Monopoly Client' description = 'Monopoly Client'
@@ -26,3 +27,12 @@ application {
mainClass = 'pp.monopoly.client.MonopolyApp' mainClass = 'pp.monopoly.client.MonopolyApp'
applicationName = 'monopoly' applicationName = 'monopoly'
} }
shadowJar {
manifest {
attributes(
'Main-Class': 'pp.monopoly.client.MonopolyApp'
)
}
}

View File

@@ -0,0 +1,354 @@
package pp.monopoly.client;
import com.jme3.app.Application;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.effect.shapes.EmitterSphereShape;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState.FaceCullMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Cylinder;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import com.jme3.shadow.EdgeFilteringMode;
import com.jme3.texture.Texture;
import com.jme3.util.TangentBinormalGenerator;
import pp.monopoly.client.gui.BobTheBuilder;
import pp.monopoly.client.gui.CameraController;
import pp.monopoly.client.gui.CameraInputHandler;
import pp.monopoly.client.gui.Toolbar;
import pp.monopoly.model.Board;
/**
* Manages the rendering and visual aspects of the sea and sky in the Battleship game.
* This state is responsible for setting up and updating the sea, sky, and lighting
* conditions, and controls the camera to create a dynamic view of the game environment.
*/
public class BoardAppState extends MonopolyAppState {
/**
* The path to the unshaded texture material.
*/
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
private static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md";
/**
* The path to the sea texture material.
*/
private static final String BoardTexture = "Pictures/board2.png"; //NON-NLS
/**
* The root node for all visual elements in this state.
*/
private final Node viewNode = new Node("view"); //NON-NLS
/**
* The node containing the scene elements, such as the sea surface.
*/
private final Node sceneNode = new Node("scene"); //NON-NLS
/**
* Synchronizes the buildings's visual representation with the game logic.
*/
private BobTheBuilder bobTheBuilder;
/**
* The pop-up manager for displaying messages and notifications.
*/
private PopUpManager popUpManager;
private CameraController cameraController;
private CameraInputHandler cameraInputHandler;
/**
* Initializes the state by setting up the sky, lights, and other visual components.
* This method is called when the state is first attached to the state manager.
*
* @param stateManager the state manager
* @param application the application
*/
@Override
public void initialize(AppStateManager stateManager, Application application) {
super.initialize(stateManager, application);
// Initialisiere den CameraController zuerst
cameraController = new CameraController(getApp().getCamera(), getApp());
// Danach den CameraInputHandler mit dem initialisierten CameraController
cameraInputHandler = new CameraInputHandler(cameraController, getApp().getInputManager());
popUpManager = new PopUpManager(getApp());
viewNode.attachChild(sceneNode);
setupLights();
// setupSky();
getApp().getViewPort().setBackgroundColor(new com.jme3.math.ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f));
}
/**
* Enables the sea and sky state, setting up the scene and registering any necessary listeners.
* This method is called when the state is set to active.
*/
@Override
protected void enableState() {
getApp().getRootNode().detachAllChildren();
getApp().getGuiNode().detachAllChildren();
getApp().getDialogManager().close(getApp().getDialogManager().getDialogStack().peek());
new Toolbar(getApp()).open();
sceneNode.detachAllChildren();
setupScene();
if (bobTheBuilder == null) {
bobTheBuilder = new BobTheBuilder(getApp(), sceneNode);
getGameLogic().addListener(bobTheBuilder);
}
getApp().getRootNode().attachChild(viewNode);
}
/**
* Disables the sea and sky state, removing visual elements from the scene and unregistering listeners.
* This method is called when the state is set to inactive.
*/
@Override
protected void disableState() {
getApp().getRootNode().detachChild(viewNode);
if (bobTheBuilder != null) {
getGameLogic().removeListener(bobTheBuilder);
bobTheBuilder = null;
}
}
/**
* Sets up the lighting for the scene, including directional and ambient lights.
* Also configures shadows to enhance the visual depth of the scene.
*/
private void setupLights() {
final AssetManager assetManager = getApp().getAssetManager();
final DirectionalLightShadowRenderer shRend = new DirectionalLightShadowRenderer(assetManager, 2048, 3);
shRend.setLambda(0.55f);
shRend.setShadowIntensity(0.6f);
shRend.setEdgeFilteringMode(EdgeFilteringMode.Bilinear);
getApp().getViewPort().addProcessor(shRend);
final DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-1f, -0.7f, -1f).normalizeLocal());
viewNode.addLight(sun);
shRend.setLight(sun);
final AmbientLight ambientLight = new AmbientLight();
// ambientLight.setColor(ColorRGBA.White.mult(0.f)); // brightness
viewNode.addLight(ambientLight);
}
/**
* Sets up the sky in the scene using a skybox with textures for all six directions.
* This creates a realistic and immersive environment for the sea.
*/
private void setupSky() {
final AssetManager assetManager = getApp().getAssetManager();
// Create a cylinder for the sky
float radius = 500f; // Adjust radius as needed
float height = 200f; // Height of the cylinder
int radialSamples = 64; // Number of radial segments for smoothness
int axisSamples = 2; // No vertical divisions (flat vertical surface)
Cylinder skyCylinder = new Cylinder(axisSamples, radialSamples, radius, height, true);
// Create a geometry for the cylinder
Geometry skyGeometry = new Geometry("CylinderSky", skyCylinder);
// Load the cylindrical texture
Texture cylinderTexture = assetManager.loadTexture("Textures/CylinderMap.jpg");
// Create a material and apply the texture
Material skyMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
skyMaterial.setTexture("ColorMap", cylinderTexture);
skyMaterial.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); // Render inside of the cylinder
// Assign material to the geometry
skyGeometry.setMaterial(skyMaterial);
skyGeometry.rotate(-FastMath.HALF_PI, 0, 0); // Rotate 90° along the Y-axis
// Position and attach the cylinder to the scene
skyGeometry.setQueueBucket(RenderQueue.Bucket.Sky); // Ensure it's rendered in the background
skyGeometry.setCullHint(Spatial.CullHint.Never); // Always render the sky
viewNode.attachChild(skyGeometry);
addCylinderCaps();
}
/**
* Adds top and bottom caps to the cylinder sky.
*/
private void addCylinderCaps() {
final AssetManager assetManager = getApp().getAssetManager();
float radius = 500f; // Match the cylinder's radius
float height = 225f; // Match the cylinder's height
int radialSamples = 64; // Match the cylinder's radial samples
// Bottom Cap
Cylinder bottomCap = new Cylinder(2, radialSamples, radius, 0.01f, true, false); // Thin bottom cap
Geometry bottomGeometry = new Geometry("BottomCap", bottomCap);
bottomGeometry.setLocalTranslation(0, -height / 2, 0); // Position at the bottom
bottomGeometry.rotate(FastMath.HALF_PI, 0, 0); // Rotate to make it horizontal
Material bottomMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
bottomMaterial.setTexture("ColorMap", assetManager.loadTexture("Textures/grass.jpg")); // Bottom texture
bottomMaterial.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); // Render both sides
bottomGeometry.setMaterial(bottomMaterial);
bottomGeometry.setQueueBucket(RenderQueue.Bucket.Sky);
bottomGeometry.setCullHint(Spatial.CullHint.Never);
// Top Cap
Cylinder topCap = new Cylinder(2, radialSamples, radius, 0.01f, true, false); // Thin top cap
Geometry topGeometry = new Geometry("TopCap", topCap);
topGeometry.setLocalTranslation(0, height / 2, 0); // Position at the top
topGeometry.rotate(FastMath.HALF_PI, 0, 0); // Rotate to make it horizontal
Material topMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
topMaterial.setTexture("ColorMap", assetManager.loadTexture("Textures/Top.png")); // Top texture
topMaterial.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); // Render both sides
topGeometry.setMaterial(topMaterial);
topGeometry.setQueueBucket(RenderQueue.Bucket.Sky);
topGeometry.setCullHint(Spatial.CullHint.Never);
// Attach caps to the view node
viewNode.attachChild(bottomGeometry);
viewNode.attachChild(topGeometry);
}
/**
* Sets up the sea surface in the scene. This includes creating the sea mesh,
* applying textures, and enabling shadows.
*/
private void setupScene() {
final Board board = getGameLogic().getBoard();
final float x = board.getWidth();
final float y = board.getHeight();
final Box seaMesh = new Box(y, 0.1f, x);
final Geometry seaGeo = new Geometry("sea", seaMesh); //NON-NLS
seaGeo.setLocalTranslation(new Vector3f(0, -0.1f, 0));
Quaternion rotation = new Quaternion();
rotation.fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y);
seaGeo.setLocalRotation(rotation);
final Material seaMat = new Material(getApp().getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
Texture texture = getApp().getAssetManager().loadTexture("Pictures/board2.png");
texture.setMagFilter(Texture.MagFilter.Bilinear);
texture.setMinFilter(Texture.MinFilter.Trilinear);
seaMat.setTexture("DiffuseMap", texture);
// Add specular highlights
// seaMat.setBoolean("UseMaterialColors", true);
seaMat.setColor("Diffuse", ColorRGBA.White);
seaMat.setColor("Specular", ColorRGBA.White);
// seaMat.setFloat("Shininess", 16f);
seaGeo.setMaterial(seaMat);
seaGeo.setShadowMode(ShadowMode.CastAndReceive);
TangentBinormalGenerator.generate(seaGeo);
sceneNode.attachChild(createCardDeck());
sceneNode.attachChild(seaGeo);
// Schneefall hinzufügen
// addSnowEffect(sceneNode);
}
private Node createCardDeck() {
Node cardDeck = new Node("cardDeck");
// Ereigniskarten
Vector3f basePosition1 = new Vector3f(3.1f, 0.4f, 3.8f); // Basisposition für Ereigniskarten
float baseRotation1 = -60; // Basisrotation in Grad
for (int i = 0; i < 6; i++) {
Box box = new Box(1.2f, 0.05f, 1.8f); // Sehr flaches Rechteck
Geometry flatCard = new Geometry("Ereigniskarten_" + i, box);
Material mat = new Material(getApp().getAssetManager(), UNSHADED);
mat.setTexture("ColorMap", getApp().getAssetManager().loadTexture("Textures/Ereigniskarten.png"));
flatCard.setMaterial(mat);
// Position und Rotation für die Karte
flatCard.setLocalTranslation(basePosition1.x, basePosition1.y - (i * 0.08f), basePosition1.z);
flatCard.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD * (baseRotation1 - (i * 5)), Vector3f.UNIT_Y));
cardDeck.attachChild(flatCard);
}
// Gemeinschaftskarten
Vector3f basePosition2 = new Vector3f(-3.3f, 0.4f, -3.8f); // Basisposition für Gemeinschaftskarten
float baseRotation2 = -220; // Basisrotation in Grad
for (int i = 0; i < 6; i++) {
Box box = new Box(1.2f, 0.04f, 1.8f); // Sehr flaches Rechteck
Geometry flatCard = new Geometry("Gemeinschaftskarten_" + i, box);
Material mat = new Material(getApp().getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", getApp().getAssetManager().loadTexture("Textures/Gemeinschaftskarten.png"));
flatCard.setMaterial(mat);
// Position und Rotation für die Karte
flatCard.setLocalTranslation(basePosition2.x, basePosition2.y - (i * 0.08f), basePosition2.z);
flatCard.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD * (baseRotation2 - (i * 5)), Vector3f.UNIT_Y));
cardDeck.attachChild(flatCard);
}
return cardDeck;
}
private void addSnowEffect(Node parentNode) {
// ParticleEmitter für Schnee
ParticleEmitter snowEmitter = new ParticleEmitter("Snow", ParticleMesh.Type.Triangle, 5000);
Material snowMat = new Material(getApp().getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
snowMat.setTexture("Texture", getApp().getAssetManager().loadTexture("Textures/snowflake.png")); // Schneeflocken-Textur
snowEmitter.setMaterial(snowMat);
// Eigenschaften für Schneepartikel
snowEmitter.setImagesX(1);
snowEmitter.setImagesY(1);
snowEmitter.setEndColor(new ColorRGBA(1f, 1f, 1f, 0.5f)); // Weiß, halbtransparent
snowEmitter.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f)); // Vollweiß
snowEmitter.setStartSize(0.1f);
snowEmitter.setEndSize(0.2f);
snowEmitter.setGravity(0, 0.5f, 0); // Langsames Fallen
snowEmitter.setLowLife(3f);
snowEmitter.setHighLife(15f);
snowEmitter.getParticleInfluencer().setInitialVelocity(new Vector3f(0, -1, 0));
snowEmitter.getParticleInfluencer().setVelocityVariation(0.3f);
// Spawn-Bereich für Schneeflocken definieren
snowEmitter.setParticlesPerSec(200);
snowEmitter.setLocalTranslation(0, 10, 0);
snowEmitter.setShape(new EmitterSphereShape(new Vector3f(0, 0, 0), 15)); // Bereich von -15 bis 15
// Emitter zur Szene hinzufügen
parentNode.attachChild(snowEmitter);
}
@Override
public void update(float tpf) {
super.update(tpf);
cameraController.update(tpf);
}
}

View File

@@ -1,113 +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.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

@@ -13,51 +13,35 @@ import com.jme3.asset.AssetLoadException;
import com.jme3.asset.AssetNotFoundException; import com.jme3.asset.AssetNotFoundException;
import com.jme3.audio.AudioData; import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode; import com.jme3.audio.AudioNode;
/** /**
* Handles the background music being played. Is able to start and stop the music. Set the Volume of the Audio. * Handles the background and secondary music in the game.
* Allows playing, stopping, and toggling between background music and a secondary track.
*/ */
public class GameMusic extends AbstractAppState{ public class GameMusic extends AbstractAppState {
private static final Logger LOGGER = System.getLogger(GameMusic.class.getName()); private static final Logger LOGGER = System.getLogger(pp.monopoly.client.GameMusic.class.getName());
private static final Preferences PREFERENCES = getPreferences(GameMusic.class); private static final Preferences PREFERENCES = getPreferences(pp.monopoly.client.GameMusic.class);
private static final String ENABLED_PREF = "enabled"; //NON-NLS private static final String ENABLED_PREF = "enabled"; // NON-NLS
private static final String VOLUME_PREF = "volume"; //NON-NLS private static final String VOLUME_PREF = "volume"; // NON-NLS
private AudioNode music; private AudioNode mainMusic;
private AudioNode secondaryMusic;
private boolean isMainMusicPlaying = false;
private boolean isSecondaryMusicPlaying = false;
/** /**
* Checks if sound is enabled in the preferences. * Initializes the GameMusic app state and loads the background music.
*
* @return {@code true} if sound is enabled, {@code false} otherwise.
*/
public static boolean enabledInPreferences() {
return PREFERENCES.getBoolean(ENABLED_PREF, true);
}
/**
* 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);
}
/**
* Initializes the sound effects for the game.
* Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
* *
* @param stateManager The state manager * @param stateManager The state manager
* @param app The application * @param app The application instance
*/ */
@Override @Override
public void initialize(AppStateManager stateManager, Application app) { public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app); super.initialize(stateManager, app);
music = loadSound(app, "Sound/background.ogg"); mainMusic = loadSound(app, "Sound/background.ogg");
secondaryMusic = loadSound(app, "Sound/ChooseYourCharakter.ogg");
setVolume(volumeInPreferences()); setVolume(volumeInPreferences());
music.setLooping(true); if (isEnabled()) {
if (isEnabled() && music != null) { playMainMusic();
music.play();
} }
} }
@@ -71,7 +55,7 @@ public class GameMusic extends AbstractAppState{
private AudioNode loadSound(Application app, String name) { private AudioNode loadSound(Application app, String name) {
try { try {
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer); final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
sound.setLooping(false); sound.setLooping(true);
sound.setPositional(false); sound.setPositional(false);
return sound; return sound;
} }
@@ -82,41 +66,138 @@ public class GameMusic extends AbstractAppState{
} }
/** /**
* Sets the enabled state of this AppState. * Plays the main music.
* Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
*/
public void playMainMusic() {
if (!isEnabled()) {
return; // Sound is disabled
}
if (mainMusic != null && !isMainMusicPlaying) {
mainMusic.play();
isMainMusicPlaying = true;
}
}
/**
* Stops the main music.
*/
private void stopMainMusic() {
if (mainMusic != null && isMainMusicPlaying) {
mainMusic.stop();
isMainMusicPlaying = false;
}
}
/**
* Plays the secondary music and stops the main music.
* *
* @param enabled {@code true} to enable the AppState, {@code false} to disable it. */
public void playSecondaryMusic() {
if (!isEnabled()) {
stopAllMusic();
return;
}
if (isSecondaryMusicPlaying) {
return; // Secondary music is already playing
}
stopMainMusic();
if (secondaryMusic != null) {
secondaryMusic.setVolume(volumeInPreferences());
secondaryMusic.play();
isSecondaryMusicPlaying = true;
}
}
/**
* Stops the secondary music.
*/
public void stopSecondaryMusic() {
if (secondaryMusic != null && isSecondaryMusicPlaying) {
secondaryMusic.stop();
isSecondaryMusicPlaying = false;
}
}
/**
* Toggles between the background music and the secondary track.
* If the secondary track is playing, it stops and resumes the background music.
* If the background music is playing, it pauses and plays the secondary track.
*
*/
public void toggleMusic() {
if (!isEnabled()) {
stopAllMusic();
return;
}
if (isSecondaryMusicPlaying) {
stopSecondaryMusic();
playMainMusic();
} else {
stopMainMusic();
playSecondaryMusic();
}
}
/**
* Sets the audio volume for both the main and secondary tracks.
*
* @param vol The volume level (0.0f to 1.0f)
*/
public void setVolume(float vol) {
if (mainMusic != null) mainMusic.setVolume(vol);
if (secondaryMusic != null) secondaryMusic.setVolume(vol);
PREFERENCES.putFloat(VOLUME_PREF, vol);
}
/**
* Stops all music (both main and secondary).
*/
public void stopAllMusic() {
stopMainMusic();
stopSecondaryMusic();
}
/**
* Enables or disables the sound system.
* When disabled, all music stops.
*
* @param enabled {@code true} to enable, {@code false} to disable
*/ */
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
if (isEnabled() == enabled) return; if (isEnabled() == enabled) return; // Avoid redundant operations
if (music != null) { PREFERENCES.putBoolean(ENABLED_PREF, enabled);
if (enabled) {
music.play(); if (enabled) {
} else { playMainMusic();
music.stop(); } else {
} stopAllMusic();
} }
super.setEnabled(enabled); super.setEnabled(enabled);
LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); // NON-NLS
PREFERENCES.putBoolean(ENABLED_PREF, enabled); PREFERENCES.putBoolean(ENABLED_PREF, enabled);
} }
/** /**
* Toggles the game sound on or off. * Retrieves the current sound volume preference.
*
* @return The volume level (0.0f to 1.0f)
*/ */
public void toggleSound() { public static float volumeInPreferences() {
setEnabled(!isEnabled()); return PREFERENCES.getFloat(VOLUME_PREF, 0.5f);
} }
/** /**
* Sets the volume of music * Checks if sound is enabled in the preferences.
* @param vol the volume to which the music should be set *
* @return {@code true} if sound is enabled, {@code false} otherwise
*/ */
public void setVolume(float vol){ public static boolean enabledInPreferences() {
music.setVolume(vol); return PREFERENCES.getBoolean(ENABLED_PREF, true);
PREFERENCES.putFloat(VOLUME_PREF, vol);
} }
} }

View File

@@ -120,6 +120,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
winnerSound = loadSound(app, "Sound/Effects/winner.ogg"); winnerSound = loadSound(app, "Sound/Effects/winner.ogg");
looserSound = loadSound(app, "Sound/Effects/loser.ogg"); looserSound = loadSound(app, "Sound/Effects/loser.ogg");
buttonSound = loadSound(app, "Sound/Effects/button.ogg"); buttonSound = loadSound(app, "Sound/Effects/button.ogg");
setVolume(volumeInPreferences());
} }
/** /**

View File

@@ -15,6 +15,9 @@ import java.lang.System.Logger.Level;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.logging.LogManager; import java.util.logging.LogManager;
import java.awt.Image;
import javax.imageio.ImageIO;
import com.jme3.app.DebugKeysAppState; import com.jme3.app.DebugKeysAppState;
import com.jme3.app.SimpleApplication; import com.jme3.app.SimpleApplication;
@@ -30,18 +33,16 @@ import com.jme3.system.AppSettings;
import com.simsilica.lemur.GuiGlobals; import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.style.BaseStyles; import com.simsilica.lemur.style.BaseStyles;
import pp.dialog.Dialog;
import pp.dialog.DialogBuilder; import pp.dialog.DialogBuilder;
import pp.dialog.DialogManager; import pp.dialog.DialogManager;
import pp.graphics.Draw; import pp.graphics.Draw;
import static pp.monopoly.Resources.lookup; import static pp.monopoly.Resources.lookup;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.client.gui.StartMenu; 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.ClientGameLogic;
import pp.monopoly.game.client.MonopolyClient; import pp.monopoly.game.client.MonopolyClient;
import pp.monopoly.game.client.ServerConnection; import pp.monopoly.game.client.ServerConnection;
import pp.monopoly.message.client.NotificationAnswer;
import pp.monopoly.notification.ClientStateEvent; import pp.monopoly.notification.ClientStateEvent;
import pp.monopoly.notification.GameEventListener; import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent; import pp.monopoly.notification.InfoTextEvent;
@@ -123,22 +124,10 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
*/ */
private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed); private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
//TODO temp for testing /**
private EventCardPopup eventCard; * Listener for handeling Demo Mode (Minas mode)
private BuildingPropertyCard buildingProperty; */
private FoodFieldCard foodField; private final ActionListener f8Listener = (name, isPressed, tpf) -> handleF8(isPressed);
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 { static {
// Configure logging // Configure logging
@@ -183,6 +172,16 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
private AppSettings makeSettings() { private AppSettings makeSettings() {
final AppSettings settings = new AppSettings(true); final AppSettings settings = new AppSettings(true);
settings.setTitle(lookup("monopoly.name")); settings.setTitle(lookup("monopoly.name"));
try {
// Prüfen, ob das Betriebssystem ein Mac-System ist
if (!System.getProperty("os.name").toLowerCase().contains("mac")) {
settings.setIcons(new Image[]{ImageIO.read(new File("src/main/resources/icons/Uniman.png"))});
} else {
LOGGER.log(Level.INFO, "Icon setting skipped on macOS due to system restrictions.");
}
} catch (IOException e) {
LOGGER.log(Level.ERROR, e.getMessage());
}
settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight()); settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight());
settings.setFullscreen(config.fullScreen()); settings.setFullscreen(config.fullScreen());
settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer()); settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer());
@@ -267,20 +266,20 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
inputManager.setCursorVisible(false); inputManager.setCursorVisible(false);
inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE)); inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addMapping("F8", new KeyTrigger(KeyInput.KEY_F8));
inputManager.addListener(f8Listener, "F8");
inputManager.addListener(escapeListener, ESC); inputManager.addListener(escapeListener, ESC);
//TODO tmp for testing
// inputManager.addMapping("B", new KeyTrigger(KeyInput.KEY_B));
// inputManager.addListener(BListener, "B");
// inputManager.addMapping("T", new KeyTrigger(KeyInput.KEY_T));
} }
//logik zum wechselnden erscheinen und verschwinden beim drücken von B //TODO später entfernen /**
private void handleB(boolean isPressed) { * Handles the action on alt m for demo mode
* @param isPressed {@code true} is alt + m is pressed, {@code false} otherwise
*/
private void handleF8(boolean isPressed) {
if (isPressed) { if (isPressed) {
Dialog tmp = new GulagInfo(this, 3); LOGGER.log(Level.INFO, "F detected."); // Debug logging
tmp.open(); getGameLogic().send(new NotificationAnswer("hack"));
} }
} }
@@ -294,12 +293,14 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
stateManager.attach(stats); stateManager.attach(stats);
} }
flyCam.setEnabled(false); flyCam.setEnabled(false);
flyCam.setMoveSpeed(4f); // Setzt die Bewegungsgeschwindigkeit der Kamera (Standardwert ist 1f)
stateManager.detach(stateManager.getState(StatsAppState.class)); stateManager.detach(stateManager.getState(StatsAppState.class));
stateManager.detach(stateManager.getState(DebugKeysAppState.class)); stateManager.detach(stateManager.getState(DebugKeysAppState.class));
attachGameSound(); attachGameSound();
attachGameMusic(); attachGameMusic();
stateManager.attach(new GameAppState()); stateManager.attach(new BoardAppState());
} }
/** /**
@@ -333,11 +334,6 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
dialogManager.update(tpf); dialogManager.update(tpf);
logic.update(tpf); logic.update(tpf);
stateManager.update(tpf); stateManager.update(tpf);
// //TODO testing replace later
// if (testWorld != null) {
// testWorld.update(tpf);
// }
} }
/** /**
@@ -424,7 +420,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
*/ */
@Override @Override
public void receivedEvent(ClientStateEvent event) { public void receivedEvent(ClientStateEvent event) {
stateManager.getState(GameAppState.class).setEnabled(true); stateManager.getState(BoardAppState.class).setEnabled(logic.isTurn());
} }
/** /**
@@ -496,7 +492,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
/** /**
* Retrieves the unique identifier associated with the server connection. * Retrieves the unique identifier associated with the server connection.
* *
* Checks if a Server is connected and returns {@Code 0} if there is no connection * Checks if a Server is connected and returns 0 if there is no connection
* *
* @return the ID of the connected Server instance. * @return the ID of the connected Server instance.
*/ */

View File

@@ -106,6 +106,26 @@ public class MonopolyAppConfig extends MonopolyClientConfig {
@Property("overlay.top.color") //NON-NLS @Property("overlay.top.color") //NON-NLS
private ColorRGBA topColor = ColorRGBA.White; private ColorRGBA topColor = ColorRGBA.White;
private ColorRGBA applyGammaCorrection(ColorRGBA color) {
return new ColorRGBA(
correctGamma(color.r),
correctGamma(color.g),
correctGamma(color.b),
color.a // Alpha bleibt unverändert
);
}
private float correctGamma(float channel) {
// Formel: ((RGB / 255)^2.2) * 255
float normalized = channel / 255.0f; // RGB normalisieren (0-1)
float gammaCorrected = (float) Math.pow(normalized, 2.2); // ^2.2
return gammaCorrected * 255.0f; // Zurückskalieren auf 0-255
}
private float correctGamma(float channel, float gamma) {
return (float) Math.pow(channel, gamma);
}
/** /**
* Creates a default {@code MonopolyAppConfig} with predefined values. * Creates a default {@code MonopolyAppConfig} with predefined values.
*/ */

View File

@@ -0,0 +1,97 @@
package pp.monopoly.client;
import java.util.Timer;
import java.util.TimerTask;
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.ReceivedRent;
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.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;
public class PopUpManager implements GameEventListener {
private final MonopolyApp app;
public PopUpManager(MonopolyApp app) {
this.app = app;
app.getGameLogic().addListener(this);
}
@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();
}
});
}
}, 8000);
} 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();
} else if (event.msg().equals("ReceivedRent")) {
new ReceivedRent(app, ( (NotificationMessage) event.message()).getRentOwner(), ( (NotificationMessage) event.message()).getRentAmount() ).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);
}
}

View File

@@ -1,74 +0,0 @@
package pp.monopoly.client.gui;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import pp.monopoly.model.Board;
import pp.monopoly.model.Item;
import pp.monopoly.model.Visitor;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.ItemAddedEvent;
import pp.monopoly.notification.ItemRemovedEvent;
import pp.view.ModelViewSynchronizer;
/**
* Abstract base class for synchronizing the visual representation of a {@link Board} with its model state.
* This class handles the addition and removal of items from the map, ensuring that changes in the model
* are accurately reflected in the view.
*/
abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
protected final Board board;
/**
* Constructs a new BoardSynchronizer.
*
* @param board the game board to synchronize
* @param root the root node to which the view representations of the board items are attached
*/
protected BoardSynchronizer(Board board, Node root) {
super(root);
this.board = board;
}
/**
* Translates a model item into its corresponding visual representation.
*
* @param item the item from the model to be translated
* @return the visual representation of the item as a {@link Spatial}
*/
@Override
protected Spatial translate(Item item) {
return item.accept(this);
}
/**
* Adds the existing items from the board to the view during initialization.
*/
protected void addExisting() {
board.getItems().forEach(this::add);
}
/**
* Handles the event when an item is removed from the board.
*
* @param event the event indicating that an item has been removed from the board
*/
@Override
public void receivedEvent(ItemRemovedEvent event) {
if (board == event.getBoard()) {
delete(event.getItem());
}
}
/**
* Handles the event when an item is added to the board.
*
* @param event the event indicating that an item has been added to the board
*/
@Override
public void receivedEvent(ItemAddedEvent event) {
if (board == event.getBoard()) {
add(event.getItem());
}
}
}

View File

@@ -0,0 +1,147 @@
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.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.model.Figure;
import pp.monopoly.model.Hotel;
import pp.monopoly.model.House;
import pp.monopoly.model.Item;
import pp.monopoly.notification.UpdatePlayerView;
public class BobTheBuilder extends GameBoardSynchronizer {
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
private static final String COLOR = "Color"; //NON-NLS
private static final String FIGURE = "figure"; //NON-NLS
private static final String HOUSE = "house"; //NON-NLS
private static final String HOTEL = "hotel"; //NON-NLS
private final MonopolyApp app;
public BobTheBuilder(MonopolyApp app, Node root) {
super(app.getGameLogic().getBoard(), root);
this.app = app;
addExisting();
}
@Override
public Spatial visit(Figure figure) {
final Node node = new Node(FIGURE);
Spatial spatial = createFigure(figure);
node.attachChild(spatial);
// Setze die Position basierend auf der Feld-ID
node.setLocalTranslation(figure.getPos());
// Setze die Anfangsrotation auf 90 Grad nach links
Quaternion initialRotation = new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y);
node.setLocalRotation(initialRotation);
node.addControl(new FigureControl(node, figure, app));
return node;
}
@Override
public Spatial visit(Hotel hotel) {
final Node node = new Node(HOTEL);
node.attachChild(createHotel(hotel));
// Setze die Position basierend auf der Feld-ID
node.setLocalTranslation(hotel.getPos());
// Setze die Rotation basierend auf der Feld-ID
node.setLocalRotation(hotel.getRot().toQuaternion());
return node;
}
@Override
public Spatial visit(House house) {
final Node node = new Node(HOUSE);
node.attachChild(createHouse(house));
// Setze die Position basierend auf der Feld-ID
node.setLocalTranslation(house.getPos());
// Setze die Rotation basierend auf der Feld-ID
node.setLocalRotation(house.getAlignment());
return node;
}
private Spatial createFigure(Figure figure) {
// Lade das Modell
Spatial model = app.getAssetManager().loadModel("models/" + "Spielfiguren/" + figure.getType() + "/" + figure.getType() + ".j3o");
// Skaliere und positioniere das Modell
model.scale(0.5f);
return model;
}
private Spatial createHotel(Hotel hotel) {
Spatial model = app.getAssetManager().loadModel("models/Hotel/Hotel.j3o");
model.scale(0.2f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;
}
private Spatial createHouse(House house) {
Spatial model = app.getAssetManager().loadModel("models/Haus/"+house.getStage()+"Haus.j3o");
model.scale(0.5f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;
}
/**
* Creates a simple box to represent a battleship that is not of the "King George V" type.
*
* @param ship the battleship to be represented
* @return the geometry representing the battleship as a box
*/
private Spatial createBox(Item item) {
final Box box = new Box(3,
3f,
3);
final Geometry geometry = new Geometry(FIGURE, box);
geometry.setMaterial(createColoredMaterial(ColorRGBA.Blue));
geometry.setShadowMode(ShadowMode.CastAndReceive);
geometry.setLocalTranslation(0, 2, 0);
return geometry;
}
/**
* Creates a new {@link Material} with the specified color.
* If the color includes transparency (i.e., alpha value less than 1),
* the material's render state is set to use alpha blending, allowing for
* semi-transparent rendering.
*
* @param color the {@link ColorRGBA} to be applied to the material. If the alpha value
* of the color is less than 1, the material will support transparency.
* @return a {@link Material} instance configured with the specified color and,
* if necessary, alpha blending enabled.
*/
private Material createColoredMaterial(ColorRGBA color) {
final Material material = new Material(app.getAssetManager(), UNSHADED);
if (color.getAlpha() < 1f)
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
material.setColor(COLOR, color);
return material;
}
}

View File

@@ -3,64 +3,106 @@ package pp.monopoly.client.gui;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
/** import pp.monopoly.client.MonopolyApp; // Import MonopolyApp
* Controls the movement of the camera within the scene. import pp.monopoly.game.server.PlayerHandler;
*/ import pp.monopoly.notification.GameEventListener;
public class CameraController { import pp.monopoly.notification.UpdatePlayerView;
public class CameraController implements GameEventListener{
public enum CameraMode {
FOCUS_CURRENT_PLAYER,
FOCUS_SELF,
FREECAM
}
private final Camera camera; private final Camera camera;
private final float height = 25; // Height of the camera above the game board private CameraMode currentMode;
/** private PlayerHandler playerHandler; // Reference to PlayerHandler for player data
* Constructor for the CameraController. private final MonopolyApp app; // Reference to MonopolyApp for self ID
*
* @param camera The camera to be controlled public CameraController(Camera camera, MonopolyApp app) {
*/
public CameraController(Camera camera) {
this.camera = camera; this.camera = camera;
setPosition(0); this.playerHandler = app.getGameLogic().getPlayerHandler();
camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); this.app = app;
app.getGameLogic().addListener(this);
setMode(CameraMode.FOCUS_SELF); // Initialize the camera mode
}
public void setMode(CameraMode mode) {
this.currentMode = mode;
} }
/**
* Updates the camera's position and orientation.
*
* @param tpf Time per frame
*/
public void update(float tpf) { public void update(float tpf) {
camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
switch (currentMode) {
case FOCUS_CURRENT_PLAYER:
updatePosition();
break;
case FOCUS_SELF:
updatePosition();
break;
case FREECAM:
break;
default:
break;
}
} }
/** public void updatePosition() {
* Sets the camera's position based on the field ID. Vector3f newPosition = getPos();
* camera.setLocation(newPosition);
* @param fieldID The ID of the field to which the camera should move
*/ camera.lookAt(app.getGameLogic().getBoard().getFigure(app.getId()).getPos(), Vector3f.UNIT_Y);
public void setPosition(int fieldID) { camera.update();
camera.setLocation(fieldIdToVector(fieldID));
} }
/** private Vector3f getPos() {
* Sets the camera's position using specific coordinates. Vector3f pos = new Vector3f();
* switch (currentMode) {
* @param x The X-coordinate of the new camera position case FOCUS_CURRENT_PLAYER:
* @param y The Y-coordinate of the new camera position pos = app.getGameLogic().getBoard().getFigure(playerHandler.getPlayerById(0).getId()).getPos();
*/
public void setPosition(float x, float y) { case FOCUS_SELF:
camera.setLocation(new Vector3f(x, height, y)); pos = app.getGameLogic().getBoard().getFigure(app.getId()).getPos();
case FREECAM:
break;
default:
break;
}
Vector3f offset = getOffset();
pos = new Vector3f(pos.getX() + offset.getX(), pos.getY() + offset.getY(), pos.getZ() + offset.getZ());
return pos;
} }
/** private Vector3f getOffset() {
* Maps a field ID to its corresponding position in the game world. Vector3f offset = new Vector3f();
*
* @param fieldID The ID of the field int fieldId = playerHandler.getPlayerById( (currentMode == CameraMode.FOCUS_SELF ? app.getId() : playerHandler.getPlayerAtIndex(0).getId()) ).getFieldID();
* @return The position of the field as a {@link Vector3f} // System.out.println();
* @throws IllegalArgumentException If the field ID is invalid if(fieldId < 10) {
*/ offset = new Vector3f(0, 10, -15);
private Vector3f fieldIdToVector(int fieldID) { } else if(fieldId < 20) {
if (fieldID <= 10) return new Vector3f(30, height, 0); offset = new Vector3f(15 , 10, 0);
if (fieldID <= 20) return new Vector3f(0, height, 30); } else if(fieldId < 30) {
if (fieldID <= 30) return new Vector3f(-30, height, 0); offset = new Vector3f(0, 10, 15 );
if (fieldID <= 40) return new Vector3f(0, height, -30); } else {
else throw new IllegalArgumentException(); offset = new Vector3f(-15, 10, 0);
}
return offset;
} }
}
@Override
public void receivedEvent(UpdatePlayerView event) {
playerHandler = app.getGameLogic().getPlayerHandler();
}
}

View File

@@ -0,0 +1,31 @@
package pp.monopoly.client.gui;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
public class CameraInputHandler {
private CameraController cameraController;
public CameraInputHandler(CameraController cameraController, InputManager inputManager) {
this.cameraController = cameraController;
// Tasten für die verschiedenen Kameramodi registrieren
inputManager.addMapping("FocusCurrentPlayer", new KeyTrigger(KeyInput.KEY_1));
inputManager.addMapping("FocusSelf", new KeyTrigger(KeyInput.KEY_2));
inputManager.addMapping("FreeCam", new KeyTrigger(KeyInput.KEY_3));
inputManager.addListener(actionListener, "FocusCurrentPlayer", "FocusSelf", "FreeCam");
}
private final ActionListener actionListener = (name, isPressed, tpf) -> {
if (!isPressed) return;
switch (name) {
case "FocusCurrentPlayer" -> cameraController.setMode(CameraController.CameraMode.FOCUS_CURRENT_PLAYER);
case "FocusSelf" -> cameraController.setMode(CameraController.CameraMode.FOCUS_SELF);
case "FreeCam" -> cameraController.setMode(CameraController.CameraMode.FREECAM);
}
};
}

View File

@@ -0,0 +1,158 @@
package pp.monopoly.client.gui;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.scene.control.AbstractControl;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.game.client.ClientGameLogic;
import pp.monopoly.model.Figure;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.UpdatePlayerView;
// import java.lang.System.Logger;
// import java.lang.System.Logger.Level;
import java.util.LinkedList;
import java.util.Queue;
public class FigureControl extends AbstractControl implements GameEventListener {
// // // private static final Logger LOGGER = System.getLogger(FigureControl.class.getName());
private final Figure figure;
private final Node spatial;
private final MonopolyApp app;
private Queue<Vector3f> path; // Path to follow
private Vector3f currentTarget;
private float animationTime = 0f; // Time elapsed for the current movement
private final float durationPerField = 0.5f; // Time to move between fields
private float delayTime = 3f; // Verzögerung in Sekunden
private float delayElapsed = 0f; // Zeit, die seit dem Start der Verzögerung vergangen ist
public FigureControl(Node spatial, Figure figure, MonopolyApp app) {
super();
this.figure = figure;
this.spatial = spatial;
this.app = app;
this.path = new LinkedList<>();
app.getGameLogic().addListener(this);
}
@Override
protected void controlUpdate(float tpf) {
if (delayTime > 0) {
delayElapsed += tpf;
if (delayElapsed < delayTime) {
return; // Warte, bis die Verzögerung abgeschlossen ist
}
delayTime = 0; // Verzögerung abgeschlossen
}
if (currentTarget == null && !path.isEmpty()) {
// Hole das nächste Ziel aus dem Pfad
currentTarget = path.poll();
animationTime = 0f;
// Prüfe, ob eine Drehung erforderlich ist (Felder 0, 10, 20, 30)
int currentField = figure.getCurrentFieldID();
int nextField = nextField(currentField);
if ((nextField(currentField) == 10) ||
(nextField(currentField) == 20) ||
(nextField(currentField) == 30) ||
(nextField(currentField) == 0)) {
Quaternion rotation = spatial.getLocalRotation();
Quaternion turnRight = new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);
spatial.setLocalRotation(rotation.mult(turnRight));
}
}
if (currentTarget != null) {
animationTime += tpf;
Vector3f startPosition = spatial.getLocalTranslation();
Vector3f interpolatedPosition = startPosition.interpolateLocal(
currentTarget,
animationTime / durationPerField
);
// Hüpfeffekt hinzufügen
float hopHeight = 0.5f * FastMath.sin(FastMath.PI * (animationTime / durationPerField));
interpolatedPosition.setY(hopHeight );
spatial.setLocalTranslation(interpolatedPosition);
// Ziel erreicht
if (animationTime >= durationPerField) {
spatial.setLocalTranslation(currentTarget);
figure.moveTo(currentTarget); // Synchronisiere die interne Position
currentTarget = null; // Setze Ziel zurück
}
}
}
private int nextField(int currentField) {
return (currentField + 1) % 40;
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
// No rendering logic required
}
public void setPath(int startField, int endField) {
// LOGGER.log(Level.TRACE, "setPath called with startField: {0} to endField {1}", startField, endField);
path.clear();
for (int fieldId = startField; fieldId != endField; fieldId = (fieldId + 1) % 40) {
Vector3f position = figure.calculateFieldPosition(fieldId);
// LOGGER.log(Level.DEBUG, "Adding postition to path: {0}", position);
path.add(position);
}
Vector3f finalPosition = figure.calculateFieldPosition(endField);
path.add(finalPosition);
// LOGGER.log(Level.DEBUG, "Final position added to path: {0}", finalPosition);
// LOGGER.log(Level.TRACE, "Path size: {0}", path.size());
}
@Override
public void receivedEvent(UpdatePlayerView event) {
// LOGGER.log(Level.TRACE, "receivedEvent called with event: {0}", event);
int newPos = app.getGameLogic().getPlayerHandler().getPlayerById(figure.getId()).getFieldID();
int currentField = figure.getCurrentFieldID();
if (currentField == newPos) {
// LOGGER.log(Level.DEBUG, "No movement required. Current field: {0}, New field: {1}", currentField, newPos);
return;
}
// LOGGER.log(Level.DEBUG, "Movement required. Current field: {0}, New field: {1}", currentField, newPos);
setPath(currentField, newPos);
delayTime = 3f; // Verzögerung zurücksetzen
delayElapsed = 0f; // Timer zurücksetzen
}
}

View File

@@ -1,122 +1,87 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client.gui; package pp.monopoly.client.gui;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box; import pp.monopoly.model.Item;
import pp.monopoly.model.Visitor;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.notification.DiceRollEvent;
import pp.monopoly.game.server.PlayerColor; import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.ItemAddedEvent;
import pp.monopoly.notification.ItemRemovedEvent;
import pp.monopoly.notification.UpdatePlayerView;
import pp.monopoly.model.Board; import pp.monopoly.model.Board;
import pp.monopoly.model.Figure; import pp.monopoly.model.Figure;
import pp.monopoly.model.Rotation; import pp.view.ModelViewSynchronizer;
import static pp.util.FloatMath.HALF_PI;
import static pp.util.FloatMath.PI;
/** /**
* The {@code GameBoardSynchronizer} class is responsible for synchronizing the graphical * Abstract base class for synchronizing the visual representation of a {@link Board} with its model state.
* representation of the Game board and figures with the underlying data model. * This class handles the addition and removal of items from the board, ensuring that changes in the model
* It extends the {@link BoardSynchronizer} to provide specific synchronization * are accurately reflected in the view.
* logic for the Game board. * <p>
* Subclasses are responsible for providing the specific implementation of how each item in the map
* is represented visually by implementing the {@link Visitor} interface.
* </p>
*/ */
class GameBoardSynchronizer extends BoardSynchronizer { abstract class GameBoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS // The board that this synchronizer is responsible for
private static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md"; protected final Board board;
private static final String COLOR = "Color"; //NON-NLS
private static final String FIGURE = "figure"; //NON-NLS
private final MonopolyApp app;
private final ParticleEffectFactory particleFactory;
/** /**
* Constructs a {@code GameBoardSynchronizer} object with the specified application, root node, and ship map. * Constructs a new GameBoardSynchronizer.
* Initializes the synchronizer with the provided board and the root node for attaching view representations.
* *
* @param app the Monopoly application * @param map the board to be synchronized
* @param root the root node to which graphical elements will be attached * @param root the root node to which the view representations of the board items are attached
* @param map the Game Board containing fields and figures
*/ */
public GameBoardSynchronizer(MonopolyApp app, Node root, Board board) { protected GameBoardSynchronizer(Board board, Node root) {
super(board, root); super(root);
this.app = app; this.board = board;
this.particleFactory = new ParticleEffectFactory(app);
addExisting();
} }
/** /**
* Visits a {@link Figure} and creates a graphical representation of it. * Translates a model item into its corresponding visual representation.
* The representation is a 3D model. * The specific visual representation is determined by the concrete implementation of the {@link Visitor} interface.
* *
* @param figure the figure to be represented * @param item the item from the model to be translated
* @return the node containing the graphical representation of the figure * @return the visual representation of the item as a {@link Spatial}
*/ */
public Spatial visit(Figure figure) { @Override
final Node node = new Node(FIGURE); protected Spatial translate(Item item) {
node.attachChild(createBox(figure)); return item.accept(this);
final float x = 1;
final float z = 1;
node.setLocalTranslation(x, 0f, z);
return node;
} }
/** /**
* Creates a representation of a figure * Adds the existing items from the board to the view.
* * This method should be called during initialization to ensure that all current items in the board
* @param figure the figure to be represented * are visually represented.
* @return the geometry representing the figure
*/ */
private Spatial createBox(Figure figure) { protected void addExisting() {
final Box box = new Box(0.5f * (figure.getMaxY() - figure.getMinY()) + 0.3f, board.getItems().forEach(this::add);
0.3f, }
0.5f * (figure.getMaxX() - figure.getMinX()) + 0.3f);
final Geometry geometry = new Geometry(FIGURE, box);
geometry.setMaterial(createColoredMaterial(PlayerColor.PINK.getColor()));
geometry.setShadowMode(ShadowMode.CastAndReceive);
return geometry; /**
* Handles the event when an item is removed from the ship map.
* Removes the visual representation of the item from the view if it belongs to the synchronized ship map.
*
* @param event the event indicating that an item has been removed from the ship map
*/
@Override
public void receivedEvent(ItemRemovedEvent event) {
if (board == event.board())
delete(event.item());
} }
/** /**
* Creates a new {@link Material} with the specified color. * Handles the event when an item is added to the ship map.
* If the color includes transparency (i.e., alpha value less than 1), * Adds the visual representation of the new item to the view if it belongs to the synchronized ship map.
* the material's render state is set to use alpha blending, allowing for
* semi-transparent rendering.
* *
* @param color the {@link ColorRGBA} to be applied to the material. If the alpha value * @param event the event indicating that an item has been added to the ship map
* of the color is less than 1, the material will support transparency.
* @return a {@link Material} instance configured with the specified color and,
* if necessary, alpha blending enabled.
*/ */
private Material createColoredMaterial(ColorRGBA color) { @Override
final Material material = new Material(app.getAssetManager(), UNSHADED); public void receivedEvent(ItemAddedEvent event) {
if (color.getAlpha() < 1f) if (board == event.board()){
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); add(event.item());
material.setColor(COLOR, color); }
return material;
} }
/**
* Calculates the rotation angle for the specified rotation.
*
* @param rot the rotation of the battleship
* @return the rotation angle in radians
*/
private static float calculateRotationAngle(Rotation rot) {
return switch (rot) {
case RIGHT -> HALF_PI;
case DOWN -> 0f;
case LEFT -> -HALF_PI;
case UP -> PI;
};
}
} }

View File

@@ -0,0 +1,93 @@
package pp.monopoly.client.gui;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Command;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.game.server.Player;
import pp.monopoly.game.server.PlayerColor;
import pp.monopoly.notification.Sound;
public class ImageButton extends Button {
private final MonopolyApp app;
private final String functionality;
private final PlayerColor playerColor;
public ImageButton(String functionality, MonopolyApp app) {
super("", "button-clear");
this.app = app;
this.functionality = functionality;
this.playerColor = Player.getColor(app.getId());
updateButtonAppearance(ButtonState.ENABLED);
addButtonCommands();
}
/**
* Updates the button's appearance based on its state.
*
* @param state the current button state
*/
private void updateButtonAppearance(ButtonState state) {
setBackgroundTexture(state.name().toLowerCase());
}
/**
* Adds button commands for state-specific actions like hover, press, enable, and disable.
*/
private void addButtonCommands() {
addCommands(ButtonAction.Enabled, source -> updateButtonAppearance(ButtonState.ENABLED));
addCommands(ButtonAction.Disabled, source -> updateButtonAppearance(ButtonState.DISABLED));
addCommands(ButtonAction.Hover, source -> {
if (isEnabled()) {
updateButtonAppearance(ButtonState.HOVER);
}
});
addCommands(ButtonAction.HighlightOff, source -> updateButtonAppearance(isEnabled() ? ButtonState.ENABLED : ButtonState.DISABLED));
addCommands(ButtonAction.Up, source -> updateButtonAppearance(isEnabled() ? ButtonState.ENABLED : ButtonState.DISABLED));
addCommands(ButtonAction.Down, source -> {
if (isEnabled()) {
app.getGameLogic().playSound(Sound.BUTTON);
}
});
}
/**
* Sets the background texture for the button based on the given state.
*
* @param state the button state (e.g., "enabled", "disabled", "hover")
*/
private void setBackgroundTexture(String state) {
String texturePath = buildTexturePath(state);
Texture texture = app.getAssetManager().loadTexture(texturePath);
setBackground(new QuadBackgroundComponent(texture));
}
/**
* Builds the file path for the button texture.
*
* @param state the button state (e.g., "enabled", "disabled", "hover")
* @return the full file path to the texture
*/
private String buildTexturePath(String state) {
return String.format("Pictures/Buttons/Button_%s_%s_%s.png", functionality, playerColor.getColorName(), state);
}
/**
* Button states for handling appearance transitions.
*/
private enum ButtonState {
ENABLED, DISABLED, HOVER
}
public void addClickCommands( Command<? super Button> command ) {
super.addCommands(ButtonAction.Down, command);
}
@SuppressWarnings("unchecked") // because Java doesn't like var-arg generics
public void addClickCommands( Command<? super Button>... commands ) {
super.addCommands(ButtonAction.Down, commands);
}
}

View File

@@ -1,7 +1,5 @@
package pp.monopoly.client.gui; package pp.monopoly.client.gui;
import com.jme3.app.Application;
import com.jme3.app.state.BaseAppState;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
@@ -24,8 +22,9 @@ import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.monopoly.client.GameMusic;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.game.server.PlayerColor; import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.PlayerReady; import pp.monopoly.message.client.PlayerReady;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
@@ -67,6 +66,9 @@ public class LobbyMenu extends Dialog {
/** Selected player figure. */ /** Selected player figure. */
private String figure; private String figure;
private VersionedReference<Set<Integer>> selectionRef;
private Selector<String> figureDropdown;
/** /**
* Constructs the lobby menu for player configuration. * Constructs the lobby menu for player configuration.
* *
@@ -76,6 +78,10 @@ public class LobbyMenu extends Dialog {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
GameMusic music = app.getStateManager().getState(GameMusic.class);
if (music != null && music.isEnabled()) {
music.playSecondaryMusic();
}
playerInputField = new TextField("Spieler "+(app.getId()+1)); playerInputField = new TextField("Spieler "+(app.getId()+1));
// Hintergrundbild laden und hinzufügen // Hintergrundbild laden und hinzufügen
addBackgroundImage(); addBackgroundImage();
@@ -142,16 +148,16 @@ public class LobbyMenu extends Dialog {
figureDropdownContainer.setBackground(null); figureDropdownContainer.setBackground(null);
VersionedList<String> figures = new VersionedList<>(); VersionedList<String> figures = new VersionedList<>();
figures.add("Laptop"); figures.add("Computer");
figures.add("Flugzeug"); figures.add("Flugzeug");
figures.add("Jägermeister"); figures.add("Jägermeister");
figures.add("Katze"); figures.add("Katze");
figures.add("OOP"); figures.add("OOP");
figures.add("Handyholster"); figures.add("Handyholster");
figures.add("Panzer");
figureDropdown = new Selector<>(figures, "glass");
Selector<String> figureDropdown = new Selector<>(figures, "glass");
figureDropdown.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray)); figureDropdown.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
figureDropdown.setPreferredSize(new Vector3f(100, 20, 0)); figureDropdown.setPreferredSize(new Vector3f(100, 20, 0));
figureDropdownContainer.addChild(figureDropdown); figureDropdownContainer.addChild(figureDropdown);
@@ -159,10 +165,12 @@ public class LobbyMenu extends Dialog {
Vector3f dimens2 = figureDropdown.getPopupContainer().getPreferredSize(); Vector3f dimens2 = figureDropdown.getPopupContainer().getPreferredSize();
dimens2.setX( dimens.getX() ); dimens2.setX( dimens.getX() );
figureDropdown.getPopupContainer().setPreferredSize(new Vector3f(200,200,5)); figureDropdown.getPopupContainer().setPreferredSize(new Vector3f(200,200,5));
figureDropdown.getSelectionModel().setSelection(0);
figure = "Laptop";
addSelectionActionListener(figureDropdown, this::onDropdownSelectionChanged); // Create selection ref for updating
selectionRef = figureDropdown.getSelectionModel().createReference();
// Set default
figureDropdown.getSelectionModel().setSelection(0);
onDropdownSelectionChanged(figureDropdown);
Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y))); Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
buttonContainer.setPreferredSize(new Vector3f(100, 40, 0)); buttonContainer.setPreferredSize(new Vector3f(100, 40, 0));
@@ -190,6 +198,7 @@ public class LobbyMenu extends Dialog {
readyButton.setFontSize(18); // Adjust font size readyButton.setFontSize(18); // Adjust font size
readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.Green)); // Add color to match the style readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.Green)); // Add color to match the style
readyButton.addClickCommands(s -> ifTopDialog(() -> { readyButton.addClickCommands(s -> ifTopDialog(() -> {
music.toggleMusic();
toggleReady(); toggleReady();
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray)); readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
@@ -216,6 +225,7 @@ public class LobbyMenu extends Dialog {
1 // Höhere Z-Ebene für den Vordergrund 1 // Höhere Z-Ebene für den Vordergrund
); );
app.getGuiNode().attachChild(menuContainer); app.getGuiNode().attachChild(menuContainer);
} }
@@ -247,31 +257,12 @@ public class LobbyMenu extends Dialog {
// Create a material with a solid color // Create a material with a solid color
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", idToColor()); // Set the desired color material.setColor("Color", Player.getColor(app.getId()).getColor()); // Set the desired color
circleGeometry.setMaterial(material); circleGeometry.setMaterial(material);
return circleGeometry; return circleGeometry;
} }
/**
* Maps the player's ID to a corresponding color.
*
* @return the color associated with the player's ID
*/
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:
return null;
}
}
/** /**
* Toggles the player's ready state and sends the configuration to the server. * Toggles the player's ready state and sends the configuration to the server.
*/ */
@@ -288,71 +279,52 @@ public class LobbyMenu extends Dialog {
} }
/** /**
* Adds a custom action listener to a dropdown selector. * Updates the menu at regular intervals.
* Checks if the dropdown selection has been updated and invokes the selection change handler.
* *
* @param selector the selector to add the listener to * @param tpf Time per frame, in seconds, since the last update.
* @param listener the action to perform when a selection changes
*/ */
private void addSelectionActionListener(Selector<String> selector, SelectionActionListener<String> listener) { @Override
VersionedReference<Set<Integer>> selectionRef = selector.getSelectionModel().createReference(); public void update(float tpf) {
if (selectionRef.update()) {
onDropdownSelectionChanged(figureDropdown);
}
}
app.getStateManager().attach(new BaseAppState() { /**
@Override * Closes the current menu and transitions music playback.
public void update(float tpf) { * Stops the secondary music (if playing) and resumes the main background music
if (selectionRef.update()) { * if music is enabled in the preferences. Ensures smooth transitions in audio.
String selected = selectionRef.get().toString(); */
listener.onSelectionChanged(selected); @Override
} public void close() {
GameMusic music = app.getStateManager().getState(GameMusic.class);
if (music != null) {
music.stopSecondaryMusic();
if (music.isEnabled()) {
music.playMainMusic();
} }
}
@Override super.close();
protected void initialize(Application app) {
}
@Override
protected void cleanup(Application app) {
}
@Override
protected void onEnable() {
}
@Override
protected void onDisable() {
}
});
} }
/** /**
* Updates the selected figure based on the dropdown menu selection. * Updates the selected figure based on the dropdown menu selection.
* *
* @param selected the selected figure * @param selector the selected figure
*/ */
private void onDropdownSelectionChanged(String selected) { private void onDropdownSelectionChanged(Selector<String> selector) {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
switch (selected) { switch (selector.getSelectedItem()) {
case "[0]": case "Jägermeister":
figure = "Computer";
break;
case "[1]":
figure = "Flugzeug";
break;
case "[2]":
figure = "Jaegermeister"; figure = "Jaegermeister";
break; break;
case "[3]": case "Handyholster":
figure = "Katze";
break;
case "[4]":
figure = "OOP";
break;
case "[5]":
figure = "Holster"; figure = "Holster";
break; break;
default: default:
break; figure = selector.getSelectedItem();
break;
} }
} }

View File

@@ -1,22 +0,0 @@
package pp.monopoly.client.gui;
import com.jme3.effect.ParticleMesh.Type;
import pp.monopoly.client.MonopolyApp;
/**
* Factory class responsible for creating particle effects used in the game.
* This centralizes the creation of various types of particle emitters.
*/
public class ParticleEffectFactory {
private static final int COUNT_FACTOR = 1;
private static final float COUNT_FACTOR_F = 1f;
private static final boolean POINT_SPRITE = true;
private static final Type EMITTER_TYPE = POINT_SPRITE ? Type.Point : Type.Triangle;
private final MonopolyApp app;
ParticleEffectFactory(MonopolyApp app) {
this.app = app;
}
}

View File

@@ -17,8 +17,8 @@ import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.FoodField; import pp.monopoly.model.fields.FoodField;
import pp.monopoly.model.fields.GateField; import pp.monopoly.model.fields.GateField;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound;
import java.text.Collator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@@ -78,7 +78,11 @@ public class PropertyOverviewMenu extends Dialog {
// Add the "Zurück" button at the bottom // Add the "Zurück" button at the bottom
Button backButton = mainContainer.addChild(new Button("Zurück", new ElementId("button"))); Button backButton = mainContainer.addChild(new Button("Zurück", new ElementId("button")));
backButton.setPreferredSize(new Vector3f(200, 60, 0)); backButton.setPreferredSize(new Vector3f(200, 60, 0));
backButton.addClickCommands(source -> this.close()); backButton.addClickCommands(source -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Attach the main container to the GUI node // Attach the main container to the GUI node
app.getGuiNode().attachChild(mainContainer); app.getGuiNode().attachChild(mainContainer);

View File

@@ -51,7 +51,17 @@ public class SettingsMenu extends Dialog {
private final SoundSlider soundSlider; private final SoundSlider soundSlider;
/** /**
* Constructs the Menu dialog for the Battleship application. * Checkbox for toggling sound effects.
*/
private final Checkbox soundCheckbox;
/**
* Checkbox for toggling background music.
*/
private final Checkbox musicCheckbox;
/**
* Constructs the Menu dialog for the Monopoly application.
* *
* @param app the MonopolyApp instance * @param app the MonopolyApp instance
*/ */
@@ -65,11 +75,15 @@ public class SettingsMenu extends Dialog {
addChild(soundSlider); addChild(soundSlider);
addChild(new Checkbox("Soundeffekte an / aus", new StateCheckboxModel(app, GameSound.class))); soundCheckbox = new Checkbox("Soundeffekte an / aus", new StateCheckboxModel(app, GameSound.class));
addChild(soundCheckbox);
addChild(new Label("Hintergrund Musik", new ElementId("label"))); //NON-NLS addChild(new Label("Hintergrund Musik", new ElementId("label"))); //NON-NLS
addChild(new Checkbox("Musik an / aus", new StateCheckboxModel(app, GameMusic.class)));
musicCheckbox = new Checkbox("Musik an / aus", new StateCheckboxModel(app, GameMusic.class));
musicCheckbox.addClickCommands(s -> toggleMusicPreference());
addChild(musicCheckbox);
addChild(musicSlider); addChild(musicSlider);
addChild(new Button("Zurück zum Spiel", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> { addChild(new Button("Zurück zum Spiel", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> {
@@ -84,16 +98,42 @@ public class SettingsMenu extends Dialog {
} }
/** /**
* Updates the state of the load and save buttons based on the game logic. * Toggles the music preference based on the state of the musicCheckbox.
* Enables or disables background music and starts playback if enabled.
*/
private void toggleMusicPreference() {
boolean enabled = musicCheckbox.isChecked();
GameMusic gameMusic = app.getStateManager().getState(GameMusic.class);
if (gameMusic != null) {
gameMusic.setEnabled(enabled);
if (enabled) {
gameMusic.playMainMusic();
}
}
}
/**
* Updates the state of the music checkbox to match the current preferences.
* This ensures the checkbox reflects the actual enabled/disabled state of the music.
*/ */
@Override @Override
public void update() { public void update() {
GameMusic gameMusic = app.getStateManager().getState(GameMusic.class);
if (gameMusic != null) {
musicCheckbox.setChecked(gameMusic.isEnabled());
}
} }
/**
* Updates UI elements such as sliders and synchronizes the state of the settings menu.
*
* @param delta the time in seconds since the last update
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
musicSlider.update(); musicSlider.update();
soundSlider.update(); soundSlider.update();
update();
} }
/** /**

View File

@@ -65,7 +65,7 @@ public class StartMenu extends Dialog {
app.getGuiNode().attachChild(centerMenu); app.getGuiNode().attachChild(centerMenu);
// Load the Monopoly logo as a texture // Load the Monopoly logo as a texture
Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopoly.png"); Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopolyw.png");
// Create a container for the logo // Create a container for the logo
Container logoContainer = new Container(); Container logoContainer = new Container();
@@ -91,8 +91,8 @@ public class StartMenu extends Dialog {
QuadBackgroundComponent unibwBackground = new QuadBackgroundComponent(unibwTexture); QuadBackgroundComponent unibwBackground = new QuadBackgroundComponent(unibwTexture);
unibwContainer.setBackground(unibwBackground); unibwContainer.setBackground(unibwBackground);
float unibwWidth = 512; float unibwWidth = 662;
float unibwHeight = 128; float unibwHeight = 180;
unibwContainer.setPreferredSize(new Vector3f(unibwWidth, unibwHeight, 0)); unibwContainer.setPreferredSize(new Vector3f(unibwWidth, unibwHeight, 0));
unibwContainer.setLocalTranslation(new Vector3f( unibwContainer.setLocalTranslation(new Vector3f(

View File

@@ -1,563 +0,0 @@
package pp.monopoly.client.gui;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
import com.jme3.texture.Texture;
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 Spielfeld und Spielfiguren.
*/
public class TestWorld implements GameEventListener {
private final MonopolyApp app;
private PlayerHandler playerHandler;
private CameraController cameraController;
private Toolbar toolbar;
private List<String> existingHouses = new ArrayList<>();
/**
* Konstruktor für die TestWorld.
*
* @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 mit Spielfeld und Figuren.
*/
public void initializeScene() {
// Entferne bestehende Inhalte
app.getGuiNode().detachAllChildren();
app.getRootNode().detachAllChildren();
System.out.println("Szene initialisiert.");
//Füge Inhalte ein
setSkyColor();
createBoard();
addLighting();
createPlayerFigures();
toolbar = new Toolbar(app);
toolbar.open();
}
/**
* Setzt die Hintergrundfarbe der Szene auf hellblau.
*/
private void setSkyColor() {
app.getViewPort().setBackgroundColor(new com.jme3.math.ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f));
}
/**
* Erstellt das Spielfeld und fügt es zur Szene hinzu.
*/
private void createBoard() {
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);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
Texture texture = app.getAssetManager().loadTexture("Pictures/board2.png");
mat.setTexture("DiffuseMap", texture);
geom.setMaterial(mat);
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);
} catch (Exception e) {
System.err.println("Fehler beim Erstellen des Spielfelds: " + e.getMessage());
}
}
private void addLighting() {
// Direktionales Licht
DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(-0.5f, -0.7f, -1.0f).normalizeLocal());
app.getRootNode().addLight(sun);
// Umgebungslicht
AmbientLight ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.6f, 0.6f, 0.6f, 1.0f));
app.getRootNode().addLight(ambient);
}
private com.jme3.math.Quaternion calculateRotationForField(int fieldID) {
com.jme3.math.Quaternion rotation = new com.jme3.math.Quaternion();
// Berechne die Rotation basierend auf der Feld-ID
if (fieldID >= 0 && fieldID <= 9) {
// Untere Seite (0-9)
rotation.fromAngleAxis(0, Vector3f.UNIT_Y); // Richtung: nach oben
} else if (fieldID >= 10 && fieldID <= 19) {
// Rechte Seite (10-19)
rotation.fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y); // Richtung: nach links
} else if (fieldID >= 20 && fieldID <= 29) {
// Obere Seite (20-29)
rotation.fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y); // Richtung: nach unten
} else if (fieldID >= 30 && fieldID <= 39) {
// Linke Seite (30-39)
rotation.fromAngleAxis(3 * FastMath.HALF_PI, Vector3f.UNIT_Y); // Richtung: nach rechts
}
// Korrigiere die Richtung für die Quadranten 1019 und 3039 (gegenüberliegende Richtung)
if ((fieldID >= 10 && fieldID <= 19) || (fieldID >= 30 && fieldID <= 39)) {
com.jme3.math.Quaternion oppositeDirection = new com.jme3.math.Quaternion();
oppositeDirection.fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y); // 180° drehen
rotation = rotation.multLocal(oppositeDirection);
}
// Füge zusätzliche 90° nach links hinzu
com.jme3.math.Quaternion leftTurn = new com.jme3.math.Quaternion();
leftTurn.fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y); // 90° nach links
rotation = rotation.multLocal(leftTurn);
return rotation;
}
/**
* Erstellt die Spielfiguren basierend auf der bereits bekannten Spielerliste.
*/
private void createPlayerFigures() {
for (Player player : playerHandler.getPlayers()) {
try {
// Lade das Modell
com.jme3.scene.Spatial model = app.getAssetManager().loadModel(
"models/" + "Spielfiguren/" + player.getFigure().getType() + "/" + player.getFigure().getType() + ".j3o");
// Skaliere und positioniere das Modell
model.setLocalScale(0.5f);
Vector3f startPosition = calculateFieldPosition(player.getFieldID(), player.getId());
model.setLocalTranslation(startPosition);
// Setze die Rotation basierend auf der Feld-ID
model.setLocalRotation(calculateRotationForField(player.getFieldID()));
model.setName("PlayerFigure_" + player.getId());
// Füge das Modell zur Szene hinzu
app.getRootNode().attachChild(model);
} 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) {
// Füge einen Delay hinzu (z.B. 3 Sekunden)
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
app.enqueue(() -> {
// Setze die Position
Vector3f targetPosition = calculateFieldPosition(player.getFieldID(), player.getId());
figure.setLocalTranslation(targetPosition);
// Aktualisiere die Rotation basierend auf der Feld-ID
figure.setLocalRotation(calculateRotationForField(player.getFieldID()));
});
}
}, 3000); // 3000 Millisekunden Delay
} 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();
}
}
private Vector3f calculateBuildingPosition(int fieldID) {
float baseX = 0.0f;
float baseZ = 0.0f;
switch (fieldID) {
case 0: baseX = -8.4f; baseZ = -7.7f; break;
case 1: baseX = -6.3f; baseZ = -7.7f; break;
case 2: baseX = -4.7f; baseZ = -7.7f; break;
case 3: baseX = -3.1f; baseZ = -7.7f; break;
case 4: baseX = -1.4f; baseZ = -7.7f; break;
case 5: baseX = 0.2f; baseZ = -7.7f; break;
case 6: baseX = 1.8f; baseZ = -7.7f; break;
case 7: baseX = 3.5f; baseZ = -7.7f; break;
case 8: baseX = 5.1f; baseZ = -7.7f; break;
case 9: baseX = 6.7f; baseZ = -7.7f; break;
case 10: baseX = 8.2f; baseZ = -7.7f; break;
case 11: baseX = 8.2f; baseZ = -6.5f; break; //passt
case 12: baseX = 8.2f; baseZ = -4.9f; break; //passt
case 13: baseX = 8.2f; baseZ = -3.3f; break; //passt
case 14: baseX = 8.2f; baseZ = -1.6f; break; //passt
case 15: baseX = 8.2f; baseZ = 0.0f; break; //passt
case 16: baseX = 8.2f; baseZ = 1.6f; break; //passt
case 17: baseX = 8.2f; baseZ = 3.3f; break; //passt
case 18: baseX = 8.2f; baseZ = 4.9f; break; //passt
case 19: baseX = 8.2f; baseZ = 6.5f; break; //passt
case 20: baseX = 8.2f; baseZ = 7.7f; break;
case 21: baseX = 6.5f; baseZ = 7.7f; break;
case 22: baseX = 4.9f; baseZ = 7.7f; break;
case 23: baseX = 3.3f; baseZ = 7.7f; break;
case 24: baseX = 1.6f; baseZ = 7.7f; break;
case 25: baseX = 0.0f; baseZ = 7.7f; break;
case 26: baseX = -1.6f; baseZ = 7.7f; break;
case 27: baseX = -3.3f; baseZ = 7.7f; break;
case 28: baseX = -4.9f; baseZ = 7.7f; break;
case 29: baseX = -6.5f; baseZ = 7.7f; break;
case 30: baseX = -7.2f; baseZ = 7.7f; break;
case 31: baseX = -7.2f; baseZ = 6.5f; break;
case 32: baseX = -7.2f; baseZ = 4.9f; break;
case 33: baseX = -7.2f; baseZ = 3.3f; break;
case 34: baseX = -7.2f; baseZ = 1.6f; break;
case 35: baseX = -7.2f; baseZ = 0.0f; break;
case 36: baseX = -7.2f; baseZ = -1.6f; break;
case 37: baseX = -7.2f; baseZ = -3.3f; break;
case 38: baseX = -7.2f; baseZ = -4.9f; break;
case 39: baseX = -7.2f; baseZ = -6.5f; break;
default: throw new IllegalArgumentException("Ungültige Feld-ID: " + fieldID);
}
return new Vector3f(baseX, 0, baseZ);
}
private void updateHousesOnBoard() {
app.enqueue(() -> {
List<BuildingProperty> propertiesWithBuildings = app.getGameLogic().getBoardManager().getPropertiesWithBuildings();
for (BuildingProperty property : propertiesWithBuildings) {
int houseCount = property.getHouses();
int hotelCount = property.getHotel();
String uniqueIdentifier = "Building_" + property.getId() + "_" + (hotelCount > 0 ? "Hotel" : houseCount);
if (existingHouses.contains(uniqueIdentifier)) continue;
try {
String modelPath = hotelCount > 0
? "models/Hotel/Hotel.j3o"
: "models/Haus/" + houseCount + "Haus.j3o";
com.jme3.scene.Spatial buildingModel = app.getAssetManager().loadModel(modelPath);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
buildingModel.setMaterial(mat);
buildingModel.setLocalScale(0.5f);
Vector3f position = calculateBuildingPosition(property.getId()).add(0, 0.5f, 0);
buildingModel.setLocalTranslation(position);
com.jme3.math.Quaternion rotation = new com.jme3.math.Quaternion();
if (property.getId() >= 1 && property.getId() <= 10) {
rotation.fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y);
} else if (property.getId() >= 21 && property.getId() <= 30) {
rotation.fromAngleAxis(3 * FastMath.HALF_PI, Vector3f.UNIT_Y);
} else if (property.getId() >= 31 && property.getId() <= 39) {
rotation.fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y);
}
buildingModel.setLocalRotation(rotation);
buildingModel.setName(uniqueIdentifier);
app.getRootNode().attachChild(buildingModel);
existingHouses.add(uniqueIdentifier);
} catch (Exception e) {
System.err.println("Fehler beim Hinzufügen eines Gebäudes: " + e.getMessage());
}
}
});
}
@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);
}
updateHousesOnBoard();
}
}

View File

@@ -1,17 +1,24 @@
package pp.monopoly.client.gui; package pp.monopoly.client.gui;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f; import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Axis; import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button; import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.IconComponent; import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.event.MouseEventControl;
import com.simsilica.lemur.event.MouseListener;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.popups.Bankrupt; import pp.monopoly.client.gui.popups.Bankrupt;
@@ -27,90 +34,41 @@ import pp.monopoly.notification.UpdatePlayerView;
/** /**
* Represents the toolbar interface in the Monopoly application. * Represents the toolbar interface in the Monopoly application.
* <p> * Provides game controls, player information, and event handling.
* This class provides game controls, player information, and event handling
* for actions such as dice rolling, trading, and ending turns.
* Implements {@link GameEventListener} to respond to game events.
* </p>
*/ */
public class Toolbar extends Dialog implements GameEventListener { public class Toolbar extends Dialog implements GameEventListener {
/** /** The Monopoly application instance*/
* Reference to the Monopoly application instance.
*/
private final MonopolyApp app; private final MonopolyApp app;
/** The container representing the toolbar interface */
/**
* The main container for the toolbar interface.
*/
private final Container toolbarContainer; private final Container toolbarContainer;
/** The container representing the player overview information */
/**
* Container for displaying an overview of other players.
*/
private Container overviewContainer; private Container overviewContainer;
/** The container representing the player account information */
/**
* Container for displaying account-related information.
*/
private Container accountContainer; private Container accountContainer;
/** The player handler instance */
/**
* Handles player-related data and actions.
*/
private PlayerHandler playerHandler; private PlayerHandler playerHandler;
/** The label representing the left dice */
/**
* Label for the first dice display.
*/
private Label imageLabel; private Label imageLabel;
/** The label representing the right dice */
/**
* Label for the second dice display.
*/
private Label imageLabel2; private Label imageLabel2;
/** The flag to check if the dice can be rolled */
private boolean canRollDice = false;
/** /** The trade button */
* Button for rolling the dice.
*/
private Button diceButton;
/**
* Button for initiating trades.
*/
private Button tradeButton; private Button tradeButton;
/** The property menu button */
/**
* Button for accessing the property menu.
*/
private Button propertyMenuButton; private Button propertyMenuButton;
/** The end turn button */
/**
* Button for ending the player's turn.
*/
private Button endTurnButton; private Button endTurnButton;
/** The latest incoming Dice Roll Event */
private DiceRollEvent latestDiceRollEvent = null;
/** The flag to check if the bankrupt pop up is already shown */
private boolean bankruptPopUp = false;
/** /**
* Flag indicating if dice animation is ongoing. * Constructs a new {@code Toolbar} for the given {@code MonopolyApp}.
*/
private volatile boolean animatingDice = false;
/**
* Stores the most recent dice roll event.
*/
private volatile DiceRollEvent latestDiceRollEvent = null;
/**
* Constructs the toolbar for the Monopoly application.
* <p>
* Initializes the toolbar interface, adds event listeners, and sets up
* the GUI elements such as dice, buttons, and player information displays.
* </p>
* *
* @param app the Monopoly application instance * @param app The {@code MonopolyApp} instance to create the toolbar for.
*/ */
public Toolbar(MonopolyApp app) { public Toolbar(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
@@ -119,108 +77,190 @@ public class Toolbar extends Dialog implements GameEventListener {
app.getGameLogic().addListener(this); app.getGameLogic().addListener(this);
this.playerHandler = app.getGameLogic().getPlayerHandler(); this.playerHandler = app.getGameLogic().getPlayerHandler();
toolbarContainer = createToolbarContainer(); toolbarContainer = setupToolbar();
app.getGuiNode().attachChild(toolbarContainer); app.getGuiNode().attachChild(toolbarContainer);
endTurnButton.setEnabled(false);
} }
private Container createToolbarContainer() { /**
// Erstelle den Hauptcontainer * Sets up the toolbar interface with the game controls, player information, and event handling.
*
* @return The container representing the toolbar interface.
*/
private Container setupToolbar() {
Container container = new Container(new SpringGridLayout(Axis.X, Axis.Y), "toolbar"); Container container = new Container(new SpringGridLayout(Axis.X, Axis.Y), "toolbar");
container.setLocalTranslation(0, 200, 0); container.setLocalTranslation(0, 200, 0);
container.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 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);
// unterer Balken Texture backgroundToolbar = app.getAssetManager().loadTexture("Pictures/toolbarbg.png");
Container playerColorBarbot = new Container(); QuadBackgroundComponent background = new QuadBackgroundComponent(backgroundToolbar);
playerColorBarbot.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 10, 0)); // Höhe des oberen Balkens background.setMargin(0, 0); // Removes any internal margin
playerColorBarbot.setBackground(new QuadBackgroundComponent(playerColor)); container.setBackground(background);
playerColorBarbot.setLocalTranslation(0, 10, 3); // Position über der Toolbar
app.getGuiNode().attachChild(playerColorBarbot); setupBorders(container);
setupSpacer(container);
setupPlayerInfoSection(container);
// Linker Balken setupSpacer(container);
Container leftBar = new Container(); setupDiceSection(container);
leftBar.setPreferredSize(new Vector3f(10, 210, 0)); // Breite 10, Höhe 210 setupActionMenu(container);
leftBar.setBackground(new QuadBackgroundComponent(playerColor));
leftBar.setLocalTranslation(0, 200, 3); // Position am linken Rand return container;
app.getGuiNode().attachChild(leftBar); }
// Rechter Balken /**
Container rightBar = new Container(); * Sets up the borders for the toolbar interface.
rightBar.setPreferredSize(new Vector3f(10, 210, 0)); // Breite 10, Höhe 210 *
rightBar.setBackground(new QuadBackgroundComponent(playerColor)); * @param container The container representing the toolbar interface.
rightBar.setLocalTranslation(app.getCamera().getWidth() - 10, 200, 2); // Position am rechten Rand */
app.getGuiNode().attachChild(rightBar); private void setupBorders(Container container) {
addBorder(0, 205, app.getCamera().getWidth(), 5, ColorRGBA.DarkGray); // Top
// Übersicht und Konto addBorder(0, 5, app.getCamera().getWidth(), 10, ColorRGBA.DarkGray); // Bottom
accountContainer = container.addChild(new Container()); addBorder(0, 200, 8, 210, ColorRGBA.DarkGray); // Left
overviewContainer = container.addChild(new Container()); addBorder(app.getCamera().getWidth() - 5, 200, 8, 210, ColorRGBA.DarkGray); // Right
receivedEvent(new UpdatePlayerView()); // Initiale Aktualisierung }
// Würfel-Bereich /**
container.addChild(createDiceSection()); * Adds a border to the toolbar interface with the specified dimensions and color.
*
// Aktionsmenü * @param x The x-coordinate of the border.
* @param y The y-coordinate of the border.
* @param width The width of the border.
* @param height The height of the border.
* @param color The color of the border.
*/
private void addBorder(float x, float y, float width, float height, ColorRGBA color) {
Container border = new Container();
border.setPreferredSize(new Vector3f(width, height, 0));
border.setBackground(new QuadBackgroundComponent(color));
border.setLocalTranslation(x, y, 3);
app.getGuiNode().attachChild(border);
}
/**
* Adds a spacer to the specified container.
*
* @param container the container to which the spacer is added
*/
private void setupSpacer(Container container) {
Container spacer = container.addChild(new Container());
spacer.setPreferredSize(new Vector3f(20, 10, 0));
spacer.setBackground(null);
}
/**
* Sets up the player information section of the toolbar interface.
*
* @param parentContainer The container representing the toolbar interface.
*/
private void setupPlayerInfoSection(Container parentContainer) {
Container playerInfoSection = parentContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
playerInfoSection.setPreferredSize(new Vector3f(600, 300, 0)); // Adjust size for both containers
Texture backgroundTexture = app.getAssetManager().loadTexture("Pictures/"+ Player.getColor(app.getId()).getColorName()+ "Background.png");
QuadBackgroundComponent background = new QuadBackgroundComponent(backgroundTexture);
playerInfoSection.setBackground(background);
accountContainer = playerInfoSection.addChild(new Container());
accountContainer.setPreferredSize(new Vector3f(300, 300, 0));
accountContainer.setBackground(null);
overviewContainer = playerInfoSection.addChild(new Container());
overviewContainer.setPreferredSize(new Vector3f(300, 300, 0));
overviewContainer.setBackground(null);
refreshPlayerView();
}
/**
* Sets up the dice section of the toolbar interface.
*
* @param container The container representing the toolbar interface.
*/
private void setupDiceSection(Container container) {
Container diceContainer = container.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
diceContainer.addChild(createDiceDisplay());
diceContainer.setBackground(null);
}
/**
* Sets up the action menu of the toolbar interface.
*
* @param container The container representing the toolbar interface.
*/
private void setupActionMenu(Container container) {
Container menuContainer = container.addChild(new Container()); Container menuContainer = container.addChild(new Container());
menuContainer.addChild(createTradeButton()); menuContainer.addChild(createTradeButton());
menuContainer.addChild(createPropertyMenuButton()); menuContainer.addChild(createPropertyMenuButton());
menuContainer.addChild(createEndTurnButton()); menuContainer.addChild(createEndTurnButton());
menuContainer.setBackground(createBackground()); menuContainer.setBackground(null);
return container;
}
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);
return diceContainer;
} }
/**
* Creates the dice display section of the toolbar interface.
*
* @return The container representing the dice display section.
*/
private Container createDiceDisplay() { private Container createDiceDisplay() {
Container horizontalContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y)); Container horizontalContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
horizontalContainer.setPreferredSize(new Vector3f(200, 150, 0)); horizontalContainer.setPreferredSize(new Vector3f(200, 150, 0));
horizontalContainer.setBackground(null);
imageLabel = createDiceLabel("Pictures/dice/one.png"); imageLabel = createDiceLabel("Pictures/dice/one.png");
imageLabel2 = createDiceLabel("Pictures/dice/two.png"); imageLabel2 = createDiceLabel("Pictures/dice/two.png");
horizontalContainer.setBackground(null);
horizontalContainer.addChild(createDiceContainer(imageLabel)); horizontalContainer.addChild(createDiceContainer(imageLabel));
horizontalContainer.addChild(createDiceContainer(imageLabel2)); horizontalContainer.addChild(createDiceContainer(imageLabel2));
// Add mouse event control for click handling
MouseEventControl.addListenersToSpatial(horizontalContainer, new MouseListener() {
@Override
public void mouseButtonEvent(MouseButtonEvent event, Spatial target, Spatial capture) {
if (event.isPressed()) {
handleDiceRoll();
}
}
@Override
public void mouseEntered(MouseMotionEvent event, Spatial target, Spatial capture) {
// Do nothing
}
@Override
public void mouseExited(MouseMotionEvent event, Spatial target, Spatial capture) {
// Do nothing
}
@Override
public void mouseMoved(MouseMotionEvent event, Spatial target, Spatial capture) {
// Do nothing
}
});
return horizontalContainer; return horizontalContainer;
} }
/**
* Creates a dice label with the specified icon path.
*
* @param iconPath The path to the icon image.
* @return The label representing the dice.
*/
private Label createDiceLabel(String iconPath) { private Label createDiceLabel(String iconPath) {
Label label = new Label(""); Label label = new Label("");
IconComponent icon = new IconComponent(iconPath); IconComponent icon = new IconComponent(iconPath);
icon.setIconSize(new Vector2f(100, 100)); icon.setIconSize(new Vector2f(80, 80));
label.setIcon(icon); label.setIcon(icon);
return label; return label;
} }
/**
* Creates a dice container with the specified label.
*
* @param label The label representing the dice.
* @return The container representing the dice.
*/
private Container createDiceContainer(Label label) { private Container createDiceContainer(Label label) {
Container container = new Container(); Container container = new Container();
container.setBackground(null); container.setBackground(null);
@@ -229,88 +269,145 @@ public class Toolbar extends Dialog implements GameEventListener {
return container; return container;
} }
/**
* Handles the dice roll event.
*/
private void handleDiceRoll() {
ifTopDialog(() -> {
if (!canRollDice) return;
canRollDice = false;
if (endTurnButton != null) endTurnButton.setEnabled(true);
startDiceAnimation();
app.getGameLogic().send(new RollDice());
app.getGameLogic().playSound(Sound.BUTTON);
});
}
private Button createTradeButton() { private Button createTradeButton() {
tradeButton = new Button("Handeln", new ElementId("button-toolbar")); String iconPath = "icons/icon-handeln.png";
// createActionButton(playerColor, "icons/icon-handeln.png", 100, () -> new ChoosePartner(app).open());
tradeButton = new ImageButton("generic", app);
tradeButton.setPreferredSize(new Vector3f(150, 50, 0)); tradeButton.setPreferredSize(new Vector3f(150, 50, 0));
IconComponent icon = new IconComponent(iconPath);
icon.setHAlignment(HAlignment.Center);
icon.setVAlignment(VAlignment.Center);
icon.setIconSize(new Vector2f(75 , 75));
tradeButton.setIcon(icon);
tradeButton.addClickCommands(s -> ifTopDialog(() -> { tradeButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
new ChoosePartner(app).open(); new ChoosePartner(app).open();
})); }));
return tradeButton; return tradeButton;
} }
private Button createPropertyMenuButton() { private Button createPropertyMenuButton() {
propertyMenuButton = new Button("Grundstücke", new ElementId("button-toolbar"));
String iconPath = "icons/icon-gebaude.png";
propertyMenuButton = new ImageButton("generic", app);
propertyMenuButton.setPreferredSize(new Vector3f(150, 50, 0)); propertyMenuButton.setPreferredSize(new Vector3f(150, 50, 0));
propertyMenuButton.setFontSize(30);
IconComponent icon = new IconComponent(iconPath);
icon.setHAlignment(HAlignment.Center);
icon.setVAlignment(VAlignment.Center);
icon.setIconSize(new Vector2f(50 , 50));
propertyMenuButton.setIcon(icon);
propertyMenuButton.addClickCommands(s -> ifTopDialog(() -> { propertyMenuButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
new BuildingAdminMenu(app).open(); new BuildingAdminMenu(app).open();
})); }));
return propertyMenuButton; return propertyMenuButton;
} }
private Button createEndTurnButton() { private Button createEndTurnButton() {
endTurnButton = new Button("Zug beenden", new ElementId("button-toolbar")); // return createActionButton(playerColor, "icons/icon-zugbeenden.png", 75, () -> handleEndTurn());
endTurnButton.setFontSize(28);
String iconPath = "icons/icon-zugbeenden.png";
endTurnButton = new ImageButton("generic", app);
endTurnButton.setPreferredSize(new Vector3f(150, 50, 0)); endTurnButton.setPreferredSize(new Vector3f(150, 50, 0));
IconComponent icon = new IconComponent(iconPath);
icon.setHAlignment(HAlignment.Center);
icon.setVAlignment(VAlignment.Center);
icon.setIconSize(new Vector2f(50 , 50));
endTurnButton.setIcon(icon);
endTurnButton.addClickCommands(s -> ifTopDialog(() -> { endTurnButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); handleEndTurn();
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; return endTurnButton;
} }
private QuadBackgroundComponent createBackground() {
return new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)); /**
* Handles the end turn event.
*/
private void handleEndTurn() {
Player currentPlayer = playerHandler.getPlayerById(app.getId());
if (currentPlayer.getAccountBalance() < 0 && !bankruptPopUp) {
new Bankrupt(app).open();
bankruptPopUp = true;
} else {
bankruptPopUp = false;
app.getGameLogic().send(new EndTurn());
receivedEvent(new ButtonStatusEvent(false));
}
} }
/**
* Starts the dice animation.
*/
private void startDiceAnimation() { private void startDiceAnimation() {
animatingDice = true;
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
new Thread(() -> { new Thread(() -> {
try { try {
animateDice(startTime); animateDice(startTime);
animatingDice = false;
if (latestDiceRollEvent != null) { if (latestDiceRollEvent != null) {
showFinalDiceResult(latestDiceRollEvent); showFinalDiceResult(latestDiceRollEvent);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.err.println("Dice animation interrupted: " + e.getMessage()); e.printStackTrace();
} }
}).start(); }).start();
} }
/** /**
* Animates the dice roll by cycling through dice images. * Animates the dice roll.
*
* @param startTime The start time of the animation.
* @throws InterruptedException If the animation is interrupted.
*/ */
private void animateDice(long startTime) throws InterruptedException { private void animateDice(long startTime) throws InterruptedException {
int[] currentFace = {1}; int[] currentFace = {1};
while (System.currentTimeMillis() - startTime < 2000) { // Animation duration while (System.currentTimeMillis() - startTime < 2000) {
currentFace[0] = (currentFace[0] % 6) + 1; currentFace[0] = (currentFace[0] % 6) + 1;
updateDiceIcons(currentFace[0]);
String rotatingImage1 = diceToString(currentFace[0]); Thread.sleep(100);
String rotatingImage2 = diceToString((currentFace[0] % 6) + 1);
app.enqueue(() -> {
setDiceIcon(imageLabel, rotatingImage1);
setDiceIcon(imageLabel2, rotatingImage2);
});
Thread.sleep(100); // Time between frame updates
} }
} }
/** /**
* Displays the final dice result after animation. * Updates the dice icons with the specified face.
* *
* @param event the dice roll event containing the result * @param face The face of the dice.
*/
private void updateDiceIcons(int face) {
app.enqueue(() -> {
setDiceIcon(imageLabel, diceToString(face));
setDiceIcon(imageLabel2, diceToString((face % 6) + 1));
});
}
/**
* Shows the final dice result.
*
* @param event The dice roll event.
*/ */
private void showFinalDiceResult(DiceRollEvent event) { private void showFinalDiceResult(DiceRollEvent event) {
app.enqueue(() -> { app.enqueue(() -> {
@@ -318,28 +415,39 @@ public class Toolbar extends Dialog implements GameEventListener {
setDiceIcon(imageLabel2, diceToString(event.b())); setDiceIcon(imageLabel2, diceToString(event.b()));
}); });
} }
/**
* Sets the dice icon with the specified image path.
*
* @param label The label representing the dice.
* @param imagePath The path to the icon image.
*/
private void setDiceIcon(Label label, String imagePath) { private void setDiceIcon(Label label, String imagePath) {
IconComponent icon = new IconComponent(imagePath); IconComponent icon = new IconComponent(imagePath);
icon.setIconSize(new Vector2f(80, 80)); // Set consistent dice size icon.setIconSize(new Vector2f(80, 80));
label.setIcon(icon); label.setIcon(icon);
} }
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);
}
}
/** /**
* Handles dice roll events by updating the dice display. * Converts the dice number to a string representation.
*
* @param i The dice number.
* @return The string representation of the dice number.
*/
private String diceToString(int i) {
return "Pictures/dice/" + switch (i) {
case 1 -> "one";
case 2 -> "two";
case 3 -> "three";
case 4 -> "four";
case 5 -> "five";
case 6 -> "six";
default -> throw new IllegalArgumentException("Invalid dice number: " + i);
} + ".png";
}
/**
* Handles dice roll events and updates the dice display.
* *
* @param event the dice roll event containing dice values * @param event the dice roll event containing dice values
*/ */
@@ -349,67 +457,76 @@ public class Toolbar extends Dialog implements GameEventListener {
} }
/** /**
* Updates the player view with the latest account and overview data. * Updates the player view by refreshing the player information displayed on the toolbar.
* *
* @param event the update event for the player view * @param event the update player view event
*/ */
@Override @Override
public void receivedEvent(UpdatePlayerView event) { public void receivedEvent(UpdatePlayerView event) {
playerHandler = app.getGameLogic().getPlayerHandler(); playerHandler = app.getGameLogic().getPlayerHandler();
System.out.println("Update Player View"); refreshPlayerView();
}
/**
* Refreshes the player view.
*/
private void refreshPlayerView() {
accountContainer.clearChildren(); accountContainer.clearChildren();
overviewContainer.clearChildren(); overviewContainer.clearChildren();
accountContainer.addChild(new Label("Kontostand", new ElementId("label-toolbar"))); addAccountDetails();
accountContainer.addChild(new Label( addOverviewDetails();
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"))); accountContainer.setBackground(null);
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); overviewContainer.setBackground(null);
} }
/** /**
* Updates the enabled status of toolbar buttons based on the event. * Adds the account details to the player view.
*/
private void addAccountDetails() {
Player currentPlayer = playerHandler.getPlayerById(app.getId());
accountContainer.addChild(new Label("Kontostand", new ElementId("label-toolbar")));
accountContainer.addChild(new Label(currentPlayer.getAccountBalance() + " EUR", new ElementId("label-account")));
accountContainer.addChild(new Label("Gulag Karten", new ElementId("label-toolbar")));
accountContainer.addChild(new Label(String.valueOf(currentPlayer.getNumJailCard()), new ElementId("label-account")));
}
/**
* Adds the overview details to the player view.
*/
private void addOverviewDetails() {
overviewContainer.addChild(new Label("Übersicht", new ElementId("label-toolbar")));
for (Player player : playerHandler.getPlayers()) {
if (player.getId() != app.getId()) {
Label playerLabel = new Label(
player.getName() + ": " + player.getAccountBalance() + " EUR",
new ElementId("label-player")
);
playerLabel.setColor(Player.getColor(player.getId()).getColor());
overviewContainer.addChild(playerLabel);
}
}
}
/**
* Updates the status of toolbar buttons based on the provided button status event.
* Disables or enables buttons such as trade, property menu, and end turn based on the player's turn status.
* *
* @param event the button status event * @param event the button status event indicating whether the buttons should be enabled
*/ */
@Override @Override
public void receivedEvent(ButtonStatusEvent event) { public void receivedEvent(ButtonStatusEvent event) {
boolean enabled = event.buttonsEnabled(); boolean enabled = event.buttonsEnabled();
diceButton.setEnabled(enabled); canRollDice = enabled;
tradeButton.setEnabled(enabled); tradeButton.setEnabled(enabled);
propertyMenuButton.setEnabled(enabled); propertyMenuButton.setEnabled(enabled);
endTurnButton.setEnabled(enabled); endTurnButton.setEnabled(false);
} }
/** /**
* Closes the toolbar and detaches it from the GUI. * Closes the toolbar, detaching it from the GUI.
*/ */
@Override @Override
public void close() { public void close() {
@@ -430,7 +547,7 @@ public class Toolbar extends Dialog implements GameEventListener {
*/ */
@Override @Override
public void update() { public void update() {
receivedEvent(new UpdatePlayerView()); refreshPlayerView();
super.update(); super.update();
} }
} }

View File

@@ -1,168 +0,0 @@
package pp.monopoly.client.gui;
import java.util.Random;
import com.jme3.font.BitmapText;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.monopoly.client.MonopolyApp;
/**
* Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
* Die Buttons bewegen den Würfel auf dem Spielfeld.
*/
public class Toolbar2 {
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
/**
* Konstruktor für die Toolbar.
*
* @param app Die Hauptanwendung (MonopolyApp)
* @param cube Der Würfel, der bewegt werden soll
*/
public Toolbar2(MonopolyApp app, Geometry cube) {
this.app = app;
this.cube = cube;
// Erstelle die Toolbar
toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
// Setze die Position am unteren Rand und die Breite
toolbarContainer.setLocalTranslation(
0, // Links bündig
100, // Höhe über dem unteren Rand
0 // Z-Ebene
);
toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 100, 0)); // Volle Breite
// Füge Buttons zur Toolbar hinzu
initializeButtons();
// Füge die Toolbar zur GUI hinzu
app.getGuiNode().attachChild(toolbarContainer);
// Erstelle die Position-Anzeige
positionText = createPositionDisplay();
updatePositionDisplay(); // Initialisiere die Anzeige mit der Startposition
}
/**
* Initialisiert die Buttons in der Toolbar.
*/
private void initializeButtons() {
addButton("Vorwärts", 1); // Bewegung nach vorne
addButton("Rückwärts", -1); // Bewegung nach hinten
addDiceRollButton(); // Würfel-Button
}
/**
* 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 void addDiceRollButton() {
Button diceButton = new Button("Würfeln");
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
diceButton.addClickCommands(source -> rollDice());
toolbarContainer.addChild(diceButton);
}
/**
* 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
}
/**
* 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 + ")");
}
/**
* 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
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);
}
}
/**
* 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;
}
/**
* Aktualisiert die Anzeige für die aktuelle Position.
*/
private void updatePositionDisplay() {
positionText.setText("Feld-ID: " + currentPosition);
}
/**
* Entfernt die Toolbar.
*/
public void remove() {
app.getGuiNode().detachChild(toolbarContainer);
app.getGuiNode().detachChild(positionText);
}
}

View File

@@ -12,17 +12,22 @@ import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList; import com.simsilica.lemur.core.VersionedList;
import com.simsilica.lemur.core.VersionedReference; import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import com.simsilica.lemur.text.DocumentModel;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.message.client.TradeOffer; import pp.monopoly.message.client.TradeOffer;
import pp.monopoly.model.TradeHandler; import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* Represents the trade menu dialog in the Monopoly application. * Represents the trade menu dialog in the Monopoly application.
* <p> * <p>
@@ -45,11 +50,10 @@ public class TradeMenu extends Dialog {
private Geometry background; private Geometry background;
private Selector<String> leftBuildingSelector, leftSpecialCardSelector; private Selector<String> leftBuildingSelector, leftSpecialCardSelector;
private Selector<String> rightBuildingSelector, rightSpecialCardSelector; private Selector<String> rightBuildingSelector, rightSpecialCardSelector;
private TextField leftSelectionsField, rightSelectionsField; private Label leftSelectionsLabel, rightSelectionsLabel;
private TextField leftCurrencyInput, rightCurrencyInput; private TextField leftCurrencyInput, rightCurrencyInput;
private VersionedReference<Set<Integer>> leftBuildingRef, rightBuildingRef; private VersionedReference<Set<Integer>> leftBuildingRef, rightBuildingRef;
private VersionedReference<DocumentModel> leftCurrencyRef, rightCurrencyRef;
private VersionedReference<Set<Integer>> leftCardRef, rightCardRef; private VersionedReference<Set<Integer>> leftCardRef, rightCardRef;
private Set<String> rightselBuildings = new HashSet<>(); private Set<String> rightselBuildings = new HashSet<>();
@@ -199,12 +203,34 @@ public class TradeMenu extends Dialog {
* @return an iterable of property fields * @return an iterable of property fields
*/ */
private Iterable<PropertyField> getPropertyFields(boolean isLeft) { private Iterable<PropertyField> getPropertyFields(boolean isLeft) {
return app.getGameLogic() Set<PropertyField> building = app.getGameLogic()
.getBoardManager() .getBoardManager()
.getPropertyFields(app.getGameLogic() .getPropertyFields(app.getGameLogic()
.getPlayerHandler() .getPlayerHandler()
.getPlayerById(isLeft ? tradeHandler.getSender().getId() : tradeHandler.getReceiver().getId()) .getPlayerById(isLeft ? tradeHandler.getSender().getId() : tradeHandler.getReceiver().getId())
.getProperties()); .getProperties())
.stream()
.filter(p -> p instanceof BuildingProperty)
.map(p -> (BuildingProperty) p)
.filter(p -> p.getHouses() == 0)
.collect(Collectors.toSet());
Set<PropertyField> rest = app.getGameLogic()
.getBoardManager()
.getPropertyFields(app.getGameLogic()
.getPlayerHandler()
.getPlayerById(isLeft ? tradeHandler.getSender().getId() : tradeHandler.getReceiver().getId())
.getProperties())
.stream()
.filter(p -> !(p instanceof BuildingProperty))
.collect(Collectors.toSet());
List<PropertyField> combinedProperties = new ArrayList<>();
combinedProperties.addAll(building);
combinedProperties.addAll(rest);
combinedProperties = combinedProperties.stream().sorted(Comparator.comparingInt(PropertyField::getId)).collect(Collectors.toList());
return combinedProperties;
} }
/** Creates a text field for currency input. */ /** Creates a text field for currency input. */
private TextField createCurrencyInput() { private TextField createCurrencyInput() {
@@ -217,12 +243,14 @@ public class TradeMenu extends Dialog {
Container middleSection = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container middleSection = new Container(new SpringGridLayout(Axis.Y, Axis.X));
middleSection.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f))); 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:")); Label middleLabelTop = middleSection.addChild(new Label("Meine Gebäude:"));
middleLabelTop.setFontSize(24); middleLabelTop.setFontSize(24);
middleLabelTop.setTextVAlignment(VAlignment.Center);
middleLabelTop.setTextHAlignment(HAlignment.Center);
middleLabelTop.setInsets(new Insets3f(5, 5, 5, 5)); middleLabelTop.setInsets(new Insets3f(5, 5, 5, 5));
leftSelectionsField = middleSection.addChild(new TextField("")); leftSelectionsLabel = middleSection.addChild(new Label(""));
leftSelectionsField.setPreferredSize(new Vector3f(600, 50, 0)); leftSelectionsLabel.setPreferredSize(new Vector3f(600, 50, 0));
Container buttons = middleSection.addChild(new Container(new SpringGridLayout())); Container buttons = middleSection.addChild(new Container(new SpringGridLayout()));
Button cancel = new Button("Abbrechen"); Button cancel = new Button("Abbrechen");
@@ -242,12 +270,14 @@ public class TradeMenu extends Dialog {
buttons.addChild(cancel); buttons.addChild(cancel);
buttons.addChild(trade); buttons.addChild(trade);
Label middleLabelBottom = middleSection.addChild(new Label("Gebäude: Währung: Sonderkarten:")); Label middleLabelBottom = middleSection.addChild(new Label("Gebäude des Gegenspielers:"));
middleLabelBottom.setFontSize(24); middleLabelBottom.setFontSize(24);
middleLabelBottom.setTextVAlignment(VAlignment.Center);
middleLabelBottom.setTextHAlignment(HAlignment.Center);
middleLabelBottom.setInsets(new Insets3f(5, 5, 5, 5)); middleLabelBottom.setInsets(new Insets3f(5, 5, 5, 5));
rightSelectionsField = middleSection.addChild(new TextField("")); rightSelectionsLabel = middleSection.addChild(new Label(""));
rightSelectionsField.setPreferredSize(new Vector3f(600, 50, 0)); rightSelectionsLabel.setPreferredSize(new Vector3f(600, 50, 0));
return middleSection; return middleSection;
} }
@@ -307,11 +337,9 @@ public class TradeMenu extends Dialog {
private void initializeReferences() { private void initializeReferences() {
leftBuildingRef = leftBuildingSelector.getSelectionModel().createReference(); leftBuildingRef = leftBuildingSelector.getSelectionModel().createReference();
leftCardRef = leftSpecialCardSelector.getSelectionModel().createReference(); leftCardRef = leftSpecialCardSelector.getSelectionModel().createReference();
leftCurrencyRef = leftCurrencyInput.getDocumentModel().createReference();
rightBuildingRef = rightBuildingSelector.getSelectionModel().createReference(); rightBuildingRef = rightBuildingSelector.getSelectionModel().createReference();
rightCardRef = rightSpecialCardSelector.getSelectionModel().createReference(); rightCardRef = rightSpecialCardSelector.getSelectionModel().createReference();
rightCurrencyRef = rightCurrencyInput.getDocumentModel().createReference();
} }
/** /**
@@ -321,25 +349,23 @@ public class TradeMenu extends Dialog {
*/ */
@Override @Override
public void update(float delta) { public void update(float delta) {
if (leftBuildingRef.update() || leftCardRef.update() || leftCurrencyRef.update()) { if (leftBuildingRef.update() || leftCardRef.update()) {
updateSelections(leftSelectionsField, leftBuildingSelector, leftCurrencyInput, leftSpecialCardSelector, true); updateSelections(leftSelectionsLabel, leftBuildingSelector, true);
} }
if (rightBuildingRef.update() || rightCardRef.update() || rightCurrencyRef.update()) { if (rightBuildingRef.update() || rightCardRef.update()) {
updateSelections(rightSelectionsField, rightBuildingSelector, rightCurrencyInput, rightSpecialCardSelector, false); updateSelections(rightSelectionsLabel, rightBuildingSelector, false);
} }
} }
/** /**
* Updates the displayed selections for properties, currency, and cards. * Updates the displayed selections for properties.
* *
* @param target the target text field to update * @param target the target label to update
* @param building the building selector * @param building the building selector
* @param currency the currency input field
* @param card the special card selector
* @param isLeft true if updating the left column; false otherwise * @param isLeft true if updating the left column; false otherwise
*/ */
private void updateSelections(TextField target, Selector<String> building, TextField currency, Selector<String> card, boolean isLeft) { private void updateSelections(Label target, Selector<String> building, boolean isLeft) {
StringBuilder buildingText = new StringBuilder(); StringBuilder buildingText = new StringBuilder();
if (isLeft) { if (isLeft) {
if (leftselBuildings.contains(building.getSelectedItem())) { if (leftselBuildings.contains(building.getSelectedItem())) {
@@ -347,8 +373,8 @@ public class TradeMenu extends Dialog {
} else { } else {
leftselBuildings.add(building.getSelectedItem()); // Add if not already selected leftselBuildings.add(building.getSelectedItem()); // Add if not already selected
} }
for (String property : leftselBuildings) { for (String property : leftselBuildings) {
buildingText.append(property); buildingText.append(property).append(", ");
} }
} else { } else {
if (rightselBuildings.contains(building.getSelectedItem())) { if (rightselBuildings.contains(building.getSelectedItem())) {
@@ -356,14 +382,12 @@ public class TradeMenu extends Dialog {
} else { } else {
rightselBuildings.add(building.getSelectedItem()); // Add if not already selected rightselBuildings.add(building.getSelectedItem()); // Add if not already selected
} }
for (String property : rightselBuildings) { for (String property : rightselBuildings) {
buildingText.append(property); buildingText.append(property).append(", ");
} }
} }
String currencyText = currency.getText() != null ? currency.getText().trim() : ""; target.setText(buildingText.toString().replaceAll(", $", ""));
String cardText = card.getSelectedItem() != null ? card.getSelectedItem() : "";
target.setText(String.join(" | ", buildingText, currencyText, cardText));
} }
/** Opens the settings menu when the escape key is pressed. */ /** Opens the settings menu when the escape key is pressed. */

View File

@@ -910,7 +910,6 @@
} }
sliderhorsetup(); sliderhorsetup();
adjustothercolumnmodel(); adjustothercolumnmodel();
// System.out.println("Columns available: " +availableColumns);
} }
@StyleAttribute(value="visibleColumns") @StyleAttribute(value="visibleColumns")
@@ -923,7 +922,6 @@
sliderhorsetup(); sliderhorsetup();
grid.refreshGrid(); grid.refreshGrid();
refreshSelector(); refreshSelector();
// System.out.println("Columns visble: " +grid.getVisibleColumns());
} }
// Column Operations // Column Operations

View File

@@ -12,114 +12,150 @@ import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.message.server.TradeReply; import pp.monopoly.message.server.TradeReply;
import pp.monopoly.notification.Sound; 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 * Represents a confirmation dialog that appears when a trade is accepted.
* Displays a message to the user informing them that the trade was accepted.
*/ */
public class AcceptTrade extends Dialog { public class AcceptTrade extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container noMoneyWarningContainer;
private final Container backgroundContainer;
/** Semi-transparent overlay background for the dialog. */
private Geometry overlayBackground;
/** Container for the warning message content. */
private Container noMoneyWarningContainer;
/** Background container providing a border for the dialog. */
private Container backgroundContainer;
/**
* Constructs the AcceptTrade dialog.
*
* @param app the Monopoly application instance
* @param msg the trade reply message containing details about the trade
*/
public AcceptTrade(MonopolyApp app, TradeReply msg) { public AcceptTrade(MonopolyApp app, TradeReply msg) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
// Initialize GUI elements
createOverlayBackground();
createBackgroundContainer();
createWarningContainer(msg);
}
// Halbtransparentes Overlay hinzufügen /**
overlayBackground = createOverlayBackground(); * Creates a semi-transparent background overlay for the dialog.
app.getGuiNode().attachChild(overlayBackground); */
private void createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
overlayBackground = 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
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlayBackground.setMaterial(material);
overlayBackground.setLocalTranslation(0, 0, 0);
}
// Create the background container /**
* Creates the background container for the dialog.
*/
private void createBackgroundContainer() {
backgroundContainer = new Container(); backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
app.getGuiNode().attachChild(backgroundContainer); }
/**
// Hauptcontainer für die Warnung * Creates the main warning container for the dialog.
*
* @param msg the trade reply message
*/
private void createWarningContainer(TradeReply msg) {
noMoneyWarningContainer = new Container(); noMoneyWarningContainer = new Container();
noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10)); noMoneyWarningContainer.setPreferredSize(new Vector3f(550, 250, 10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an float padding = 10;
backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel // Title
Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Handel angenommen!", new ElementId("warning-title"))); Label title = noMoneyWarningContainer.addChild(new Label("Handel angenommen!", new ElementId("warning-title")));
gateFieldTitle.setFontSize(48); title.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black); title.setColor(ColorRGBA.Black);
// Text, der im Popup steht // Message
Container textContainer = noMoneyWarningContainer.addChild(new Container()); 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("Du hast " + msg.getTradeHandler().getReceiver().getName() + " einen Handel vorgeschlagen.", new ElementId("label-Text")));
textContainer.addChild(new Label("", 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.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))); textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250, -200, 0));
// Passt den textContainer an die Größe des bankruptContainers an // Confirmation button
textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0)); Button confirmButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
// Beenden-Button confirmButton.addClickCommands(source -> ifTopDialog(() -> {
Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
})); }));
}
/**
* Centers the warning and background containers on the screen.
*/
private void centerContainers() {
float padding = 10;
// Zentriere das Popup // Center main container
noMoneyWarningContainer.setLocalTranslation( noMoneyWarningContainer.setLocalTranslation(
(app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
8 8
); );
// Zentriere das Popup // Center background container with padding
backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
7 7
); );
app.getGuiNode().attachChild(noMoneyWarningContainer);
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Displays the dialog by attaching it to the GUI through the DialogManager.
*
* @return Geometrie des Overlays
*/ */
private Geometry createOverlayBackground() { @Override
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); public void show() {
Geometry overlay = new Geometry("Overlay", quad); app.getGuiNode().attachChild(overlayBackground);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); app.getGuiNode().attachChild(backgroundContainer);
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent app.getGuiNode().attachChild(noMoneyWarningContainer);
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); centerContainers();
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
} }
/** /**
* Closes the menu and removes the GUI elements. * Closes the dialog and removes the associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(noMoneyWarningContainer); // Entferne das Menü app.getGuiNode().detachChild(overlayBackground);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(noMoneyWarningContainer);
super.close(); super.close();
} }
/**
* Handles the escape key action by closing the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); new SettingsMenu(app).open();
} }
} }

View File

@@ -12,107 +12,138 @@ import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; 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 * 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 { public class Bankrupt extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container bankruptContainer;
private final Container backgroundContainer;
/** Semi-transparent overlay background for the popup. */
private Geometry overlayBackground;
/** Main container for the bankruptcy warning content. */
private Container bankruptContainer;
/** Background container providing a border for the popup. */
private Container backgroundContainer;
/**
* Constructs the bankruptcy warning popup.
*
* @param app the Monopoly application instance
*/
public Bankrupt(MonopolyApp app) { public Bankrupt(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
// Initialize the components
createOverlayBackground();
createBackgroundContainer();
createBankruptContainer();
}
// Halbtransparentes Overlay hinzufügen /**
overlayBackground = createOverlayBackground(); * Creates a semi-transparent background overlay for the popup.
app.getGuiNode().attachChild(overlayBackground); */
private void createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
overlayBackground = 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
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlayBackground.setMaterial(material);
overlayBackground.setLocalTranslation(0, 0, 0);
}
// Create the background container /**
* Creates the background container for the popup.
*/
private void createBackgroundContainer() {
backgroundContainer = new Container(); backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
app.getGuiNode().attachChild(backgroundContainer); }
/**
// Hauptcontainer für die Warnung * Creates the main container for the bankruptcy warning content.
*/
private void createBankruptContainer() {
bankruptContainer = new Container(); bankruptContainer = new Container();
bankruptContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); bankruptContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
bankruptContainer.setPreferredSize(new Vector3f(550,250,10)); bankruptContainer.setPreferredSize(new Vector3f(550, 350, 10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an // Title
backgroundContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(padding, padding, 0)); Label title = bankruptContainer.addChild(new Label("Vorsicht!", new ElementId("warning-title")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
// Titel // Text content
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()); 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.addChild(new Label(
"Du hast einen negativen Kontostand. Wenn du jetzt deinen Zug beendest, gehst du bankrott und verlierst das Spiel!\n"
+ "Dieses Pop-Up wird nicht erneut angezeigt!",
new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(-250, -200, 0));
// Passt den textContainer an die Größe des bankruptContainers an // Confirmation button
textContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(-250,-200,0)); Button confirmButton = bankruptContainer.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
confirmButton.addClickCommands(source -> ifTopDialog(this::close));
}
// Beenden-Button /**
Button quitButton = bankruptContainer.addChild(new Button("Bestätigen", new ElementId("button"))); * Centers the popup containers on the screen.
quitButton.setFontSize(32); */
quitButton.addClickCommands(source -> ifTopDialog(this::close)); private void centerContainers() {
float padding = 10;
// Center bankrupt container
// Zentriere das Popup
bankruptContainer.setLocalTranslation( bankruptContainer.setLocalTranslation(
(app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y) / 2,
8 8
); );
// Zentriere das Popup // Center background container with padding
backgroundContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(padding, padding, 0));
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
7 7
); );
app.getGuiNode().attachChild(bankruptContainer);
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Displays the popup by attaching it to the GUI.
*
* @return Geometrie des Overlays
*/ */
private Geometry createOverlayBackground() { @Override
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); public void show() {
Geometry overlay = new Geometry("Overlay", quad); app.getGuiNode().attachChild(overlayBackground);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); app.getGuiNode().attachChild(backgroundContainer);
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent app.getGuiNode().attachChild(bankruptContainer);
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); centerContainers();
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
} }
/** /**
* Closes the menu and removes the GUI elements. * Closes the popup and removes the associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(bankruptContainer); // Entferne das Menü app.getGuiNode().detachChild(overlayBackground);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(bankruptContainer);
super.close(); super.close();
} }
/**
* Handles the escape key action by closing the popup.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();
} }
} }

View File

@@ -1,6 +1,7 @@
package pp.monopoly.client.gui.popups; package pp.monopoly.client.gui.popups;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.simsilica.lemur.Button; import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
@@ -8,6 +9,7 @@ import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.message.client.BuyPropertyResponse; import pp.monopoly.message.client.BuyPropertyResponse;
@@ -16,100 +18,148 @@ import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* BuildingPropertyCard creates the popup for field information * BuildingPropertyCard creates a popup for displaying field information.
*/ */
public class BuildingPropertyCard extends Dialog { public class BuildingPropertyCard extends Dialog implements PopupDialog {
private final MonopolyApp app; private final MonopolyApp app;
private final Container buildingPropertyContainer; private final Container buildingPropertyContainer;
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs a property card popup displaying details about the building property.
*
* @param app the Monopoly application instance
*/
public BuildingPropertyCard(MonopolyApp app) { public BuildingPropertyCard(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
//Generate the corresponding field
int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID(); int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
BuildingProperty field = (BuildingProperty) new BoardManager().getFieldAtIndex(index); BuildingProperty field = (BuildingProperty) new BoardManager().getFieldAtIndex(index);
// Create the background container // Create the main container for the popup
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
attachChild(backgroundContainer);
// Hauptcontainer für die Gebäudekarte
buildingPropertyContainer = new Container(); buildingPropertyContainer = new Container();
buildingPropertyContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor())); buildingPropertyContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
addContentToContainer(buildingPropertyContainer, field);
buildingPropertyContainer.setPreferredSize(new Vector3f(360,460,1));
System.out.println(buildingPropertyContainer.getPreferredSize());
float padding = 10; // Passt den backgroundContainer an die Größe des buildingPropertyContainer an // Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray
// Add padding to the background
float padding = 10f;
backgroundContainer.setPreferredSize(buildingPropertyContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(buildingPropertyContainer.getPreferredSize().addLocal(padding, padding, 0));
//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 System.out.println(backgroundContainer.getPreferredSize());
// Die Preise werden dynamisch dem BoardManager entnommen
Container propertyValuesContainer = buildingPropertyContainer.addChild(new Container()); // Position the containers
propertyValuesContainer.addChild(new Label("„Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text"))); centerContainers(padding);
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"))); * Adds the property details and buttons to the container.
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"))); * @param container the main container for the property card
propertyValuesContainer.addChild(new Label("„-mit 1 Hotel: " + field.getAllRent().get(5) + " EUR", new ElementId("label-Text"))); * @param field the building property to display
propertyValuesContainer.addChild(new Label("„-1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text"))); */
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile private void addContentToContainer(Container container, BuildingProperty field) {
propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text"))); // Title
Label title = container.addChild(new Label(field.getName(), new ElementId("label-Bold")));
title.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
title.setFontSize(38);
// Property details
Container propertyValuesContainer = container.addChild(new Container());
propertyValuesContainer.addChild(new Label("Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
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äusern: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- mit 3 Häusern: " + field.getAllRent().get(3) + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- mit 4 Häusern: " + 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")));
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))); propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button // Add buttons
Button quitButton = buildingPropertyContainer.addChild(new Button("Beenden", new ElementId("button"))); addButtons(container);
}
/**
* Adds the buttons for closing or buying the property.
*
* @param container the main container
*/
private void addButtons(Container container) {
// Quit button
Button quitButton = container.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog( () -> { quitButton.addClickCommands(s -> ifTopDialog(() -> {
System.err.println("Button does something?");
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
})); }));
// Kaufen-Button
Button buyButton = buildingPropertyContainer.addChild(new Button("Kaufen", new ElementId("button"))); // Buy button
Button buyButton = container.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32); buyButton.setFontSize(32);
buyButton.addClickCommands(s -> ifTopDialog( () -> { buyButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
app.getGameLogic().send(new BuyPropertyResponse()); app.getGameLogic().send(new BuyPropertyResponse());
})); }));
}
// Zentriere das Popup /**
* Centers the containers on the screen.
*
* @param padding the padding size
*/
private void centerContainers(float padding) {
// Center main container
buildingPropertyContainer.setLocalTranslation( buildingPropertyContainer.setLocalTranslation(
(app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y) / 2,
8 8
); );
// Zentriere das Popup // Center background container with padding
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y + padding) / 2,
7 7
); );
}
/**
* Attaches the popup to the GUI through the DialogManager.
*/
@Override
public void show() {
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(buildingPropertyContainer); app.getGuiNode().attachChild(buildingPropertyContainer);
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the popup and removes associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(buildingPropertyContainer); // Entferne das Menü app.getGuiNode().detachChild(buildingPropertyContainer);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer);
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();
} }
} }

View File

@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.Selector; import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList; import com.simsilica.lemur.core.VersionedList;
@@ -31,16 +30,35 @@ import java.util.stream.Collectors;
* BuyHouse is a popup which appears when a player clicks on the "Buy House"-button in the BuildingAdminMenu * BuyHouse is a popup which appears when a player clicks on the "Buy House"-button in the BuildingAdminMenu
*/ */
public class BuyHouse extends Dialog { public class BuyHouse extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the "Buy House" popup UI. */
private final Container buyHouseContainer; private final Container buyHouseContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
/** Label to display selected properties. */
private Label selectionDisplay;
/** Reference for tracking dropdown selection changes. */
private VersionedReference<Set<Integer>> selectionRef; private VersionedReference<Set<Integer>> selectionRef;
/** Dropdown selector for choosing properties to build houses on. */
private Selector<String> propertySelector; private Selector<String> propertySelector;
/** Set of selected properties for house purchase. */
private Set<String> selectedProperties = new HashSet<>(); private Set<String> selectedProperties = new HashSet<>();
/** Label displaying the total cost of building houses on the selected properties. */
private Label cost = new Label("0", new ElementId("label-Text")); private Label cost = new Label("0", new ElementId("label-Text"));
/**
* Constructs the "Buy House" popup.
*
* @param app the Monopoly application instance
*/
public BuyHouse(MonopolyApp app) { public BuyHouse(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -58,7 +76,7 @@ public class BuyHouse extends Dialog {
backgroundContainer.setPreferredSize(buyHouseContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(buyHouseContainer.getPreferredSize().addLocal(padding, padding, 0));
// Title // Title
Label title = buyHouseContainer.addChild(new Label("Gebäude Kaufen", new ElementId("warning-Bold"))); Label title = buyHouseContainer.addChild(new Label("Gebäude Kaufen", new ElementId("label-Bold")));
title.setFontSize(48); title.setFontSize(48);
title.setColor(ColorRGBA.Black); title.setColor(ColorRGBA.Black);
@@ -119,14 +137,14 @@ public class BuyHouse extends Dialog {
} }
/** /**
* Creates a dropdown menu for selecting a property. * Creates a dropdown menu for selecting properties eligible for house construction.
* *
* @return The dropdown container. * @return The container holding the dropdown menu.
*/ */
private Container createPropertyDropdown() { private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0)); dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange)); dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
VersionedList<String> propertyOptions = new VersionedList<>(); VersionedList<String> propertyOptions = new VersionedList<>();
List<BuildingProperty> playerProperties = getPlayerProperties(); List<BuildingProperty> playerProperties = getPlayerProperties();
@@ -143,8 +161,9 @@ public class BuyHouse extends Dialog {
selectionRef = propertySelector.getSelectionModel().createReference(); selectionRef = propertySelector.getSelectionModel().createReference();
// Initialize the selection display here // Initialize the selection display here
selectionDisplay = new TextField(""); // Create TextField for displaying selections selectionDisplay = new Label("");
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0)); selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
selectionDisplay.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection // Set initial selection
@@ -154,10 +173,11 @@ public class BuyHouse extends Dialog {
return dropdownContainer; return dropdownContainer;
} }
/** /**
* Retrieves the list of properties owned by the current player. * Retrieves the list of properties owned by the current player that are eligible for house construction.
* *
* @return List of BuildingProperty objects owned by the player. * @return A list of {@link BuildingProperty} objects owned by the player.
*/ */
private List<BuildingProperty> getPlayerProperties() { private List<BuildingProperty> getPlayerProperties() {
Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()); Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
@@ -170,6 +190,11 @@ public class BuyHouse extends Dialog {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Periodically updates the popup, tracking selection changes in the dropdown menu.
*
* @param delta Time since the last update in seconds.
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
if(selectionRef.update()) { if(selectionRef.update()) {
@@ -178,7 +203,9 @@ public class BuyHouse extends Dialog {
} }
/** /**
* Handles property selection changes. * Handles property selection changes in the dropdown menu.
*
* @param playerProperties the dropdown selector for the player's properties
*/ */
private void onDropdownSelectionChanged(Selector<String> playerProperties) { private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem(); String selected = playerProperties.getSelectedItem();
@@ -200,6 +227,9 @@ public class BuyHouse extends Dialog {
this.cost.setText(cost+""); this.cost.setText(cost+"");
} }
/**
* Closes the popup and removes its GUI elements.
*/
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(buyHouseContainer); app.getGuiNode().detachChild(buyHouseContainer);
@@ -207,6 +237,9 @@ public class BuyHouse extends Dialog {
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -7,11 +7,11 @@ import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.client.gui.TradeMenu; import pp.monopoly.client.gui.TradeMenu;
import pp.monopoly.message.client.TradeResponse; import pp.monopoly.message.client.TradeResponse;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.model.TradeHandler; import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
@@ -19,65 +19,82 @@ import pp.monopoly.notification.Sound;
/** /**
* ConfirmTrade is a popup which appears when a trade is proposed to this certain player. * ConfirmTrade is a popup which appears when a trade is proposed to this certain player.
*/ */
public class ConfirmTrade extends Dialog { public class ConfirmTrade extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Container confirmTradeContainer;
private final Container backgroundContainer;
private TradeHandler tradeHandler;
/** Main container for the "Confirm Trade" popup UI. */
private Container confirmTradeContainer;
/** Background container providing a border for the popup. */
private Container backgroundContainer;
/** The trade handler managing the details of the trade proposal. */
private final TradeHandler tradeHandler;
/**
* Constructs the "Confirm Trade" popup.
*
* @param app the Monopoly application instance
*/
public ConfirmTrade(MonopolyApp app) { public ConfirmTrade(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
tradeHandler = app.getGameLogic().getTradeHandler(); this.tradeHandler = app.getGameLogic().getTradeHandler();
// Create the background container // Initialize components
createBackgroundContainer();
createConfirmTradeContainer();
}
/**
* Initializes the background container.
*/
private void createBackgroundContainer() {
backgroundContainer = new Container(); backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
attachChild(backgroundContainer); }
// Hauptcontainer für das Bestätigungspopup /**
* Initializes the main confirm trade container and its UI components.
*/
private void createConfirmTradeContainer() {
confirmTradeContainer = new Container(); confirmTradeContainer = new Container();
float padding = 10; // Passt den backgroundContainer an die Größe des confirmTradeContainer an // Title
backgroundContainer.setPreferredSize(confirmTradeContainer.getPreferredSize().addLocal(padding, padding, 0)); Label title = confirmTradeContainer.addChild(new Label("Handel", new ElementId("warning-title")));
// Titel
Label title = confirmTradeContainer.addChild(new Label( "Handel", new ElementId("warning-title")));
title.setFontSize(48); title.setFontSize(48);
title.setColor(ColorRGBA.Black); title.setColor(ColorRGBA.Black);
// Build trade information strings
StringBuilder offeredProperties = new StringBuilder(); StringBuilder offeredProperties = new StringBuilder();
for (PropertyField field : tradeHandler.getOfferedProperties()) { for (PropertyField field : tradeHandler.getOfferedProperties()) {
offeredProperties.append(field.getName()); offeredProperties.append(field.getName()).append(", ");
offeredProperties.append(", ");
} }
StringBuilder requestedProperties = new StringBuilder(); StringBuilder requestedProperties = new StringBuilder();
for (PropertyField field : tradeHandler.getRequestedProperties()) { for (PropertyField field : tradeHandler.getRequestedProperties()) {
requestedProperties.append(field.getName()); requestedProperties.append(field.getName()).append(", ");
requestedProperties.append(", ");
} }
// Text, der auf der Karte steht // Trade details
// Die Werte werden dem Handel entnommen (Iwas auch immer da dann ist)
Container propertyValuesContainer = confirmTradeContainer.addChild(new Container()); Container propertyValuesContainer = confirmTradeContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Spieler " + tradeHandler.getSender().getName() + " möchte:", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label( tradeHandler.getSender().getName() + " möchte:", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- " + offeredProperties, new ElementId("label-Text"))); 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.getOfferedAmount() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedJailCards() +" Sonderkaten", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedJailCards() + " Sonderkarten", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("gegen:", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("gegen:", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- "+ requestedProperties, new ElementId("label-Text"))); 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.getRequestedAmount() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedJailCards() +" Sonderkaten", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("- " + tradeHandler.getRequestedJailCards() + " Sonderkarten", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("tauschen, willst du das Angebot annehmen?", new ElementId("label-Text"))); 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))); propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Ablehnen-Button // Decline button
Button declineButton = confirmTradeContainer.addChild(new Button("Ablehnen", new ElementId("button"))); Button declineButton = confirmTradeContainer.addChild(new Button("Ablehnen", new ElementId("button")));
declineButton.setFontSize(32); declineButton.setFontSize(32);
declineButton.addClickCommands(s -> ifTopDialog(() -> { declineButton.addClickCommands(s -> ifTopDialog(() -> {
@@ -85,52 +102,66 @@ public class ConfirmTrade extends Dialog {
app.getGameLogic().send(new TradeResponse(false, tradeHandler)); app.getGameLogic().send(new TradeResponse(false, tradeHandler));
close(); close();
})); }));
// Verhandeln-Button
// Negotiate button
Button negotiateButton = confirmTradeContainer.addChild(new Button("Verhandeln", new ElementId("button"))); Button negotiateButton = confirmTradeContainer.addChild(new Button("Verhandeln", new ElementId("button")));
negotiateButton.setFontSize(32); negotiateButton.setFontSize(32);
negotiateButton.addClickCommands(s -> ifTopDialog( () -> { negotiateButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
TradeHandler t = new TradeHandler(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getSender().getId())); TradeHandler t = new TradeHandler(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getSender().getId()));
t.setReceiver(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getReceiver().getId())); t.setReceiver(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getReceiver().getId()));
new TradeMenu(app, t).open(); new TradeMenu(app, t).open();
})); }));
// Confirm-Button
// Confirm button
Button confirmButton = confirmTradeContainer.addChild(new Button("Bestätigen", new ElementId("button"))); Button confirmButton = confirmTradeContainer.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32); confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog( () -> { confirmButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new TradeResponse(true, tradeHandler)); app.getGameLogic().send(new TradeResponse(true, tradeHandler));
close(); close();
})); }));
}
// Zentriere das Menü /**
* Displays the popup by attaching it to the GUI.
*/
@Override
public void show() {
float padding = 10;
// Center and adjust sizes
backgroundContainer.setPreferredSize(confirmTradeContainer.getPreferredSize().addLocal(padding, padding, 0));
confirmTradeContainer.setLocalTranslation( confirmTradeContainer.setLocalTranslation(
(app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y) / 2,
8 8
); );
// Zentriere das Menü
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y + padding) / 2,
7 7
); );
// Attach to GUI node
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(confirmTradeContainer); app.getGuiNode().attachChild(confirmTradeContainer);
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the popup and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(confirmTradeContainer); // Entferne das Menü app.getGuiNode().detachChild(confirmTradeContainer);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer);
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -12,108 +12,135 @@ import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* EventCardPopup is a popup which appears when a certain EventCard is triggered by entering a EventCardField * EventCardPopup is a popup which appears when a certain EventCard is triggered by entering an EventCardField.
*/ */
public class EventCardPopup extends Dialog { public class EventCardPopup extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container eventCardContainer;
private final Container backgroundContainer;
private final String description;
/** Semi-transparent overlay background for the popup. */
private Geometry overlayBackground;
/** Main container for the event card information. */
private Container eventCardContainer;
/** Background container providing a border for the popup. */
private Container backgroundContainer;
/**
* Constructs the EventCardPopup to display the details of a triggered event card.
*
* @param app the Monopoly application instance
* @param description the description of the triggered event card
*/
public EventCardPopup(MonopolyApp app, String description) { public EventCardPopup(MonopolyApp app, String description) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
this.description = description;
// Halbtransparentes Overlay hinzufügen // Initialize the UI components
overlayBackground = createOverlayBackground(); createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground); createBackgroundContainer();
createEventCardContainer(description);
}
// Create the background container /**
* Initializes the semi-transparent background overlay.
*/
private void createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
overlayBackground = 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);
overlayBackground.setMaterial(material);
overlayBackground.setLocalTranslation(0, 0, 0);
}
/**
* Initializes the background container.
*/
private void createBackgroundContainer() {
backgroundContainer = new Container(); backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
app.getGuiNode().attachChild(backgroundContainer); }
// Hauptcontainer für die Eventcard /**
* Initializes the main event card container and its UI components.
*
* @param description the description of the triggered event card
*/
private void createEventCardContainer(String description) {
eventCardContainer = new Container(); eventCardContainer = new Container();
eventCardContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); eventCardContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
eventCardContainer.setPreferredSize(new Vector3f(550,400,10)); eventCardContainer.setPreferredSize(new Vector3f(550, 400, 10));
float padding = 10; // Passt den backgroundContainer an die Größe des eventCardContainers an // Title
backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0)); Label title = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
// Titel // Event description
Label gateFieldTitle = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title"))); Container textContainer = eventCardContainer.addChild(new Container());
gateFieldTitle.setFontSize(48); textContainer.addChild(new Label(description, new ElementId("label-Text")));
gateFieldTitle.setColor(ColorRGBA.Black); textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(new Vector3f(300, 200, 0));
// Text, der auf der Karte steht // Confirm button
// Die Erklärungsfelder werden automatisch den descriptions der Message entnommen Button confirmButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
Container propertyValuesContainer = eventCardContainer.addChild(new Container()); confirmButton.setFontSize(32);
propertyValuesContainer.addChild(new Label(description, new ElementId("label-Text"))); confirmButton.addClickCommands(source -> ifTopDialog(() -> {
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 -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
})); }));
}
// Zentriere das Popup /**
* Displays the popup by attaching it to the GUI.
*/
@Override
public void show() {
float padding = 10;
// Adjust sizes and center elements
backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
eventCardContainer.setLocalTranslation( eventCardContainer.setLocalTranslation(
(app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y) / 2,
10 8
); );
// Zentriere das Popup
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y + padding) / 2,
9 7
); );
// Attach components to the GUI
app.getGuiNode().attachChild(overlayBackground);
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(eventCardContainer); app.getGuiNode().attachChild(eventCardContainer);
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Closes the popup and removes its associated GUI elements.
*
* @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 @Override
public void close() { public void close() {
app.getGuiNode().detachChild(eventCardContainer); // Entferne das Menü app.getGuiNode().detachChild(overlayBackground);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(eventCardContainer);
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(backgroundContainer);
super.close(); super.close();
} }
/**
* Handles the escape key action by closing the popup.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();
} }
} }

View File

@@ -3,6 +3,7 @@ package pp.monopoly.client.gui.popups;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode; import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button; import com.simsilica.lemur.Button;
@@ -12,131 +13,158 @@ import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.message.client.BuyPropertyResponse; import pp.monopoly.message.client.BuyPropertyResponse;
import pp.monopoly.model.fields.FoodField; import pp.monopoly.model.fields.FoodField;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* FoodFieldCard creates the popup for field information * FoodFieldCard creates the popup for field information.
*/ */
public class FoodFieldCard extends Dialog { public class FoodFieldCard extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container foodFieldContainer;
private final Container backgroundContainer;
/** Semi-transparent overlay background for the popup. */
private Geometry overlayBackground;
/** Main container for the food field information. */
private Container foodFieldContainer;
/** Background container providing a border for the popup. */
private Container backgroundContainer;
/**
* Constructs a FoodFieldCard popup displaying details about a food field.
*
* @param app the Monopoly application instance
*/
public FoodFieldCard(MonopolyApp app) { public FoodFieldCard(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
//Generate the corresponfing field // Retrieve field information
int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID(); int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index); FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen // Create UI elements
overlayBackground = createOverlayBackground(); createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground); createBackgroundContainer();
createFoodFieldContainer(field);
}
// Create the background container /**
* Initializes the semi-transparent background overlay.
*/
private void createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
overlayBackground = 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
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlayBackground.setMaterial(material);
overlayBackground.setLocalTranslation(0, 0, 0);
}
/**
* Initializes the background container.
*/
private void createBackgroundContainer() {
backgroundContainer = new Container(); backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
attachChild(backgroundContainer);
// Hauptcontainer für die Gebäudekarte }
/**
* Initializes the main food field container and its UI components.
*
* @param field the food field information to display
*/
private void createFoodFieldContainer(FoodField field) {
foodFieldContainer = new Container(); foodFieldContainer = new Container();
foodFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f))); foodFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
foodFieldContainer.setPreferredSize(new Vector3f(360,445,1));
float padding = 10; // Passt den backgroundContainer an die Größe des foodFieldContainers an // Title
backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0)); Label title = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
title.setFontSize(48);
title.setColor(ColorRGBA.White);
// Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe // Field details
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()); Container propertyValuesContainer = foodFieldContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
propertyValuesContainer.addChild(new Label("Wenn man Besitzer des", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("Miete: 40x Würfel-Augen,", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label(field.getName()+" ist, so ist die", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("„wenn Besitzer eines ", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Miete 40-mal so hoch, wie", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("„Restaurants.", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Augen auf den zwei Würfeln sind.", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("„Miete: 100x Würfel-Augen, ", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile propertyValuesContainer.addChild(new Label("„wenn Besitzer eines ", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man Besitzer beider", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("Restaurants.", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Restaurants ist, so ist die", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
propertyValuesContainer.addChild(new Label("Miete 100-mal so hoch, wie", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Augen auf den zwei Würfeln sind.", 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.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))); propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button // Quit button
Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button"))); Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog( () -> { quitButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
})); }));
// Kaufen-Button
// Buy button
Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button"))); Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32); buyButton.setFontSize(32);
buyButton.addClickCommands(s -> ifTopDialog( () -> { buyButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new BuyPropertyResponse()); app.getGameLogic().send(new BuyPropertyResponse());
close(); close();
})); }));
}
// Zentriere das Popup /**
* Displays the popup by attaching its elements to the GUI.
*/
@Override
public void show() {
float padding = 10;
// Adjust sizes and center elements
backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
foodFieldContainer.setLocalTranslation( foodFieldContainer.setLocalTranslation(
(app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y) / 2,
8 8
); );
// Zentriere das Popup
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y + padding) / 2,
7 7
); );
// Attach components to the GUI
app.getGuiNode().attachChild(overlayBackground);
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(foodFieldContainer); app.getGuiNode().attachChild(foodFieldContainer);
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Closes the popup and removes its associated GUI elements.
*
* @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 @Override
public void close() { public void close() {
app.getGuiNode().detachChild(foodFieldContainer); // Entferne das Menü app.getGuiNode().detachChild(overlayBackground);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(foodFieldContainer);
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(backgroundContainer);
super.close(); super.close();
} }
/**
* Handles the escape key action by closing the popup.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); close();
} }
} }

View File

@@ -1,16 +1,15 @@
package pp.monopoly.client.gui.popups; 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.ColorRGBA;
import com.jme3.scene.Geometry; import com.jme3.math.Vector3f;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button; import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.message.client.BuyPropertyResponse; import pp.monopoly.message.client.BuyPropertyResponse;
@@ -18,113 +17,131 @@ import pp.monopoly.model.fields.GateField;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* GateFieldCard creates the popup for field information * GateFieldCard creates the popup for field information.
*/ */
public class GateFieldCard extends Dialog { public class GateFieldCard extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Container gateFieldContainer;
private final Container backgroundContainer;
/** Main container for the gate field information. */
private Container gateFieldContainer;
/** Background container providing a border for the popup. */
private Container backgroundContainer;
/**
* Constructs a GateFieldCard popup displaying details about a gate field.
*
* @param app the Monopoly application instance
*/
public GateFieldCard(MonopolyApp app) { public GateFieldCard(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
//Generate the corresponfing field // Generate the corresponding field
int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID(); int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
GateField field = (GateField) app.getGameLogic().getBoardManager().getFieldAtIndex(index); GateField field = (GateField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
// Create the background container // Initialize UI elements
backgroundContainer = new Container(); createBackgroundContainer();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background createGateFieldContainer(field);
attachChild(backgroundContainer); }
// Hauptcontainer für die Gebäudekarte /**
* Initializes the background container.
*/
private void createBackgroundContainer() {
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
}
/**
* Initializes the main gate field container and its UI components.
*
* @param field the gate field information to display
*/
private void createGateFieldContainer(GateField field) {
gateFieldContainer = new Container(); gateFieldContainer = new Container();
//TODO: Set the size of the container to the size of the screen @Simon
gateFieldContainer.setPreferredSize(new Vector3f(360,460,1));
gateFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); gateFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
float padding = 10; // Passt den backgroundContainer an die Größe des gateFieldContainers an // Title
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"))); Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
gateFieldTitle.setFontSize(48); gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black); gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der auf der Karte steht // Field details
// Die Preise werden dynamisch dem BoardManager entnommen
Container propertyValuesContainer = gateFieldContainer.addChild(new Container()); Container propertyValuesContainer = gateFieldContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
propertyValuesContainer.addChild(new Label("Miete: 250 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("Wenn man 2 Tore", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("2 Bahnhof besitzt: 500 EUR", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("besitzt: 500 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("Wenn man 3 Tore", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("3 Bahnhof besitzt: 1000 EUR", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("besitzt: 1000 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("Wenn man 4 Tore", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("4 Bahnhof besitzt: 2000 EUR", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("besitzt: 2000 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", 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))); propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button // Quit button
Button quitButton = gateFieldContainer.addChild(new Button("Beenden", new ElementId("button"))); Button quitButton = gateFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog( () -> { quitButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
})); }));
// Kaufen-Button
// Buy button
Button buyButton = gateFieldContainer.addChild(new Button("Kaufen", new ElementId("button"))); Button buyButton = gateFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32); buyButton.setFontSize(32);
buyButton.addClickCommands(s -> ifTopDialog( () -> { buyButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new BuyPropertyResponse()); app.getGameLogic().send(new BuyPropertyResponse());
close(); close();
})); }));
}
// Zentriere das Popup /**
* Displays the popup by attaching its elements to the GUI.
*/
@Override
public void show() {
float padding = 10;
// Adjust sizes and center elements
backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
gateFieldContainer.setLocalTranslation( gateFieldContainer.setLocalTranslation(
(app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2,
8 8
); );
// Zentriere das Popup
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y + padding) / 2,
7 7
); );
// Attach components to the GUI
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(gateFieldContainer); app.getGuiNode().attachChild(gateFieldContainer);
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Closes the popup and removes its associated GUI elements.
*
* @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 @Override
public void close() { public void close() {
app.getGuiNode().detachChild(gateFieldContainer); // Entferne das Menü app.getGuiNode().detachChild(gateFieldContainer); // Remove main container
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer); // Remove background container
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -11,106 +11,131 @@ import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* Gulag is a warning popup that is triggered when a certain player enters the "Wache" field * Gulag is a warning popup triggered when a player lands on the "Wache" field in the Monopoly game.
* <p>
* This popup informs the player that they are being sent to the Gulag and includes a confirmation button.
* </p>
*/ */
public class Gulag extends Dialog { public class Gulag extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container gulagContainer;
private final Container backgroundContainer;
/** Semi-transparent overlay background for the popup. */
private Geometry overlayBackground;
/** Main container for the Gulag warning message. */
private Container gulagContainer;
/** Background container providing a border for the popup. */
private Container backgroundContainer;
/**
* Constructs the Gulag popup.
*
* @param app the Monopoly application instance
*/
public Gulag(MonopolyApp app) { public Gulag(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
// Initialize UI elements
createOverlayBackground();
createBackgroundContainer();
createGulagContainer();
}
// Halbtransparentes Overlay hinzufügen /**
overlayBackground = createOverlayBackground(); * Creates the semi-transparent overlay background for the popup.
app.getGuiNode().attachChild(overlayBackground); */
private void createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
overlayBackground = 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);
overlayBackground.setMaterial(material);
overlayBackground.setLocalTranslation(0, 0, 0);
}
// Create the background container /**
* Creates the background container providing a border for the popup.
*/
private void createBackgroundContainer() {
backgroundContainer = new Container(); backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
app.getGuiNode().attachChild(backgroundContainer); }
/**
* Creates the main container for the Gulag warning message.
// Hauptcontainer für die Warnung */
private void createGulagContainer() {
gulagContainer = new Container(); gulagContainer = new Container();
gulagContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); gulagContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
gulagContainer.setPreferredSize(new Vector3f(550,250,10)); gulagContainer.setPreferredSize(new Vector3f(550, 250, 10));
float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an // Title
backgroundContainer.setPreferredSize(gulagContainer.getPreferredSize().addLocal(padding, padding, 0)); Label title = gulagContainer.addChild(new Label("Du kommst ins Gulag!", new ElementId("warning-title")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
// Titel // Confirmation Button
Label gateFieldTitle = gulagContainer.addChild(new Label("Du kommst ins Gulag!", new ElementId("warning-title"))); Button confirmButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button")));
gateFieldTitle.setFontSize(48); confirmButton.setFontSize(32);
gateFieldTitle.setColor(ColorRGBA.Black); confirmButton.addClickCommands(source -> ifTopDialog(() -> {
// Beenden-Button
Button quitButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
})); }));
}
/**
* Displays the popup by attaching its elements to the GUI.
*/
@Override
public void show() {
float padding = 10;
// Zentriere das Popup // Adjust and position the containers
backgroundContainer.setPreferredSize(gulagContainer.getPreferredSize().addLocal(padding, padding, 0));
gulagContainer.setLocalTranslation( gulagContainer.setLocalTranslation(
(app.getCamera().getWidth() - gulagContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - gulagContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + gulagContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + gulagContainer.getPreferredSize().y) / 2,
8 8
); );
// Zentriere das Popup
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - gulagContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - gulagContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + gulagContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + gulagContainer.getPreferredSize().y + padding) / 2,
7 7
); );
// Attach components to the GUI
app.getGuiNode().attachChild(overlayBackground);
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(gulagContainer); app.getGuiNode().attachChild(gulagContainer);
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Closes the popup and removes its associated GUI elements.
*
* @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 @Override
public void close() { public void close() {
app.getGuiNode().detachChild(gulagContainer); // Entferne das Menü app.getGuiNode().detachChild(overlayBackground);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(gulagContainer);
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(backgroundContainer);
super.close(); super.close();
} }
/**
* Handles the escape action by closing the popup.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();
} }
} }

View File

@@ -7,114 +7,148 @@ import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.message.client.NotificationAnswer; import pp.monopoly.message.client.NotificationAnswer;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* ConfirmTrade is a popup which appears when a trade is proposed to this certain player. * GulagInfo is a popup that provides options for a player who is stuck in the "Gulag" (jail) field.
* This dialog offers multiple actions, including paying a bribe, using a "Get Out of Jail" card, or waiting.
*/ */
public class GulagInfo extends Dialog { public class GulagInfo extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Container gulagInfoContainer;
private final Container backgroundContainer;
/** Main container for the Gulag information dialog. */
private Container gulagInfoContainer;
/** Background container providing a styled border around the dialog. */
private Container backgroundContainer;
/**
* Constructs a GulagInfo popup that provides the player with options for getting out of the "Gulag" field.
*
* @param app the Monopoly application instance
* @param trys the number of failed attempts to roll doubles for release
*/
public GulagInfo(MonopolyApp app, int trys) { public GulagInfo(MonopolyApp app, int trys) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
// Create the background container // Initialize UI components
createBackgroundContainer();
createGulagInfoContainer(trys);
}
/**
* Creates the background container providing a border for the dialog.
*/
private void createBackgroundContainer() {
backgroundContainer = new Container(); backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
attachChild(backgroundContainer); }
// Hauptcontainer für das Bestätigungspopup /**
* Creates the main container for the Gulag information dialog.
*
* @param trys the number of failed attempts to roll doubles for release
*/
private void createGulagInfoContainer(int trys) {
gulagInfoContainer = new Container(); gulagInfoContainer = new Container();
gulagInfoContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
float padding = 10; // Passt den backgroundContainer an die Größe des confirmTradeContainer an // Title
backgroundContainer.setPreferredSize(gulagInfoContainer.getPreferredSize().addLocal(padding, padding, 0)); Label title = gulagInfoContainer.addChild(new Label("Gulag", new ElementId("warning-title")));
// Titel
Label title = gulagInfoContainer.addChild(new Label( "Gulag", new ElementId("warning-title")));
title.setFontSize(48); title.setFontSize(48);
title.setColor(ColorRGBA.Black); title.setColor(ColorRGBA.Black);
// Text, der auf der Karte steht // Text Description
// Die Werte werden dem Handel entnommen (Iwas auch immer da dann ist) Container textContainer = gulagInfoContainer.addChild(new Container());
Container propertyValuesContainer = gulagInfoContainer.addChild(new Container()); textContainer.addChild(new Label("„Du sitzt im Gefängnis und kommst nicht raus ...", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("„Du sitzt im Gefänginis und kommst nicht raus ...", new ElementId("label-Text"))); textContainer.addChild(new Label("Es sei denn, du ...", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Es sei denn, du ...", new ElementId("label-Text")));// Leerzeile textContainer.addChild(new Label("- bestichst die Wache mit 500 EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); textContainer.addChild(new Label("- löst eine Gulag-Frei-Karte ein", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- bestichst die Wache mit 500 EUR", new ElementId("label-Text"))); textContainer.addChild(new Label("- wartest 3 Runden und bezahlst dann", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- löst eine Gulag-Frei-Karte ein", new ElementId("label-Text"))); textContainer.addChild(new Label("- oder du würfelst einen Pasch", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- wartest 3 Runden und bezahlst dann", new ElementId("label-Text")));// Leerzeile textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
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)));
// Action Buttons
addActionButtons(trys);
}
// Bezahlen-Button /**
* Adds action buttons to the dialog.
*
* @param trys the number of failed attempts to roll doubles for release
*/
private void addActionButtons(int trys) {
// Bribe Button
Button payButton = gulagInfoContainer.addChild(new Button("Bestechungsgeld bezahlen", new ElementId("button"))); Button payButton = gulagInfoContainer.addChild(new Button("Bestechungsgeld bezahlen", new ElementId("button")));
payButton.setFontSize(32); payButton.setFontSize(32);
payButton.addClickCommands(s -> ifTopDialog( () -> { payButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new NotificationAnswer("PayJail")); app.getGameLogic().send(new NotificationAnswer("PayJail"));
close(); close();
})); }));
// Ereigniskarte-Button
Button eventCardButton = gulagInfoContainer.addChild(new Button("Ereigniskarte nutzen", new ElementId("button"))); // Use Jail-Free Card Button
Button eventCardButton = gulagInfoContainer.addChild(new Button("Ereigniskarte nutzen", new ElementId("button-toolbar2")));
eventCardButton.setFontSize(32); eventCardButton.setFontSize(32);
eventCardButton.addClickCommands(s -> ifTopDialog( () -> { eventCardButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new NotificationAnswer("UseJailCard")); app.getGameLogic().send(new NotificationAnswer("UseJailCard"));
close(); close();
})); }));
// Schließen-Button
// Close Button
Button closeButton = gulagInfoContainer.addChild(new Button("Schließen", new ElementId("button"))); Button closeButton = gulagInfoContainer.addChild(new Button("Schließen", new ElementId("button")));
closeButton.setFontSize(32); closeButton.setFontSize(32);
closeButton.addClickCommands(s -> ifTopDialog(() -> { closeButton.addClickCommands(s -> ifTopDialog(this::close));
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Menü // Disable options based on conditions
if (app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getNumJailCard() == 0) {
eventCardButton.setEnabled(false);
}
if (trys == 3) {
closeButton.setEnabled(false);
}
}
/**
* Displays the popup by attaching its elements to the GUI.
*/
@Override
public void show() {
float padding = 10;
// Adjust the background size
backgroundContainer.setPreferredSize(gulagInfoContainer.getPreferredSize().addLocal(padding, padding, 0));
// Center the dialog and background
gulagInfoContainer.setLocalTranslation( gulagInfoContainer.setLocalTranslation(
(app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y) / 2,
8 8
); );
// Zentriere das Menü
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y + padding) / 2,
7 7
); );
if(app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getNumJailCard() == 0) { // Attach containers to the GUI
eventCardButton.setEnabled(false); app.getGuiNode().attachChild(backgroundContainer);
}
if(trys == 3) {
closeButton.setEnabled(false);
}
app.getGuiNode().attachChild(gulagInfoContainer); app.getGuiNode().attachChild(gulagInfoContainer);
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the GulagInfo popup and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(gulagInfoContainer); // Entferne das Menü app.getGuiNode().detachChild(gulagInfoContainer); // Remove dialog
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer); // Remove background
super.close(); super.close();
} }
@Override
public void escape() {
new SettingsMenu(app).open();
}
} }

View File

@@ -16,10 +16,23 @@ import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/**
* LooserPopUp is a dialog that appears when a player loses the game.
* <p>
* This popup provides a message of encouragement and an option to quit the game.
* </p>
*/
public class LooserPopUp extends Dialog { public class LooserPopUp extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the dialog. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the "Looser" dialog UI. */
private final Container LooserContainer; private final Container LooserContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
@@ -95,9 +108,9 @@ public class LooserPopUp extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return The overlay geometry.
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -111,7 +124,7 @@ public class LooserPopUp extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the LooserPopUp dialog and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -121,6 +134,9 @@ public class LooserPopUp extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -12,88 +12,52 @@ import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
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 * NoMoneyWarning is a warning popup that informs the player they lack sufficient funds to proceed with an action.
*/ */
public class NoMoneyWarning extends Dialog { public class NoMoneyWarning extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the warning popup. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the NoMoneyWarning dialog UI. */
private final Container noMoneyWarningContainer; private final Container noMoneyWarningContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs a new NoMoneyWarning dialog.
*
* @param app The MonopolyApp instance.
*/
public NoMoneyWarning(MonopolyApp app) { public NoMoneyWarning(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground(); overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground); backgroundContainer = createBackgroundContainer();
noMoneyWarningContainer = createNoMoneyWarningContainer();
// Create the background container adjustPaddingAndCenter();
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ü. * Creates the semi-transparent overlay background.
* *
* @return Geometrie des Overlays * @return The geometry representing the overlay background.
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad); Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material); overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0); overlay.setLocalTranslation(0, 0, 0);
@@ -101,18 +65,94 @@ public class NoMoneyWarning extends Dialog {
} }
/** /**
* Closes the menu and removes the GUI elements. * Creates the background container for the dialog.
*
* @return A styled container for the dialog background.
*/
private Container createBackgroundContainer() {
Container container = new Container();
container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray
return container;
}
/**
* Creates the main container for the NoMoneyWarning dialog UI.
*
* @return The container for the dialog content.
*/
private Container createNoMoneyWarningContainer() {
Container container = new Container();
container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
container.setPreferredSize(new Vector3f(550, 250, 10));
// Title
Label title = container.addChild(new Label("Na, schon wieder Pleite?", new ElementId("warning-title")));
title.setFontSize(38);
title.setColor(ColorRGBA.Black);
// Warning message
Container textContainer = container.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)));
textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
// Confirmation button
Button confirmButton = container.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
confirmButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
return container;
}
/**
* Adjusts the padding and centers the dialog on the screen.
*/
private void adjustPaddingAndCenter() {
float padding = 10;
backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
noMoneyWarningContainer.setLocalTranslation(
(app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
8
);
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
7
);
}
/**
* Displays the dialog by attaching its components to the GUI node.
*/
@Override
public void show() {
app.getGuiNode().attachChild(overlayBackground);
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(noMoneyWarningContainer);
}
/**
* Closes the dialog and removes its components from the GUI node.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(noMoneyWarningContainer); // Entferne das Menü app.getGuiNode().detachChild(overlayBackground);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(noMoneyWarningContainer);
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();
} }
} }

View File

@@ -0,0 +1,157 @@
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.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound;
/**
* ReceivedRent is a popup that informs a player about rent they have received.
*/
public class ReceivedRent extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app;
/** Semi-transparent overlay background for the popup. */
private Geometry overlayBackground;
/** Main container for the rent information and action. */
private Container rentContainer;
/** Background container providing a border for the rent popup. */
private Container backgroundContainer;
/**
* Constructs the ReceivedRent popup displaying the rent amount and payer.
*
* @param app the Monopoly application instance
* @param playerName the name of the player who paid the rent
* @param amount the amount of rent received
*/
public ReceivedRent(MonopolyApp app, String playerName, int amount) {
super(app.getDialogManager());
this.app = app;
// Initialize GUI elements
createOverlayBackground();
createBackgroundContainer();
createRentContainer(playerName, amount);
}
/**
* Creates a semi-transparent overlay background.
*/
private void createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
overlayBackground = 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);
overlayBackground.setMaterial(material);
overlayBackground.setLocalTranslation(0, 0, 0);
}
/**
* Creates the background container with styling.
*/
private void createBackgroundContainer() {
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
}
/**
* Creates the main rent container with title, text, and button.
*
* @param playerName the name of the player who paid the rent
* @param amount the rent amount
*/
private void createRentContainer(String playerName, int amount) {
rentContainer = new Container();
rentContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
rentContainer.setPreferredSize(new Vector3f(550, 250, 10));
// Title
Label title = rentContainer.addChild(new Label("Miete!", new ElementId("warning-title")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
// Rent message
Container textContainer = rentContainer.addChild(new Container());
textContainer.addChild(new Label(playerName + " zahlt dir " + amount + " EUR Miete",
new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(-250, -200, 0));
// Confirmation button
Button confirmButton = rentContainer.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
}
/**
* 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
);
}
/**
* Displays the popup by attaching it to the GUI through the DialogManager.
*/
@Override
public void show() {
app.getGuiNode().attachChild(overlayBackground);
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(rentContainer);
centerContainers();
}
/**
* Closes the popup and removes GUI elements.
*/
@Override
public void close() {
app.getGuiNode().detachChild(overlayBackground);
app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(rentContainer);
super.close();
}
/**
* Handles the escape action to close the dialog.
*/
@Override
public void escape() {
close();
}
}

View File

@@ -12,114 +12,154 @@ import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.message.server.TradeReply; import pp.monopoly.message.server.TradeReply;
import pp.monopoly.notification.Sound; 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 * RejectTrade is a popup that appears when a trade proposal is rejected by another player.
* Displays a message indicating the rejection and provides an option to close the popup.
*/ */
public class RejectTrade extends Dialog { public class RejectTrade extends Dialog implements PopupDialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the popup. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
private final Container noMoneyWarningContainer;
/** Main container for the rejection message content. */
private final Container rejectTradeContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs the RejectTrade popup displaying the rejection of a trade proposal.
*
* @param app the Monopoly application instance
* @param msg the trade reply message containing details about the rejected trade
*/
public RejectTrade(MonopolyApp app, TradeReply msg) { public RejectTrade(MonopolyApp app, TradeReply msg) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground(); overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground); backgroundContainer = createBackgroundContainer();
rejectTradeContainer = createRejectTradeContainer(msg);
// Create the background container adjustPaddingAndCenter();
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ü. * Creates the semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return the geometry of the overlay
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad); Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material); overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0); overlay.setLocalTranslation(0, 0, 0);
return overlay; return overlay;
} }
/**
* Creates the background container for the dialog.
*
* @return A styled container for the dialog background.
*/
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 container for the RejectTrade dialog UI.
*
* @param msg the trade reply message containing details about the rejected trade
* @return The container for the rejection message and action button
*/
private Container createRejectTradeContainer(TradeReply msg) {
Container container = new Container();
container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
container.setPreferredSize(new Vector3f(550, 250, 10));
// Title
Label title = container.addChild(new Label("Handel abgelehnt!", new ElementId("warning-title")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
// Rejection message
Container textContainer = container.addChild(new Container());
textContainer.addChild(new Label("Du hast " + 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)));
textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
// Confirmation button
Button confirmButton = container.addChild(new Button("Bestätigen", new ElementId("button")));
confirmButton.setFontSize(32);
confirmButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
return container;
}
/**
* Adjusts the padding and centers the dialog on the screen.
*/
private void adjustPaddingAndCenter() {
float padding = 10;
backgroundContainer.setPreferredSize(rejectTradeContainer.getPreferredSize().addLocal(padding, padding, 0));
rejectTradeContainer.setLocalTranslation(
(app.getCamera().getWidth() - rejectTradeContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + rejectTradeContainer.getPreferredSize().y) / 2,
8
);
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
7
);
}
/**
* Displays the popup by attaching its elements to the GUI node.
*/
@Override
public void show() {
app.getGuiNode().attachChild(overlayBackground);
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(rejectTradeContainer);
}
/** /**
* Closes the menu and removes the GUI elements. * Closes the menu and removes the GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(noMoneyWarningContainer); // Entferne das Menü app.getGuiNode().detachChild(overlayBackground);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(rejectTradeContainer);
super.close(); super.close();
} }
/**
* Handles the escape key action by closing the popup.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();
} }
} }

View File

@@ -12,14 +12,20 @@ import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.PopupDialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* Rent popup is triggered when a player enters a field owned by another player and needs to pay rent. * Rent is a popup that is triggered when a player lands on a property owned by another player
* and needs to pay rent in the Monopoly application.
* <p>
* Displays the rent amount and the recipient player's name, with an option to confirm the payment.
* </p>
*/ */
public class Rent extends Dialog { public class Rent extends Dialog implements PopupDialog {
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground; private final Geometry overlayBackground;
private final Container rentContainer; private final Container rentContainer;
private final Container backgroundContainer; private final Container backgroundContainer;
@@ -28,98 +34,66 @@ public class Rent extends Dialog {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
// Create the overlay // Create the overlay and containers
overlayBackground = createOverlayBackground(); overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create and position the background container
backgroundContainer = createBackgroundContainer(); backgroundContainer = createBackgroundContainer();
app.getGuiNode().attachChild(backgroundContainer);
// Create and position the rent container
rentContainer = createRentContainer(playerName, amount); rentContainer = createRentContainer(playerName, amount);
app.getGuiNode().attachChild(rentContainer);
// Center containers (positioning logic only, no GUI attachment)
centerContainers(); centerContainers();
} }
/**
* Creates a semi-transparent overlay background.
*
* @return the overlay geometry
*/
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad); Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); 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.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f));
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material); overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0); overlay.setLocalTranslation(0, 0, 0);
return overlay; return overlay;
} }
/**
* Creates the background container with styling.
*
* @return the styled background container
*/
private Container createBackgroundContainer() { private Container createBackgroundContainer() {
Container container = new Container(); Container container = new Container();
container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
return container; 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) { private Container createRentContainer(String playerName, int amount) {
Container container = new Container(); Container container = new Container();
container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray)); container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
container.setPreferredSize(new Vector3f(550, 250, 10)); container.setPreferredSize(new Vector3f(550, 250, 10));
// Title
Label title = container.addChild(new Label("Miete!", new ElementId("warning-title"))); Label title = container.addChild(new Label("Miete!", new ElementId("warning-title")));
title.setFontSize(48); title.setFontSize(48);
title.setColor(ColorRGBA.Black); title.setColor(ColorRGBA.Black);
// Rent message
Container textContainer = container.addChild(new Container()); Container textContainer = container.addChild(new Container());
textContainer.addChild(new Label("Du musst Spieler " + playerName + " " + amount + " EUR Miete zahlen", textContainer.addChild(new Label("Du musst " + amount + " EUR Miete an " + playerName + " zahlen",
new ElementId("label-Text"))); new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0)); textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
// Payment button
Button payButton = container.addChild(new Button("Überweisen", new ElementId("button"))); Button payButton = container.addChild(new Button("Überweisen", new ElementId("button")));
payButton.setFontSize(32); payButton.setFontSize(32);
payButton.addClickCommands(s -> ifTopDialog( () -> { payButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
})); }));
return container; return container;
} }
/**
* Centers the rent and background containers on the screen.
*/
private void centerContainers() { private void centerContainers() {
float padding = 10; float padding = 10;
// Center rent container
rentContainer.setLocalTranslation( rentContainer.setLocalTranslation(
(app.getCamera().getWidth() - rentContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - rentContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + rentContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + rentContainer.getPreferredSize().y) / 2,
8 8
); );
// Center background container with padding
backgroundContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(padding, padding, 0));
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
@@ -128,22 +102,25 @@ public class Rent extends Dialog {
); );
} }
/** @Override
* Closes the popup and removes GUI elements. public void show() {
*/ // Attach components to GUI only when the dialog is displayed via DialogManager
app.getGuiNode().attachChild(overlayBackground);
app.getGuiNode().attachChild(backgroundContainer);
app.getGuiNode().attachChild(rentContainer);
}
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(rentContainer);
app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(overlayBackground); app.getGuiNode().detachChild(overlayBackground);
app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(rentContainer);
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();
} }
} }

View File

@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.Selector; import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList; import com.simsilica.lemur.core.VersionedList;
@@ -28,20 +27,43 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* RepayMortage is a popup which appears when a player clicks on the "Repay Mortage"-button in the BuildingAdminMenu * RepayMortage is a popup that appears when a player selects the "Repay Mortgage" option
* in the Building Administration Menu.
* <p>
* This popup allows the player to select mortgaged properties and repay their mortgages,
* showing the total cost of the repayment. Includes options to confirm or cancel the repayment.
* </p>
*/ */
public class RepayMortage extends Dialog { public class RepayMortage extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the mortgage repayment menu. */
private final Container repayMortageContainer; private final Container repayMortageContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
/** Label to display selected properties. */
private Label selectionDisplay;
/** Reference to track property selections in the dropdown menu. */
private VersionedReference<Set<Integer>> selectionRef; private VersionedReference<Set<Integer>> selectionRef;
/** Dropdown menu for selecting mortgaged properties. */
private Selector<String> propertySelector; private Selector<String> propertySelector;
/** Set of selected properties for mortgage repayment. */
private Set<String> selectedProperties = new HashSet<>(); private Set<String> selectedProperties = new HashSet<>();
/** Label displaying the total repayment cost. */
private Label cost = new Label("0", new ElementId("label-Text")); private Label cost = new Label("0", new ElementId("label-Text"));
/**
* Constructs the RepayMortage popup for handling mortgage repayment.
*
* @param app the Monopoly application instance
*/
public RepayMortage(MonopolyApp app) { public RepayMortage(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -59,7 +81,7 @@ public class RepayMortage extends Dialog {
backgroundContainer.setPreferredSize(repayMortageContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(repayMortageContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel // Titel
Label title = repayMortageContainer.addChild(new Label( "Hypothek Abbezahlen", new ElementId("warining-Bold"))); Label title = repayMortageContainer.addChild(new Label( "Hypothek Abbezahlen", new ElementId("label-Bold")));
title.setFontSize(48); title.setFontSize(48);
title.setColor(ColorRGBA.Black); title.setColor(ColorRGBA.Black);
@@ -74,7 +96,7 @@ public class RepayMortage extends Dialog {
upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
middleContainer.setPreferredSize(new Vector3f(100, 150, 0)); middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange)); middleContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
middleContainer.addChild(createPropertyDropdown()); middleContainer.addChild(createPropertyDropdown());
@@ -126,7 +148,7 @@ public class RepayMortage extends Dialog {
private Container createPropertyDropdown() { private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0)); dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange)); dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
VersionedList<String> propertyOptions = new VersionedList<>(); VersionedList<String> propertyOptions = new VersionedList<>();
List<PropertyField> playerProperties = getPlayerProperties(); List<PropertyField> playerProperties = getPlayerProperties();
@@ -143,8 +165,9 @@ public class RepayMortage extends Dialog {
selectionRef = propertySelector.getSelectionModel().createReference(); selectionRef = propertySelector.getSelectionModel().createReference();
// Initialize the selection display here // Initialize the selection display here
selectionDisplay = new TextField(""); // Create TextField for displaying selections selectionDisplay = new Label(""); // Create TextField for displaying selections
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0)); selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
selectionDisplay.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection // Set initial selection
@@ -154,6 +177,7 @@ public class RepayMortage extends Dialog {
return dropdownContainer; return dropdownContainer;
} }
/** /**
* Retrieves the list of properties owned by the current player. * Retrieves the list of properties owned by the current player.
* *
@@ -170,6 +194,11 @@ public class RepayMortage extends Dialog {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Updates the UI based on selection changes in the dropdown menu.
*
* @param delta the time elapsed since the last update
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
if(selectionRef.update()) { if(selectionRef.update()) {
@@ -178,7 +207,9 @@ public class RepayMortage extends Dialog {
} }
/** /**
* Handles property selection changes. * Handles changes in the property selection and updates the total repayment cost.
*
* @param playerProperties the dropdown menu for selecting properties
*/ */
private void onDropdownSelectionChanged(Selector<String> playerProperties) { private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem(); String selected = playerProperties.getSelectedItem();
@@ -201,7 +232,7 @@ public class RepayMortage extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the popup and removes its associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -210,6 +241,9 @@ public class RepayMortage extends Dialog {
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -1,17 +1,12 @@
package pp.monopoly.client.gui.popups; package pp.monopoly.client.gui.popups;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.simsilica.lemur.Axis; import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button; import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.ListBox;
import com.simsilica.lemur.Selector; 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.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList; import com.simsilica.lemur.core.VersionedList;
@@ -32,20 +27,43 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* SellHouse is a popup which appears when a player clicks on the "demolish"-button in the BuildingAdminMenu * SellHouse is a popup that appears when a player clicks on the "Demolish" button
* in the BuildingAdminMenu.
* <p>
* This dialog allows players to select their properties and demolish houses or hotels
* for a partial refund of their purchase cost.
* </p>
*/ */
public class SellHouse extends Dialog { public class SellHouse extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the SellHouse dialog UI. */
private final Container sellhouseContainer; private final Container sellhouseContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
/** Label to display selected properties. */
private Label selectionDisplay;
/** Reference to track selection changes in the property selector. */
private VersionedReference<Set<Integer>> selectionRef; private VersionedReference<Set<Integer>> selectionRef;
/** Dropdown selector for displaying available properties. */
private Selector<String> propertySelector; private Selector<String> propertySelector;
/** Set of properties selected for selling. */
private Set<String> selectedProperties = new HashSet<>(); private Set<String> selectedProperties = new HashSet<>();
/** Label to display the total refund amount for the selected properties. */
private Label cost = new Label("0", new ElementId("label-Text")); private Label cost = new Label("0", new ElementId("label-Text"));
/**
* Constructs a new SellHouse dialog.
*
* @param app The MonopolyApp instance.
*/
public SellHouse(MonopolyApp app) { public SellHouse(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -63,11 +81,11 @@ public class SellHouse extends Dialog {
backgroundContainer.setPreferredSize(sellhouseContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(sellhouseContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel // Titel
Label title = sellhouseContainer.addChild(new Label( "Gebäude Abreißen", new ElementId("warining-Bold"))); Label title = sellhouseContainer.addChild(new Label( "Gebäude Abreißen", new ElementId("label-Bold")));
title.setFontSize(48); title.setFontSize(48);
title.setColor(ColorRGBA.Black); title.setColor(ColorRGBA.Black);
//Unterteilund des sellHouseContainer in drei "Untercontainer" //Unterteilung des sellHouseContainer in drei "Untercontainer"
Container upContainer = sellhouseContainer.addChild(new Container()); Container upContainer = sellhouseContainer.addChild(new Container());
Container middleContainer = sellhouseContainer.addChild(new Container()); Container middleContainer = sellhouseContainer.addChild(new Container());
Container downContainer = sellhouseContainer.addChild(new Container()); Container downContainer = sellhouseContainer.addChild(new Container());
@@ -100,13 +118,7 @@ public class SellHouse extends Dialog {
confirmButton.addClickCommands(s -> ifTopDialog( () -> { confirmButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
AlterProperty msg = new AlterProperty("SellHouse"); 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())); 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); app.getGameLogic().send(msg);
close(); close();
})); }));
@@ -136,7 +148,7 @@ public class SellHouse extends Dialog {
private Container createPropertyDropdown() { private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0)); dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange)); dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
VersionedList<String> propertyOptions = new VersionedList<>(); VersionedList<String> propertyOptions = new VersionedList<>();
List<BuildingProperty> playerProperties = getPlayerProperties(); List<BuildingProperty> playerProperties = getPlayerProperties();
@@ -153,8 +165,9 @@ public class SellHouse extends Dialog {
selectionRef = propertySelector.getSelectionModel().createReference(); selectionRef = propertySelector.getSelectionModel().createReference();
// Initialize the selection display here // Initialize the selection display here
selectionDisplay = new TextField(""); // Create TextField for displaying selections selectionDisplay = new Label("");
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0)); selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
selectionDisplay.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection // Set initial selection
@@ -180,6 +193,11 @@ public class SellHouse extends Dialog {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Updates the dialog UI, tracking changes in the property selection.
*
* @param delta Time since the last update.
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
if(selectionRef.update()) { if(selectionRef.update()) {
@@ -188,7 +206,9 @@ public class SellHouse extends Dialog {
} }
/** /**
* Handles property selection changes. * Handles changes to the property selection.
*
* @param playerProperties The dropdown menu's selection state.
*/ */
private void onDropdownSelectionChanged(Selector<String> playerProperties) { private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem(); String selected = playerProperties.getSelectedItem();
@@ -201,7 +221,7 @@ public class SellHouse extends Dialog {
int cost = 0; int cost = 0;
for (String s : selectedProperties) { for (String s : selectedProperties) {
cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice(); cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice() / 2;
} }
String display = String.join(" | ", selectedProperties); String display = String.join(" | ", selectedProperties);
@@ -211,7 +231,7 @@ public class SellHouse extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the dialog and removes GUI elements from the screen.
*/ */
@Override @Override
public void close() { public void close() {
@@ -220,6 +240,9 @@ public class SellHouse extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.Selector; import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList; import com.simsilica.lemur.core.VersionedList;
@@ -19,7 +18,7 @@ import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.AlterProperty; import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.model.fields.BoardManager; import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
@@ -29,20 +28,43 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* TakeMortage is a popup which appears when a player clicks on the "TakeMortage"-button in the BuildingAdminMenu * TakeMortage is a popup that appears when a player clicks on the "Take Mortage" button
* in the BuildingAdminMenu.
* <p>
* This popup allows the player to select properties and take a mortgage on them
* to gain financial benefit during gameplay.
* </p>
*/ */
public class TakeMortage extends Dialog { public class TakeMortage extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the TakeMortage dialog UI. */
private final Container takeMortageContainer; private final Container takeMortageContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
/** Label to display selected properties. */
private Label selectionDisplay;
/** Reference to track selection changes in the property selector. */
private VersionedReference<Set<Integer>> selectionRef; private VersionedReference<Set<Integer>> selectionRef;
/** Dropdown selector for displaying available properties. */
private Selector<String> propertySelector; private Selector<String> propertySelector;
/** Set of properties selected for mortgaging. */
private Set<String> selectedProperties = new HashSet<>(); private Set<String> selectedProperties = new HashSet<>();
/** Label to display the total mortgage amount. */
private Label cost = new Label("0", new ElementId("label-Text")); private Label cost = new Label("0", new ElementId("label-Text"));
/**
* Constructs a new TakeMortage dialog.
*
* @param app The MonopolyApp instance.
*/
public TakeMortage(MonopolyApp app) { public TakeMortage(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -60,7 +82,7 @@ public class TakeMortage extends Dialog {
backgroundContainer.setPreferredSize(takeMortageContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(takeMortageContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel // Titel
Label title = takeMortageContainer.addChild(new Label( "Hypothek aufnehmen", new ElementId("warining-Bold"))); Label title = takeMortageContainer.addChild(new Label( "Hypothek aufnehmen", new ElementId("label-Bold")));
title.setFontSize(48); title.setFontSize(48);
title.setColor(ColorRGBA.Black); title.setColor(ColorRGBA.Black);
@@ -122,18 +144,23 @@ public class TakeMortage extends Dialog {
/** /**
* Creates a dropdown menu for selecting a property. * Creates a dropdown menu for selecting a property.
* *
* @return The dropdown container. * @return The dropdown container with property options.
*/ */
private Container createPropertyDropdown() { private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0)); dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange)); dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
VersionedList<String> propertyOptions = new VersionedList<>(); VersionedList<String> propertyOptions = new VersionedList<>();
List<PropertyField> playerProperties = getPlayerProperties(); List<PropertyField> playerProperties = getPlayerProperties();
// Populate the dropdown with property names // Populate the dropdown with property names
for (PropertyField property : playerProperties) { for (PropertyField property : playerProperties) {
if(property instanceof BuildingProperty) {
if (((BuildingProperty)property).getHouses()!=0) {
break;
}
}
propertyOptions.add(property.getName()); propertyOptions.add(property.getName());
} }
@@ -144,8 +171,9 @@ public class TakeMortage extends Dialog {
selectionRef = propertySelector.getSelectionModel().createReference(); selectionRef = propertySelector.getSelectionModel().createReference();
// Initialize the selection display here // Initialize the selection display here
selectionDisplay = new TextField(""); // Create TextField for displaying selections selectionDisplay = new Label(""); // Create TextField for displaying selections
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0)); selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
selectionDisplay.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection // Set initial selection
@@ -155,10 +183,14 @@ public class TakeMortage extends Dialog {
return dropdownContainer; return dropdownContainer;
} }
/** /**
* Retrieves the list of properties owned by the current player. * Retrieves the list of properties owned by the current player.
* <p>
* Only properties that are not currently mortgaged are included.
* </p>
* *
* @return List of PropertyField objects owned by the player. * @return List of eligible PropertyField objects owned by the player.
*/ */
private List<PropertyField> getPlayerProperties() { private List<PropertyField> getPlayerProperties() {
Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()); Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
@@ -171,6 +203,11 @@ public class TakeMortage extends Dialog {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Updates the dialog UI, tracking changes in the property selection.
*
* @param delta Time since the last update.
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
if(selectionRef.update()) { if(selectionRef.update()) {
@@ -179,7 +216,9 @@ public class TakeMortage extends Dialog {
} }
/** /**
* Handles property selection changes. * Handles changes to the property selection.
*
* @param playerProperties The dropdown menu's selection state.
*/ */
private void onDropdownSelectionChanged(Selector<String> playerProperties) { private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem(); String selected = playerProperties.getSelectedItem();
@@ -202,7 +241,7 @@ public class TakeMortage extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the dialog and removes GUI elements from the screen.
*/ */
@Override @Override
public void close() { public void close() {
@@ -211,6 +250,9 @@ public class TakeMortage extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -14,19 +14,31 @@ import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound; 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. * TimeOut is a warning popup triggered when the connection to the server is interrupted.
* <p>
* This popup informs the user about the loss of connection and provides an option to acknowledge it.
* </p>
*/ */
public class TimeOut extends Dialog { public class TimeOut extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the dialog. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the TimeOut dialog UI. */
private final Container timeOutContainer; private final Container timeOutContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs a new TimeOut dialog to notify the user about a connection loss.
*
* @param app The MonopolyApp instance.
*/
public TimeOut(MonopolyApp app) { public TimeOut(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -65,7 +77,10 @@ public class TimeOut extends Dialog {
// Beenden-Button // Beenden-Button
Button quitButton = timeOutContainer.addChild(new Button("Bestätigen", new ElementId("button"))); Button quitButton = timeOutContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close()); quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Popup // Zentriere das Popup
@@ -86,9 +101,9 @@ public class TimeOut extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return The overlay geometry.
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -102,8 +117,9 @@ public class TimeOut extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the TimeOut dialog and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(timeOutContainer); // Entferne das Menü app.getGuiNode().detachChild(timeOutContainer); // Entferne das Menü
@@ -112,6 +128,9 @@ public class TimeOut extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -16,12 +16,24 @@ import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/**
* WinnerPopUp is a dialog displayed when a player wins the Monopoly game.
* <p>
* This popup congratulates the player for their victory and provides an option to quit the game.
* </p>
*/
public class WinnerPopUp extends Dialog { public class WinnerPopUp extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container WinnerContainer;
private final Container backgroundContainer;
/** Semi-transparent overlay background for the dialog. */
private final Geometry overlayBackground;
/** Main container for the "Winner" dialog UI. */
private final Container WinnerContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer;
/** /**
* Constructs a new WinnerPopUp dialog. * Constructs a new WinnerPopUp dialog.
@@ -94,9 +106,9 @@ public class WinnerPopUp extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return The overlay geometry.
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -110,7 +122,7 @@ public class WinnerPopUp extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the WinnerPopUp dialog and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -120,6 +132,9 @@ public class WinnerPopUp extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

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