Compare commits
	
		
			113 Commits
		
	
	
		
			reworkedGu
			...
			5de76f3226
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					5de76f3226 | ||
| 
						 | 
					e2db058fc7 | ||
| 
						 | 
					7c79bb77e7 | ||
| 
						 | 
					444cf9db4e | ||
| 
						 | 
					9e199d677e | ||
| 
						 | 
					df4a81cbf2 | ||
| 
						 | 
					c635df9369 | ||
| 
						 | 
					c6ad605021 | ||
| 
						 | 
					1e20a2ac6e | ||
| 
						 | 
					36a9a7addf | ||
| 
						 | 
					e1190cd4a2 | ||
| 
						 | 
					34ecd2277b | ||
| 
						 | 
					5959f36a21 | ||
| 
						 | 
					1db2d9ebac | ||
| 
						 | 
					54bac50a7e | ||
| 
						 | 
					274ed2b25d | ||
| 
						 | 
					371fa83319 | ||
| 
						 | 
					c1faf91188 | ||
| 
						 | 
					617d707df8 | ||
| 
						 | 
					d18cea435c | ||
| 
						 | 
					1543f0dcea | ||
| 
						 | 
					ae181e4eff | ||
| 
						 | 
					fa96324c15 | ||
| 
						 | 
					9f559fe0d7 | ||
| 
						 | 
					cf6ee535b8 | ||
| 
						 | 
					be89bf1a27 | ||
| 
						 | 
					6f2027c2fb | ||
| 
						 | 
					6e99f17787 | ||
| 
						 | 
					b7e2e3213a | ||
| 
						 | 
					3ea6452d6d | ||
| 
						 | 
					fd3c141967 | ||
| 
						 | 
					b3d2dfed08 | ||
| 
						 | 
					5306208107 | ||
| 
						 | 
					2a7cbeed89 | ||
| 
						 | 
					0a34751825 | ||
| 
						 | 
					996bc0118a | ||
| 
						 | 
					bbcb12c131 | ||
| 
						 | 
					1969afc58f | ||
| 
						 | 
					ad0c432102 | ||
| 
						 | 
					315739646c | ||
| 
						 | 
					330e788498 | ||
| 
						 | 
					fc5a2809c8 | ||
| 
						 | 
					0acb63adb6 | ||
| 
						 | 
					b4c664927b | ||
| 
						 | 
					ed27e0aaf1 | ||
| 
						 | 
					98f453d7f8 | ||
| 
						 | 
					8de7499c21 | ||
| 
						 | 
					b680d7bc58 | ||
| 
						 | 
					30559bf443 | ||
| 
						 | 
					8774c4246d | ||
| 
						 | 
					7b82b20736 | ||
| 
						 | 
					698937e77c | ||
| 
						 | 
					7cbf000c44 | ||
| 
						 | 
					e98e17f6d7 | ||
| 
						 | 
					e337303408 | ||
| 
						 | 
					97619fe662 | ||
| 
						 | 
					246566a211 | ||
| 
						 | 
					96a78ee61b | ||
| 
						 | 
					c9e99ee9ff | ||
| 
						 | 
					111f2b1283 | ||
| 
						 | 
					93386fa77a | ||
| 
						 | 
					6cdf0eee53 | ||
| 
						 | 
					b6803c562c | ||
| 
						 | 
					38699ac07a | ||
| 
						 | 
					f396ef52f2 | ||
| 
						 | 
					73bf147817 | ||
| 
						 | 
					80f9054add | ||
| 
						 | 
					b819e1ca9b | ||
| 
						 | 
					c4955e0b57 | ||
| 
						 | 
					008cb1ebe4 | ||
| 
						 | 
					723c934d73 | ||
| 
						 | 
					4eac2e3312 | ||
| 
						 | 
					fef881f42c | ||
| 
						 | 
					eeaf29a646 | ||
| 
						 | 
					2eae0fce2a | ||
| 
						 | 
					aa9e8ed3f0 | ||
| 
						 | 
					3e14a2674f | ||
| 
						 | 
					815899fa8d | ||
| 
						 | 
					793e93ef24 | ||
| 
						 | 
					43d0549e9e | ||
| 
						 | 
					170afe2718 | ||
| 
						 | 
					17220c228b | ||
| 
						 | 
					0f1be83064 | ||
| 
						 | 
					e0ab09295d | ||
| 
						 | 
					758e9b8397 | ||
| 
						 | 
					b3fe289fbe | ||
| 
						 | 
					42fefb2899 | ||
| 
						 | 
					5da86117c8 | ||
| 
						 | 
					1376da3ba6 | ||
| 
						 | 
					fb280101a5 | ||
| 
						 | 
					844495ebbb | ||
| 
						 | 
					e14f6bbef7 | ||
| 
						 | 
					4839ddd497 | ||
| 
						 | 
					b901323e2f | ||
| 
						 | 
					640665fd29 | ||
| 
						 | 
					ba8791d9fe | ||
| 
						 | 
					f8fe0b9877 | ||
| 
						 | 
					48913356e3 | ||
| 
						 | 
					e498c6f179 | ||
| 
						 | 
					31fe60807f | ||
| 
						 | 
					c758ba9735 | ||
| 
						 | 
					650dcb85db | ||
| 
						 | 
					6b110c81c8 | ||
| 
						 | 
					93ef00870b | ||
| 
						 | 
					645433610f | ||
| 
						 | 
					10a5b6b4d4 | ||
| 
						 | 
					69fccefed9 | ||
| 
						 | 
					14aecdd929 | ||
| 
						 | 
					48f18dd468 | ||
| 
						 | 
					96fe09c6fa | ||
| 
						 | 
					14c68f55d9 | ||
| 
						 | 
					392a81b2d8 | ||
| 
						 | 
					944b6b674e | 
| 
		 After Width: | Height: | Size: 518 KiB  | 
@@ -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
 | 
			
		||||
@@ -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
 | 
			
		||||
| 
		 After Width: | Height: | Size: 55 KiB  | 
| 
		 After Width: | Height: | Size: 552 KiB  | 
| 
		 After Width: | Height: | Size: 100 KiB  | 
@@ -19,6 +19,8 @@ import java.util.Deque;
 | 
			
		||||
 | 
			
		||||
import static java.lang.Math.max;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 static Logger LOGGER = System.getLogger(DialogManager.class.getName());
 | 
			
		||||
    /**
 | 
			
		||||
     * A stack to keep track of the dialogs.
 | 
			
		||||
     */
 | 
			
		||||
    private final Deque<Dialog> dialogStack = new ArrayDeque<>();
 | 
			
		||||
 | 
			
		||||
    private final Deque<PopupDialog> popUpStack = new ArrayDeque<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a DialogManager for the specified application.
 | 
			
		||||
     *
 | 
			
		||||
@@ -112,11 +118,45 @@ public class DialogManager {
 | 
			
		||||
     * @param dialog the dialog to open
 | 
			
		||||
     */
 | 
			
		||||
    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);
 | 
			
		||||
        if(dialog instanceof PopupDialog) {
 | 
			
		||||
            ((PopupDialog)dialog).show();
 | 
			
		||||
        }
 | 
			
		||||
        dialog.update();
 | 
			
		||||
        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.
 | 
			
		||||
     *
 | 
			
		||||
@@ -140,6 +180,8 @@ public class DialogManager {
 | 
			
		||||
        if (!dialogStack.isEmpty())
 | 
			
		||||
            dialogStack.peek().update();
 | 
			
		||||
        app.getGuiNode().detachChild(dialog);
 | 
			
		||||
 | 
			
		||||
        processPopUps();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -150,6 +192,11 @@ public class DialogManager {
 | 
			
		||||
        dialogStack.peek().escape();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates all dialogs in the dialog stack.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta the time since the last update
 | 
			
		||||
     */
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        for (Dialog dialog : dialogStack)
 | 
			
		||||
            dialog.update(delta);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Projekte/jme-common/src/main/java/pp/dialog/PopupDialog.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,10 @@
 | 
			
		||||
package pp.dialog;
 | 
			
		||||
 | 
			
		||||
/** An interface for tagging Dialogs as PopUps for handling in the DialogManager */
 | 
			
		||||
public interface PopupDialog {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shows the popup.
 | 
			
		||||
     */
 | 
			
		||||
    void show();
 | 
			
		||||
}
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
// https://github.com/jMonkeyEngine-Contributions/Lemur/wiki/Styling
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA
 | 
			
		||||
import com.jme3.texture.Texture
 | 
			
		||||
import com.simsilica.lemur.*
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent
 | 
			
		||||
import com.simsilica.lemur.Button
 | 
			
		||||
@@ -12,6 +13,8 @@ import com.simsilica.lemur.HAlignment
 | 
			
		||||
import com.simsilica.lemur.Insets3f
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent
 | 
			
		||||
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 buttonEnabledColor = color(0, 0, 0, 1)
 | 
			
		||||
@@ -47,6 +50,23 @@ def orangeBorder = TbtQuadBackgroundComponent.create(
 | 
			
		||||
        1f, false)
 | 
			
		||||
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") {
 | 
			
		||||
    font = font("Interface/Fonts/Metropolis/Metropolis-Regular-32.fnt")
 | 
			
		||||
}
 | 
			
		||||
@@ -69,7 +89,7 @@ selector("label-Bold", "pp") {
 | 
			
		||||
selector("label-toolbar", "pp") {
 | 
			
		||||
    insets = new Insets3f(2, 2, 2, 2)
 | 
			
		||||
    font = font("Interface/Fonts/Metropolis/Metropolis-Bold-32.fnt")
 | 
			
		||||
    fontSize = 30
 | 
			
		||||
    fontSize = 25
 | 
			
		||||
    color = new ColorRGBA(ColorRGBA.White)
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
@@ -81,6 +101,13 @@ selector("label-Text", "pp") {
 | 
			
		||||
    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") {
 | 
			
		||||
    insets = new Insets3f(2, 2, 2, 2)
 | 
			
		||||
    fontSize = 25
 | 
			
		||||
@@ -198,7 +225,6 @@ selector("button", "pp") {
 | 
			
		||||
    insets = new Insets3f(3, 3, 3, 3) // Adjust the border thickness
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
    buttonCommands = stdButtonCommands
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def enabledCommandToolbar = new Command<Button>() {
 | 
			
		||||
    MonopolyApp app // Pass the app instance to access player details
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
        // Get the current player's color
 | 
			
		||||
        Player currentPlayer = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
 | 
			
		||||
        ColorRGBA playerColor = Player.getColor(currentPlayer.getId()).getColor();
 | 
			
		||||
 | 
			
		||||
        if (source.isEnabled()) {
 | 
			
		||||
            source.setColor(ColorRGBA.White);
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,362 @@
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The camera controller for managing the camera's position and orientation.
 | 
			
		||||
     */
 | 
			
		||||
    private CameraController cameraController;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The input handler for controlling the camera's movement and rotation.
 | 
			
		||||
     */
 | 
			
		||||
    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(new ColorRGBA(1f, 1f, 1f, 1f));
 | 
			
		||||
        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(BoardTexture);
 | 
			
		||||
        seaMat.setTexture("DiffuseMap", texture);
 | 
			
		||||
        seaGeo.setMaterial(seaMat);
 | 
			
		||||
        seaGeo.setShadowMode(ShadowMode.CastAndReceive);
 | 
			
		||||
        TangentBinormalGenerator.generate(seaGeo);
 | 
			
		||||
    
 | 
			
		||||
        sceneNode.attachChild(createCardDeck());
 | 
			
		||||
        sceneNode.attachChild(seaGeo);
 | 
			
		||||
    
 | 
			
		||||
        // Schneefall hinzufügen
 | 
			
		||||
        addSnowEffect(sceneNode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card deck with six event and six community cards.
 | 
			
		||||
     * @return the node containing the card deck
 | 
			
		||||
     */
 | 
			
		||||
    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(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
            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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a snow effect to the scene by creating a particle emitter with snowflakes.
 | 
			
		||||
     * @param parentNode the parent node to attach the snow effect to
 | 
			
		||||
     */
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the state by moving the camera and updating the visual elements.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param tpf the time per frame
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        super.update(tpf);
 | 
			
		||||
        cameraController.update(tpf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,99 +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.lang.System.Logger.Level;
 | 
			
		||||
 | 
			
		||||
import com.jme3.input.controls.ActionListener;
 | 
			
		||||
import com.jme3.scene.Node;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.gui.TestWorld;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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());
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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() {
 | 
			
		||||
        LOGGER.log(Level.DEBUG, "Enabling game state");
 | 
			
		||||
        battleNode.detachAllChildren();
 | 
			
		||||
        initializeGuiComponents();
 | 
			
		||||
        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() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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) {
 | 
			
		||||
        super.update(tpf);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -13,14 +13,13 @@ import com.jme3.asset.AssetLoadException;
 | 
			
		||||
import com.jme3.asset.AssetNotFoundException;
 | 
			
		||||
import com.jme3.audio.AudioData;
 | 
			
		||||
import com.jme3.audio.AudioNode;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 {
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(GameMusic.class.getName());
 | 
			
		||||
    private static final Preferences PREFERENCES = getPreferences(GameMusic.class);
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(pp.monopoly.client.GameMusic.class.getName());
 | 
			
		||||
    private static final Preferences PREFERENCES = getPreferences(pp.monopoly.client.GameMusic.class);
 | 
			
		||||
    private static final String ENABLED_PREF = "enabled"; // NON-NLS
 | 
			
		||||
    private static final String VOLUME_PREF = "volume"; // NON-NLS
 | 
			
		||||
 | 
			
		||||
@@ -68,8 +67,9 @@ public class GameMusic extends AbstractAppState {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the main music.
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    private void playMainMusic() {
 | 
			
		||||
    public void playMainMusic() {
 | 
			
		||||
        if (!isEnabled()) {
 | 
			
		||||
            return; // Sound is disabled
 | 
			
		||||
        }
 | 
			
		||||
@@ -92,11 +92,10 @@ public class GameMusic extends AbstractAppState {
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the secondary music and stops the main music.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app                The application instance
 | 
			
		||||
     * @param secondaryMusicFile The file path of the secondary audio file
 | 
			
		||||
     */
 | 
			
		||||
    private void playSecondaryMusic() {
 | 
			
		||||
        if(!isEnabled()) {
 | 
			
		||||
    public void playSecondaryMusic() {
 | 
			
		||||
        if (!isEnabled()) {
 | 
			
		||||
            stopAllMusic();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (isSecondaryMusicPlaying) {
 | 
			
		||||
@@ -115,7 +114,7 @@ public class GameMusic extends AbstractAppState {
 | 
			
		||||
    /**
 | 
			
		||||
     * Stops the secondary music.
 | 
			
		||||
     */
 | 
			
		||||
    private void stopSecondaryMusic() {
 | 
			
		||||
    public void stopSecondaryMusic() {
 | 
			
		||||
        if (secondaryMusic != null && isSecondaryMusicPlaying) {
 | 
			
		||||
            secondaryMusic.stop();
 | 
			
		||||
            isSecondaryMusicPlaying = false;
 | 
			
		||||
@@ -127,17 +126,17 @@ public class GameMusic extends AbstractAppState {
 | 
			
		||||
     * 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.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app                The application instance
 | 
			
		||||
     * @param secondaryMusicFile The file path of the secondary audio file
 | 
			
		||||
     */
 | 
			
		||||
    public void toggleMusic() {
 | 
			
		||||
        if(!isEnabled()) {
 | 
			
		||||
        if (!isEnabled()) {
 | 
			
		||||
            stopAllMusic();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (isSecondaryMusicPlaying) {
 | 
			
		||||
            stopSecondaryMusic();
 | 
			
		||||
            playMainMusic();
 | 
			
		||||
        } else {
 | 
			
		||||
            stopMainMusic();
 | 
			
		||||
            playSecondaryMusic();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -153,6 +152,14 @@ public class GameMusic extends AbstractAppState {
 | 
			
		||||
        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.
 | 
			
		||||
@@ -161,13 +168,14 @@ public class GameMusic extends AbstractAppState {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setEnabled(boolean enabled) {
 | 
			
		||||
        if (isEnabled() == enabled) return;
 | 
			
		||||
        if (isEnabled() == enabled) return; // Avoid redundant operations
 | 
			
		||||
 | 
			
		||||
        PREFERENCES.putBoolean(ENABLED_PREF, enabled);
 | 
			
		||||
 | 
			
		||||
        if (enabled) {
 | 
			
		||||
            playMainMusic();
 | 
			
		||||
        } else {
 | 
			
		||||
            stopMainMusic();
 | 
			
		||||
            stopSecondaryMusic();
 | 
			
		||||
            stopAllMusic();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.setEnabled(enabled);
 | 
			
		||||
 
 | 
			
		||||
@@ -48,16 +48,27 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
     */
 | 
			
		||||
    private static final String VOLUME_PREF = "volume"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    /** The sound effect for passing the start field. */
 | 
			
		||||
    private AudioNode passStartSound;
 | 
			
		||||
    /** The sound effect for drawing an event card. */
 | 
			
		||||
    private AudioNode eventCardSound;
 | 
			
		||||
    /** The sound effect for going to the gulag. */
 | 
			
		||||
    private AudioNode gulagSound;
 | 
			
		||||
    /** The sound effect for rolling the dice. */
 | 
			
		||||
    private AudioNode diceRollSound;
 | 
			
		||||
    /** The sound effect for collecting money. */
 | 
			
		||||
    private AudioNode moneyCollectSound;
 | 
			
		||||
    /** The sound effect for losing money. */
 | 
			
		||||
    private AudioNode moneyLostSound;
 | 
			
		||||
    /** The sound effect for accepting a trade. */
 | 
			
		||||
    private AudioNode tradeAcceptedSound;
 | 
			
		||||
    /** The sound effect for rejecting a trade. */
 | 
			
		||||
    private AudioNode tradeRejectedSound;
 | 
			
		||||
    /** The sound effect for winning the game. */
 | 
			
		||||
    private AudioNode winnerSound;
 | 
			
		||||
    /** The sound effect for loosing the game. */
 | 
			
		||||
    private AudioNode looserSound;
 | 
			
		||||
    /** The sound effect for pressing a button. */
 | 
			
		||||
    private AudioNode buttonSound;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -120,6 +131,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
        winnerSound = loadSound(app, "Sound/Effects/winner.ogg");
 | 
			
		||||
        looserSound = loadSound(app, "Sound/Effects/loser.ogg");
 | 
			
		||||
        buttonSound = loadSound(app, "Sound/Effects/button.ogg");
 | 
			
		||||
        setVolume(volumeInPreferences());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,9 @@ import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.concurrent.ExecutorService;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
import java.util.logging.LogManager;
 | 
			
		||||
import java.awt.Image;
 | 
			
		||||
 | 
			
		||||
import javax.imageio.ImageIO;
 | 
			
		||||
 | 
			
		||||
import com.jme3.app.DebugKeysAppState;
 | 
			
		||||
import com.jme3.app.SimpleApplication;
 | 
			
		||||
@@ -169,6 +172,19 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
    private AppSettings makeSettings() {
 | 
			
		||||
        final AppSettings settings = new AppSettings(true);
 | 
			
		||||
        settings.setTitle(lookup("monopoly.name"));
 | 
			
		||||
 | 
			
		||||
        // Set the icon for the application window
 | 
			
		||||
        
 | 
			
		||||
        // 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.setFullscreen(config.fullScreen());
 | 
			
		||||
        settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer());
 | 
			
		||||
@@ -280,12 +296,14 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
            stateManager.attach(stats);
 | 
			
		||||
        }
 | 
			
		||||
        flyCam.setEnabled(false);
 | 
			
		||||
        flyCam.setMoveSpeed(4f); // Setzt die Bewegungsgeschwindigkeit der Kamera (Standardwert ist 1f)
 | 
			
		||||
 | 
			
		||||
        stateManager.detach(stateManager.getState(StatsAppState.class));
 | 
			
		||||
        stateManager.detach(stateManager.getState(DebugKeysAppState.class));
 | 
			
		||||
 | 
			
		||||
        attachGameSound();
 | 
			
		||||
        attachGameMusic();
 | 
			
		||||
        stateManager.attach(new GameAppState());
 | 
			
		||||
        stateManager.attach(new BoardAppState());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -405,7 +423,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(ClientStateEvent event) {
 | 
			
		||||
        stateManager.getState(GameAppState.class).setEnabled(true);
 | 
			
		||||
        stateManager.getState(BoardAppState.class).setEnabled(logic.isTurn());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -106,6 +106,26 @@ public class MonopolyAppConfig extends MonopolyClientConfig {
 | 
			
		||||
    @Property("overlay.top.color") //NON-NLS
 | 
			
		||||
    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.
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,120 @@
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is responsible for managing the popups that are shown to the user.
 | 
			
		||||
 * It listens for events that require a popup to be shown and then shows the
 | 
			
		||||
 * appropriate popup.
 | 
			
		||||
 */
 | 
			
		||||
public class PopUpManager implements GameEventListener {
 | 
			
		||||
 | 
			
		||||
    /** The MonopolyApp instance */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor for the PopUpManager.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param app The MonopolyApp instance
 | 
			
		||||
     */
 | 
			
		||||
    public PopUpManager(MonopolyApp app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        app.getGameLogic().addListener(this);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This method is called when a PopUpEvent is received.
 | 
			
		||||
     * It checks the message of the event and shows the appropriate popup.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param event The PopUpEvent
 | 
			
		||||
     */
 | 
			
		||||
    @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();
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }, 6000);
 | 
			
		||||
        } 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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This method is called when an EventCardEvent is received.
 | 
			
		||||
     * It shows the EventCardPopup.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param event The EventCardEvent
 | 
			
		||||
     */
 | 
			
		||||
    @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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,185 @@
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The {@code BobTheBuilder} class is responsible for synchronizing the graphical
 | 
			
		||||
 * representation of the figures and buildings on the board with the underlying data model.
 | 
			
		||||
 * It extends the {@link GameBoardSynchronizer} to provide specific synchronization
 | 
			
		||||
 * logic for the board.
 | 
			
		||||
 */
 | 
			
		||||
public class BobTheBuilder extends GameBoardSynchronizer {
 | 
			
		||||
 | 
			
		||||
    /** The String representing the path to the unshaded material*/
 | 
			
		||||
    private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
 | 
			
		||||
    /** The String representing the color parameter in the material*/
 | 
			
		||||
    private static final String COLOR = "Color"; //NON-NLS
 | 
			
		||||
    /** The String representing the figure node*/
 | 
			
		||||
    private static final String FIGURE = "figure"; //NON-NLS
 | 
			
		||||
    /** The String representing the house node*/
 | 
			
		||||
    private static final String HOUSE = "house"; //NON-NLS
 | 
			
		||||
    /** The String representing the hotel node*/
 | 
			
		||||
    private static final String HOTEL = "hotel"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    /** The {@link MonopolyApp} instance*/
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new {@code BobTheBuilder} instance with the specified {@link MonopolyApp} and root node.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the {@link MonopolyApp} instance
 | 
			
		||||
     * @param root the root node of the scene graph
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new spatial to represent the specified figure.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param figure the figure to be represented
 | 
			
		||||
     * @return the geometry representing the figure
 | 
			
		||||
     */
 | 
			
		||||
    private Spatial createFigure(Figure figure) {
 | 
			
		||||
        Spatial model;
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            // Lade das Modell
 | 
			
		||||
            model = app.getAssetManager().loadModel("models/" + "Spielfiguren/" + figure.getType() + "/" + figure.getType() + ".j3o");
 | 
			
		||||
            
 | 
			
		||||
            // Skaliere und positioniere das Modell
 | 
			
		||||
            model.scale(0.5f);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            model = createBox(figure);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return model;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new spatial to represent the specified hotel.
 | 
			
		||||
     * @param hotel the hotel to be represented
 | 
			
		||||
     * @return  the geometry representing the hotel
 | 
			
		||||
     */
 | 
			
		||||
    private Spatial createHotel(Hotel hotel) {
 | 
			
		||||
        Spatial model = app.getAssetManager().loadModel("models/Hotel/Hotel.j3o");
 | 
			
		||||
        model.scale(0.2f);
 | 
			
		||||
        model.setShadowMode(ShadowMode.CastAndReceive);
 | 
			
		||||
        return model;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new spatial to represent the specified house.
 | 
			
		||||
     * @param house the house to be represented
 | 
			
		||||
     * @return  the geometry representing the house
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -191,9 +191,6 @@ public class BuildingAdminMenu extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the building administration menu and detaches its elements from the GUI.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(mainContainer);
 | 
			
		||||
@@ -201,21 +198,8 @@ public class BuildingAdminMenu extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Periodic updates for the menu, if required.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta Time since the last update in seconds.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        // Periodic updates if necessary
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,64 +3,149 @@ package pp.monopoly.client.gui;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.renderer.Camera;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.game.server.PlayerHandler;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.UpdatePlayerView;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Controls the movement of the camera within the scene.
 | 
			
		||||
 * Represents a camera controller for the Monopoly application.
 | 
			
		||||
 */
 | 
			
		||||
public class CameraController {
 | 
			
		||||
    private final Camera camera;
 | 
			
		||||
    private final float height = 25;    // Height of the camera above the game board
 | 
			
		||||
public class CameraController implements GameEventListener{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor for the CameraController.
 | 
			
		||||
     *
 | 
			
		||||
     * @param camera The camera to be controlled
 | 
			
		||||
     * Enum representing the camera mode for the CameraController.
 | 
			
		||||
     */
 | 
			
		||||
    public CameraController(Camera camera) {
 | 
			
		||||
    public enum CameraMode {
 | 
			
		||||
        FOCUS_CURRENT_PLAYER,
 | 
			
		||||
        FOCUS_SELF,
 | 
			
		||||
        FREECAM
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** The camera to control */
 | 
			
		||||
    private final Camera camera;
 | 
			
		||||
    /** The current camera mode */
 | 
			
		||||
    private CameraMode currentMode;
 | 
			
		||||
    /** The player handler instance */
 | 
			
		||||
    private PlayerHandler playerHandler;
 | 
			
		||||
    /** The {@link MonopolyApp} instance*/
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new CameraController instance.
 | 
			
		||||
     * @param camera The camera to control
 | 
			
		||||
     * @param app The MonopolyApp instance
 | 
			
		||||
     */
 | 
			
		||||
    public CameraController(Camera camera, MonopolyApp app) {
 | 
			
		||||
        this.camera = camera;
 | 
			
		||||
        setPosition(0);
 | 
			
		||||
        camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
 | 
			
		||||
        this.playerHandler = app.getGameLogic().getPlayerHandler();
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        app.getGameLogic().addListener(this);
 | 
			
		||||
        setMode(CameraMode.FOCUS_SELF); // Initialize the camera mode
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the camera's position and orientation.
 | 
			
		||||
     *
 | 
			
		||||
     * @param tpf Time per frame
 | 
			
		||||
     * Sets the camera mode to the specified mode.
 | 
			
		||||
     * @param mode The camera mode to set
 | 
			
		||||
     */
 | 
			
		||||
    public void setMode(CameraMode mode) {
 | 
			
		||||
        this.currentMode = mode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the camera behavior based on the current mode and the time-per-frame (tpf).
 | 
			
		||||
     * <p>
 | 
			
		||||
     * This method checks the current mode of the camera and updates its position or behavior accordingly.
 | 
			
		||||
     * Supported modes include:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *   <li>FOCUS_CURRENT_PLAYER: Updates the camera position to focus on the current player.</li>
 | 
			
		||||
     *   <li>FOCUS_SELF: Updates the camera position to focus on the self (the object controlled by the player).</li>
 | 
			
		||||
     *   <li>FREECAM: Leaves the camera position unchanged, allowing free movement.</li>
 | 
			
		||||
     * </ul>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param tpf The time-per-frame value, typically provided by the game engine,
 | 
			
		||||
     *            which represents the elapsed time since the last frame.
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the camera's position based on the field ID.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fieldID The ID of the field to which the camera should move
 | 
			
		||||
     * Updates the camera position depending on the current mode.
 | 
			
		||||
     */
 | 
			
		||||
    public void setPosition(int fieldID) {
 | 
			
		||||
        camera.setLocation(fieldIdToVector(fieldID));
 | 
			
		||||
    public void updatePosition() {
 | 
			
		||||
        Vector3f newPosition = getPos();
 | 
			
		||||
        camera.setLocation(newPosition);
 | 
			
		||||
 | 
			
		||||
        camera.lookAt(app.getGameLogic().getBoard().getFigure(app.getId()).getPos(), Vector3f.UNIT_Y);
 | 
			
		||||
        camera.update();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the camera's position using specific coordinates.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x The X-coordinate of the new camera position
 | 
			
		||||
     * @param y The Y-coordinate of the new camera position
 | 
			
		||||
     * Returns the position for the camera depending on the current mode.
 | 
			
		||||
     * @return The position for the camera
 | 
			
		||||
     */
 | 
			
		||||
    public void setPosition(float x, float y) {
 | 
			
		||||
        camera.setLocation(new Vector3f(x, height, y));
 | 
			
		||||
    private Vector3f getPos() {
 | 
			
		||||
        Vector3f pos = new Vector3f();
 | 
			
		||||
        switch (currentMode) {
 | 
			
		||||
            case FOCUS_CURRENT_PLAYER:
 | 
			
		||||
                pos =  app.getGameLogic().getBoard().getFigure(playerHandler.getPlayerById(0).getId()).getPos();
 | 
			
		||||
        
 | 
			
		||||
            case FOCUS_SELF:
 | 
			
		||||
                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;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Maps a field ID to its corresponding position in the game world.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fieldID The ID of the field
 | 
			
		||||
     * @return The position of the field as a {@link Vector3f}
 | 
			
		||||
     * @throws IllegalArgumentException If the field ID is invalid
 | 
			
		||||
     * Calculates the offset for the camera depending on the field the player is on.
 | 
			
		||||
     * @return The offset for the camera
 | 
			
		||||
     */
 | 
			
		||||
    private Vector3f fieldIdToVector(int fieldID) {
 | 
			
		||||
        if (fieldID <= 10) return new Vector3f(30, height, 0);
 | 
			
		||||
        if (fieldID <= 20) return new Vector3f(0, height, 30);
 | 
			
		||||
        if (fieldID <= 30) return new Vector3f(-30, height, 0);
 | 
			
		||||
        if (fieldID <= 40) return new Vector3f(0, height, -30);
 | 
			
		||||
        else throw new IllegalArgumentException();
 | 
			
		||||
    private Vector3f getOffset() {
 | 
			
		||||
        Vector3f offset = new Vector3f();
 | 
			
		||||
 | 
			
		||||
        int fieldId = playerHandler.getPlayerById( (currentMode == CameraMode.FOCUS_SELF ? app.getId() : playerHandler.getPlayerAtIndex(0).getId()) ).getFieldID();
 | 
			
		||||
        // System.out.println();
 | 
			
		||||
        if(fieldId < 10) {
 | 
			
		||||
            offset = new Vector3f(0, 15, -20);
 | 
			
		||||
        } else if(fieldId < 20) {
 | 
			
		||||
            offset = new Vector3f(20 , 15, 0);
 | 
			
		||||
        } else if(fieldId < 30) {
 | 
			
		||||
            offset = new Vector3f(0, 15, 20 );
 | 
			
		||||
        } else {
 | 
			
		||||
            offset = new Vector3f(-20, 15, 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return offset;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(UpdatePlayerView event) {
 | 
			
		||||
        playerHandler = app.getGameLogic().getPlayerHandler();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,60 +1,44 @@
 | 
			
		||||
//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;
 | 
			
		||||
//
 | 
			
		||||
///**
 | 
			
		||||
// * Handhabt die Eingaben für die Kamera.
 | 
			
		||||
// */
 | 
			
		||||
//public class CameraInputHandler {
 | 
			
		||||
//
 | 
			
		||||
//    private CameraController cameraController; // Kamera-Controller
 | 
			
		||||
//
 | 
			
		||||
//    /**
 | 
			
		||||
//     * Konstruktor für den CameraInputHandler.
 | 
			
		||||
//     *
 | 
			
		||||
//     * @param cameraController Der Kamera-Controller, der gesteuert werden soll.
 | 
			
		||||
//     * @param inputManager     Der InputManager, um Eingaben zu registrieren.
 | 
			
		||||
//     */
 | 
			
		||||
//    public CameraInputHandler(CameraController cameraController, InputManager inputManager) {
 | 
			
		||||
//        if (cameraController == null || inputManager == null) {
 | 
			
		||||
//            throw new IllegalArgumentException("CameraController und InputManager dürfen nicht null sein");
 | 
			
		||||
//        }
 | 
			
		||||
//        this.cameraController = cameraController;
 | 
			
		||||
//
 | 
			
		||||
//        // Mappings für Kamerasteuerung
 | 
			
		||||
//        inputManager.addMapping("FocusCurrentPlayer", new KeyTrigger(KeyInput.KEY_1)); // Modus 1
 | 
			
		||||
//        inputManager.addMapping("FocusSelf", new KeyTrigger(KeyInput.KEY_2));         // Modus 2
 | 
			
		||||
//        inputManager.addMapping("FreeCam", new KeyTrigger(KeyInput.KEY_3));          // Modus 3
 | 
			
		||||
//
 | 
			
		||||
//        // Listener für die Kameramodi
 | 
			
		||||
//        inputManager.addListener(actionListener, "FocusCurrentPlayer", "FocusSelf", "FreeCam");
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    /**
 | 
			
		||||
//     * ActionListener für die Kamerasteuerung.
 | 
			
		||||
//     */
 | 
			
		||||
//    private final ActionListener actionListener = (name, isPressed, tpf) -> {
 | 
			
		||||
//        if (!isPressed) return;
 | 
			
		||||
//
 | 
			
		||||
//        // Umschalten der Kamera-Modi basierend auf der Eingabe
 | 
			
		||||
//        switch (name) {
 | 
			
		||||
//            case "FocusCurrentPlayer" -> {
 | 
			
		||||
//                cameraController.setMode(CameraController.CameraMode.FOCUS_CURRENT_PLAYER);
 | 
			
		||||
//                System.out.println("Kameramodus: Fokus auf aktuellen Spieler");
 | 
			
		||||
//            }
 | 
			
		||||
//            case "FocusSelf" -> {
 | 
			
		||||
//                cameraController.setMode(CameraController.CameraMode.FOCUS_SELF);
 | 
			
		||||
//                System.out.println("Kameramodus: Fokus auf eigene Figur");
 | 
			
		||||
//            }
 | 
			
		||||
//            case "FreeCam" -> {
 | 
			
		||||
//                cameraController.setMode(CameraController.CameraMode.FREECAM);
 | 
			
		||||
//                System.out.println("Kameramodus: Freie Kamera");
 | 
			
		||||
//            }
 | 
			
		||||
//            default -> System.err.println("Unbekannter Kameramodus: " + name);
 | 
			
		||||
//        }
 | 
			
		||||
//    };
 | 
			
		||||
//}
 | 
			
		||||
//
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class to handle the input for the camera.
 | 
			
		||||
 */
 | 
			
		||||
public class CameraInputHandler {
 | 
			
		||||
 | 
			
		||||
    /**The camera controller */
 | 
			
		||||
    private CameraController cameraController;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor for the CameraInputHandler.
 | 
			
		||||
     * @param cameraController The camera controller.
 | 
			
		||||
     * @param inputManager The input manager.
 | 
			
		||||
     */
 | 
			
		||||
    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");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * ActionListener for the camera.
 | 
			
		||||
     */
 | 
			
		||||
    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);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -22,21 +22,34 @@ import pp.monopoly.message.client.ViewAssetsRequest;
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Dialog for choosing a trade partner.
 | 
			
		||||
 */
 | 
			
		||||
public class ChoosePartner extends Dialog {
 | 
			
		||||
    /** The {@link MonopolyApp} instance*/
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    /** Selector for selecting the player */
 | 
			
		||||
    private Selector<String> playerSelector;
 | 
			
		||||
    /** Button for cancel*/
 | 
			
		||||
    private final Button cancelButton = new Button("Abbrechen");
 | 
			
		||||
    /** Button for confirm*/
 | 
			
		||||
    private final Button confirmButton = new Button("Bestätigen");
 | 
			
		||||
    /** Main container for the UI components */
 | 
			
		||||
    private final Container mainContainer;
 | 
			
		||||
    /** Container for the lower left menu */
 | 
			
		||||
    private Container lowerLeftMenu;
 | 
			
		||||
    /** Container for the lower right menu */
 | 
			
		||||
    private Container lowerRightMenu;
 | 
			
		||||
    /** The background image */
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
    /** The trade handler */
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef; // Reference to track selector changes
 | 
			
		||||
    private String lastSelected = ""; // To keep track of the last selected value
 | 
			
		||||
 | 
			
		||||
    QuadBackgroundComponent translucentWhiteBackground =
 | 
			
		||||
            new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
 | 
			
		||||
    /** Reference to track selector changes */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
    /** The last selected value */
 | 
			
		||||
    private String lastSelected = "";
 | 
			
		||||
    /** The translucent white background */
 | 
			
		||||
    private QuadBackgroundComponent translucentWhiteBackground = new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the ChoosePartner dialog.
 | 
			
		||||
@@ -169,9 +182,6 @@ public class ChoosePartner extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action for the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -38,18 +38,31 @@ import pp.dialog.DialogBuilder;
 | 
			
		||||
 * Allows users to specify the host and port for connecting to a game server.
 | 
			
		||||
 */
 | 
			
		||||
public class CreateGameMenu extends Dialog {
 | 
			
		||||
    /** The Logger for this class */
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(CreateGameMenu.class.getName());
 | 
			
		||||
    /** A string represing the localhost default */
 | 
			
		||||
    private static final String LOCALHOST = "localhost"; //NON-NLS
 | 
			
		||||
    /** A string representing the default port number */
 | 
			
		||||
    private static final String DEFAULT_PORT = "42069"; //NON-NLS
 | 
			
		||||
    /** The NetworkSupport instance to be used for network operations */
 | 
			
		||||
    private final NetworkSupport network;
 | 
			
		||||
    /** The text field for the host name */
 | 
			
		||||
    private final TextField host = new TextField(LOCALHOST);
 | 
			
		||||
    /** The text field for the port number */
 | 
			
		||||
    private final TextField port = new TextField(DEFAULT_PORT);
 | 
			
		||||
    /** The button for starting the server */
 | 
			
		||||
    private final Button serverButton = new Button("Selber hosten");
 | 
			
		||||
    /** The button for canceling the connection */
 | 
			
		||||
    private final Button cancelButton = new Button("Abbrechen");
 | 
			
		||||
    /** The button for joining a game */
 | 
			
		||||
    private final Button joinButton = new Button("Beitreten");
 | 
			
		||||
    /** The hostname of the server */
 | 
			
		||||
    private String hostname;
 | 
			
		||||
    /** The port number of the server */
 | 
			
		||||
    private int portNumber;
 | 
			
		||||
    /** The future representing the connection to the server */
 | 
			
		||||
    private Future<Object> connectionFuture;
 | 
			
		||||
    /** The dialog for indicating that the connection is in progress */
 | 
			
		||||
    private Dialog progressDialog;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,186 @@
 | 
			
		||||
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.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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Control class for the figure objects.
 | 
			
		||||
 * 
 | 
			
		||||
 * Handles the movement of the figure along a path.
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class FigureControl extends AbstractControl implements GameEventListener {
 | 
			
		||||
    /** The Logger for this class */
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(FigureControl.class.getName());
 | 
			
		||||
    /** The Figure object to control */
 | 
			
		||||
    private final Figure figure;
 | 
			
		||||
    /** The spatial object of the figure*/
 | 
			
		||||
    private final Node spatial;
 | 
			
		||||
    /** The MonopolyApp instance */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    /** The path to follow */
 | 
			
		||||
    private Queue<Vector3f> path;
 | 
			
		||||
    /** The current target position */
 | 
			
		||||
    private Vector3f currentTarget;
 | 
			
		||||
    /** The time elapsed for the current movement */
 | 
			
		||||
    private float animationTime = 0f;
 | 
			
		||||
    /** The duration per field */
 | 
			
		||||
    private final float durationPerField = 0.5f;
 | 
			
		||||
    /** The delay time */
 | 
			
		||||
    private float delayTime = 3f;
 | 
			
		||||
    /** The delay elapsed time */
 | 
			
		||||
    private float delayElapsed = 0f;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor for the FigureControl class
 | 
			
		||||
     * @param spatial The spatial object of the figure
 | 
			
		||||
     * @param figure The figure object
 | 
			
		||||
     * @param app The MonopolyApp object
 | 
			
		||||
     */
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the figure's movement along a path.
 | 
			
		||||
     * 
 | 
			
		||||
     * Handles movement delays, rotates at specific fields (0, 10, 20, 30), 
 | 
			
		||||
     * and moves the figure with a hop effect toward the next target.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param tpf Time-per-frame since the last update.
 | 
			
		||||
     */
 | 
			
		||||
    @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();
 | 
			
		||||
            
 | 
			
		||||
            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
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculate the next field on the board
 | 
			
		||||
     * @param currentField The current field id
 | 
			
		||||
     * @return  The next field id
 | 
			
		||||
     */
 | 
			
		||||
    private int nextField(int currentField) {
 | 
			
		||||
        return (currentField + 1) % 40;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void controlRender(RenderManager rm, ViewPort vp) {
 | 
			
		||||
        // No rendering logic required
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the path for the figure to follow
 | 
			
		||||
     * @param startField The field the figure is currently on
 | 
			
		||||
     * @param endField The field the figure should move to
 | 
			
		||||
     */
 | 
			
		||||
    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
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -1,120 +1,84 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.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.game.server.PlayerColor;
 | 
			
		||||
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.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.model.Rotation;
 | 
			
		||||
import static pp.util.FloatMath.HALF_PI;
 | 
			
		||||
import static pp.util.FloatMath.PI;
 | 
			
		||||
import pp.view.ModelViewSynchronizer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The {@code GameBoardSynchronizer} class is responsible for synchronizing the graphical
 | 
			
		||||
 * representation of the Game board and figures with the underlying data model.
 | 
			
		||||
 * It extends the {@link BoardSynchronizer} to provide specific synchronization
 | 
			
		||||
 * logic for the Game board.
 | 
			
		||||
 * 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 board, ensuring that changes in the model
 | 
			
		||||
 * are accurately reflected in the view.
 | 
			
		||||
 *
 | 
			
		||||
 * Subclasses are responsible for providing the specific implementation of how each item in the map
 | 
			
		||||
 * is represented visually by implementing the {@link Visitor} interface.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
class GameBoardSynchronizer extends BoardSynchronizer {
 | 
			
		||||
    private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
 | 
			
		||||
    private static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md";
 | 
			
		||||
    private static final String COLOR = "Color"; //NON-NLS
 | 
			
		||||
    private static final String FIGURE = "figure"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
abstract class GameBoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
 | 
			
		||||
    /** The board that this synchronizer is responsible for*/
 | 
			
		||||
    protected final Board board;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 root the root node to which graphical elements will be attached
 | 
			
		||||
     * @param map  the Game Board containing fields and figures
 | 
			
		||||
     * @param map  the board to be synchronized
 | 
			
		||||
     * @param root the root node to which the view representations of the board items are attached
 | 
			
		||||
     */
 | 
			
		||||
    public GameBoardSynchronizer(MonopolyApp app, Node root, Board board) {
 | 
			
		||||
        super(board, root);
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        addExisting();
 | 
			
		||||
    protected GameBoardSynchronizer(Board board, Node root) {
 | 
			
		||||
        super(root);
 | 
			
		||||
        this.board = board;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Visits a {@link Figure} and creates a graphical representation of it.
 | 
			
		||||
     * The representation is a 3D model.
 | 
			
		||||
     * Translates a model item into its corresponding visual representation.
 | 
			
		||||
     * The specific visual representation is determined by the concrete implementation of the {@link Visitor} interface.
 | 
			
		||||
     *
 | 
			
		||||
     * @param figure the figure to be represented
 | 
			
		||||
     * @return the node containing the graphical representation of the figure
 | 
			
		||||
     * @param item the item from the model to be translated
 | 
			
		||||
     * @return the visual representation of the item as a {@link Spatial}
 | 
			
		||||
     */
 | 
			
		||||
    public Spatial visit(Figure figure) {
 | 
			
		||||
        final Node node = new Node(FIGURE);
 | 
			
		||||
        node.attachChild(createBox(figure));
 | 
			
		||||
        final float x = 1;
 | 
			
		||||
        final float z = 1;
 | 
			
		||||
        node.setLocalTranslation(x, 0f, z);
 | 
			
		||||
        return node;
 | 
			
		||||
    @Override
 | 
			
		||||
    protected Spatial translate(Item item) {
 | 
			
		||||
        return item.accept(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a representation of a figure
 | 
			
		||||
     *
 | 
			
		||||
     * @param figure the figure to be represented
 | 
			
		||||
     * @return the geometry representing the 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
 | 
			
		||||
     * are visually represented.
 | 
			
		||||
     */
 | 
			
		||||
    private Spatial createBox(Figure figure) {
 | 
			
		||||
        final Box box = new Box(0.5f * (figure.getMaxY() - figure.getMinY()) + 0.3f,
 | 
			
		||||
                                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);
 | 
			
		||||
    protected void addExisting() {
 | 
			
		||||
        board.getItems().forEach(this::add);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        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.
 | 
			
		||||
     * 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.
 | 
			
		||||
     * Handles the event when an item is added to the ship map.
 | 
			
		||||
     * Adds the visual representation of the new item to the view if it belongs to the synchronized ship map.
 | 
			
		||||
     *
 | 
			
		||||
     * @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.
 | 
			
		||||
     * @param event the event indicating that an item has been added to the ship map
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(ItemAddedEvent event) {
 | 
			
		||||
        if (board == event.board()){
 | 
			
		||||
            add(event.item());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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;
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,38 +2,106 @@ 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 com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.game.server.PlayerColor;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A custom button class that uses images for its appearance. The button's appearance changes based on its state (enabled,
 | 
			
		||||
 */
 | 
			
		||||
public class ImageButton extends Button {
 | 
			
		||||
 | 
			
		||||
    private final String file;
 | 
			
		||||
    private static MonopolyApp app;
 | 
			
		||||
    
 | 
			
		||||
    public ImageButton( String s, String file, MonopolyApp app ) {
 | 
			
		||||
        this(s, true, new ElementId(ELEMENT_ID), null, file, app);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public ImageButton( String s, String style, String file, MonopolyApp app ) {
 | 
			
		||||
        this(s, true, new ElementId(ELEMENT_ID), style, file, app);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public ImageButton( String s, ElementId elementId, String file, MonopolyApp app ) {
 | 
			
		||||
        this(s, true, elementId, null, file, app);
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    public ImageButton( String s, ElementId elementId, String style, String file, MonopolyApp app ) {
 | 
			
		||||
        this(s, true, elementId, style, file, app);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    protected ImageButton( String s, boolean applyStyles, ElementId elementId, String style, String file, MonopolyApp app ) {
 | 
			
		||||
        super(s, false, elementId, style);
 | 
			
		||||
        this.file = file;
 | 
			
		||||
        ImageButton.app = app;
 | 
			
		||||
        Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/Buttons/"+file+".png");
 | 
			
		||||
        setBackground(new QuadBackgroundComponent(backgroundImage));
 | 
			
		||||
    /** The MonopolyApp instance */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    /** The button's functionality (e.g., "end_turn", "roll_dice") */
 | 
			
		||||
    private final String functionality;
 | 
			
		||||
    /** The player's color */
 | 
			
		||||
    private final PlayerColor playerColor;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new ImageButton with the given functionality and MonopolyApp instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param functionality the button's functionality (e.g., "end_turn", "roll_dice")
 | 
			
		||||
     * @param app the MonopolyApp instance
 | 
			
		||||
     */
 | 
			
		||||
    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
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void addClickCommands( Command<? super Button> command ) {
 | 
			
		||||
        super.addCommands(ButtonAction.Down, command);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @SuppressWarnings("unchecked") // because Java doesn't like var-arg generics
 | 
			
		||||
    public void addClickCommands( Command<? super Button>... commands ) {
 | 
			
		||||
        super.addCommands(ButtonAction.Down, commands);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,10 +32,10 @@ import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the lobby menu in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 *
 | 
			
		||||
 * Provides functionality for player configuration, including input for starting capital,
 | 
			
		||||
 * player name, and figure selection, as well as options to ready up or exit the game.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class LobbyMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
@@ -79,8 +79,9 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        GameMusic music = app.getStateManager().getState(GameMusic.class);
 | 
			
		||||
        music.toggleMusic();
 | 
			
		||||
 | 
			
		||||
        if (music != null && music.isEnabled()) {
 | 
			
		||||
            music.playSecondaryMusic();
 | 
			
		||||
        }
 | 
			
		||||
        playerInputField = new TextField("Spieler "+(app.getId()+1));
 | 
			
		||||
        // Hintergrundbild laden und hinzufügen
 | 
			
		||||
        addBackgroundImage();
 | 
			
		||||
@@ -153,6 +154,7 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        figures.add("Katze");
 | 
			
		||||
        figures.add("OOP");
 | 
			
		||||
        figures.add("Handyholster");
 | 
			
		||||
        figures.add("Panzer");
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        figureDropdown = new Selector<>(figures, "glass");
 | 
			
		||||
@@ -268,14 +270,17 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        app.getGameLogic().send(new PlayerReady(true, playerInputField.getText(), figure, Integer.parseInt(startingCapital.getText())));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the menu at regular intervals.
 | 
			
		||||
     * Checks if the dropdown selection has been updated and invokes the selection change handler.
 | 
			
		||||
     *
 | 
			
		||||
     * @param tpf Time per frame, in seconds, since the last update.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        if (selectionRef.update()) {
 | 
			
		||||
@@ -283,10 +288,22 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        GameMusic music = app.getStateManager().getState(GameMusic.class);
 | 
			
		||||
        if (music != null) {
 | 
			
		||||
            music.stopSecondaryMusic();
 | 
			
		||||
            if (music.isEnabled()) {
 | 
			
		||||
                music.playMainMusic();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the selected figure based on the dropdown menu selection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param selected the selected figure
 | 
			
		||||
     * @param selector the selected figure
 | 
			
		||||
     */
 | 
			
		||||
    private void onDropdownSelectionChanged(Selector<String> selector) {
 | 
			
		||||
        app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
@@ -301,7 +318,6 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
            figure = selector.getSelectedItem();
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        System.out.println("FIGUR:::::"+figure);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -28,10 +28,15 @@ import java.util.stream.Collectors;
 | 
			
		||||
 * PropertyOverviewMenu is a dialog for displaying the player's properties in the game.
 | 
			
		||||
 */
 | 
			
		||||
public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
    /** The MonopolyApp instance */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    /** The main container for the menu layout */
 | 
			
		||||
    private final Container mainContainer;
 | 
			
		||||
    /** The container for displaying the "Gebäude" cards */
 | 
			
		||||
    private final Container displayContainer;
 | 
			
		||||
    /** The horizontal slider for scrolling through cards */
 | 
			
		||||
    private final Slider horizontalSlider;
 | 
			
		||||
    /** The list of cards to display */
 | 
			
		||||
    private final List<Container> cards;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -124,6 +129,9 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card for BuildingProperty with detailed rent and cost information.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param field The BuildingProperty to create a card for.
 | 
			
		||||
     * @return The created card container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createBuildingCard(BuildingProperty field) {
 | 
			
		||||
        Container card = new Container();
 | 
			
		||||
@@ -156,6 +164,9 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card for FoodField with dynamic pricing and rent details.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param field The FoodField to create a card for.
 | 
			
		||||
     * @return The created card container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createFoodFieldCard(FoodField field) {
 | 
			
		||||
        Container card = new Container();
 | 
			
		||||
@@ -188,6 +199,9 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card for GateField with rent details for owning multiple gates.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param field The GateField to create a card for.
 | 
			
		||||
     * @return The created card container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createGateFieldCard(GateField field) {
 | 
			
		||||
        Container card = new Container();
 | 
			
		||||
@@ -206,11 +220,11 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete: 250 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("2 Bahnhof besitzt: 500 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("2 Tore besitzt: 500 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("3 Bahnhof besitzt: 1000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("3 Tore besitzt: 1000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("4 Bahnhof besitzt: 2000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("4 Tore besitzt: 2000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Dark grey background
 | 
			
		||||
@@ -260,9 +274,6 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the dialog and detaches it from the GUI node.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(mainContainer);
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,17 @@ public class SettingsMenu extends Dialog {
 | 
			
		||||
    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
 | 
			
		||||
     */
 | 
			
		||||
@@ -65,11 +75,15 @@ public class SettingsMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
        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 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(new Button("Zurück zum Spiel", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
@@ -84,21 +98,44 @@ 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
 | 
			
		||||
    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
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        musicSlider.update();
 | 
			
		||||
        soundSlider.update();
 | 
			
		||||
        update();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * As an escape action, this method closes the menu if it is the top dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,15 @@ package pp.monopoly.client.gui;
 | 
			
		||||
import com.simsilica.lemur.Slider;
 | 
			
		||||
import pp.monopoly.client.GameSound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A slider for the sound effects volume.
 | 
			
		||||
 */
 | 
			
		||||
public class SoundSlider extends Slider {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Manages sound effects for the game.
 | 
			
		||||
     */
 | 
			
		||||
    private final pp.monopoly.client.GameSound sound;
 | 
			
		||||
    private final GameSound sound;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Volume level for the game sounds.
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,9 @@ import pp.monopoly.notification.Sound;
 | 
			
		||||
 * Constructs the startup menu dialog for the Monopoly application.
 | 
			
		||||
 */
 | 
			
		||||
public class StartMenu extends Dialog {
 | 
			
		||||
    /**
 | 
			
		||||
     * The Monopoly application instance.
 | 
			
		||||
     */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -65,7 +68,7 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(centerMenu);
 | 
			
		||||
 | 
			
		||||
        // 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
 | 
			
		||||
        Container logoContainer = new Container();
 | 
			
		||||
@@ -91,8 +94,8 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        QuadBackgroundComponent unibwBackground = new QuadBackgroundComponent(unibwTexture);
 | 
			
		||||
        unibwContainer.setBackground(unibwBackground);
 | 
			
		||||
 | 
			
		||||
        float unibwWidth = 512;
 | 
			
		||||
        float unibwHeight = 128;
 | 
			
		||||
        float unibwWidth = 662;
 | 
			
		||||
        float unibwHeight = 180;
 | 
			
		||||
        unibwContainer.setPreferredSize(new Vector3f(unibwWidth, unibwHeight, 0));
 | 
			
		||||
 | 
			
		||||
        unibwContainer.setLocalTranslation(new Vector3f(
 | 
			
		||||
@@ -105,17 +108,11 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(unibwContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the startup menu and detaches all GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachAllChildren();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,565 +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.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.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
 | 
			
		||||
     */
 | 
			
		||||
    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 10–19 und 30–39 (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();
 | 
			
		||||
        } else if (event.msg().equals("ReceivedRent")) {
 | 
			
		||||
            new ReceivedRent(app, ( (NotificationMessage) event.message()).getRentOwner(), ( (NotificationMessage) event.message()).getRentAmount() ).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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,11 @@
 | 
			
		||||
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.Vector2f;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Spatial;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
@@ -13,8 +16,9 @@ import com.simsilica.lemur.VAlignment;
 | 
			
		||||
import com.simsilica.lemur.component.IconComponent;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
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 pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.popups.Bankrupt;
 | 
			
		||||
@@ -30,88 +34,41 @@ import pp.monopoly.notification.UpdatePlayerView;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the toolbar interface in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 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>
 | 
			
		||||
 * Provides game controls, player information, and event handling.
 | 
			
		||||
 */
 | 
			
		||||
public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reference to the Monopoly application instance.
 | 
			
		||||
     */
 | 
			
		||||
    /** The Monopoly application instance*/
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The main container for the toolbar interface.
 | 
			
		||||
     */
 | 
			
		||||
    /** The container representing the toolbar interface */
 | 
			
		||||
    private final Container toolbarContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Container for displaying an overview of other players.
 | 
			
		||||
     */
 | 
			
		||||
    /** The container representing the player overview information */
 | 
			
		||||
    private Container overviewContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Container for displaying account-related information.
 | 
			
		||||
     */
 | 
			
		||||
    /** The container representing the player account information */
 | 
			
		||||
    private Container accountContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles player-related data and actions.
 | 
			
		||||
     */
 | 
			
		||||
    /** The player handler instance */
 | 
			
		||||
    private PlayerHandler playerHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Label for the first dice display.
 | 
			
		||||
     */
 | 
			
		||||
    /** The label representing the left dice */
 | 
			
		||||
    private Label imageLabel;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Label for the second dice display.
 | 
			
		||||
     */
 | 
			
		||||
    /** The label representing the right dice */
 | 
			
		||||
    private Label imageLabel2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Button for rolling the dice.
 | 
			
		||||
     */
 | 
			
		||||
    private Button diceButton;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Button for initiating trades.
 | 
			
		||||
     */
 | 
			
		||||
    /** The flag to check if the dice can be rolled */
 | 
			
		||||
    private boolean canRollDice = false;
 | 
			
		||||
    /** The trade button */
 | 
			
		||||
    private Button tradeButton;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Button for accessing the property menu.
 | 
			
		||||
     */
 | 
			
		||||
    /** The property menu button */
 | 
			
		||||
    private Button propertyMenuButton;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Button for ending the player's turn.
 | 
			
		||||
     */
 | 
			
		||||
    /** The end turn button */
 | 
			
		||||
    private Button endTurnButton;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Stores the most recent dice roll event.
 | 
			
		||||
     */
 | 
			
		||||
    /** The latest incoming Dice Roll Event */
 | 
			
		||||
    private DiceRollEvent latestDiceRollEvent = null;
 | 
			
		||||
 | 
			
		||||
    /**Indicates if the bankrupt PopUp has already been shown */
 | 
			
		||||
    /** The flag to check if the bankrupt pop up is already shown */
 | 
			
		||||
    private boolean bankruptPopUp = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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>
 | 
			
		||||
     * Constructs a new {@code Toolbar} for the given {@code MonopolyApp}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     * @param app The {@code MonopolyApp} instance to create the toolbar for.
 | 
			
		||||
     */
 | 
			
		||||
    public Toolbar(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
@@ -120,111 +77,190 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
        app.getGameLogic().addListener(this);
 | 
			
		||||
        this.playerHandler = app.getGameLogic().getPlayerHandler();
 | 
			
		||||
 | 
			
		||||
        toolbarContainer = createToolbarContainer();
 | 
			
		||||
        toolbarContainer = setupToolbar();
 | 
			
		||||
        app.getGuiNode().attachChild(toolbarContainer);
 | 
			
		||||
 | 
			
		||||
        endTurnButton.setEnabled(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Container createToolbarContainer() {
 | 
			
		||||
    /**
 | 
			
		||||
     * 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.setLocalTranslation(0, 200, 0);
 | 
			
		||||
        container.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 200, 0));
 | 
			
		||||
 | 
			
		||||
        Texture backgroundToolbar = app.getAssetManager().loadTexture("Pictures/toolbarbg.png");
 | 
			
		||||
        QuadBackgroundComponent background = new QuadBackgroundComponent(backgroundToolbar);
 | 
			
		||||
        background.setMargin(0, 0); // Removes any internal margin
 | 
			
		||||
        container.setBackground(background);
 | 
			
		||||
    
 | 
			
		||||
        // Spielerfarbe abrufen
 | 
			
		||||
        Player currentPlayer = playerHandler.getPlayerById(app.getId());
 | 
			
		||||
        ColorRGBA playerColor = Player.getColor(currentPlayer.getId()).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
 | 
			
		||||
        Container playerColorBarbot = new Container();
 | 
			
		||||
        playerColorBarbot.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 10, 0)); // Höhe des oberen Balkens
 | 
			
		||||
        playerColorBarbot.setBackground(new QuadBackgroundComponent(playerColor));
 | 
			
		||||
        playerColorBarbot.setLocalTranslation(0, 10, 3); // Position über der Toolbar
 | 
			
		||||
        app.getGuiNode().attachChild(playerColorBarbot);
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
        // Linker Balken
 | 
			
		||||
        Container leftBar = new Container();
 | 
			
		||||
        leftBar.setPreferredSize(new Vector3f(10, 210, 0)); // Breite 10, Höhe 210
 | 
			
		||||
        leftBar.setBackground(new QuadBackgroundComponent(playerColor));
 | 
			
		||||
        leftBar.setLocalTranslation(0, 200, 3); // Position am linken Rand
 | 
			
		||||
        app.getGuiNode().attachChild(leftBar);
 | 
			
		||||
    
 | 
			
		||||
        // Rechter Balken
 | 
			
		||||
        Container rightBar = new Container();
 | 
			
		||||
        rightBar.setPreferredSize(new Vector3f(10, 210, 0)); // Breite 10, Höhe 210
 | 
			
		||||
        rightBar.setBackground(new QuadBackgroundComponent(playerColor));
 | 
			
		||||
        rightBar.setLocalTranslation(app.getCamera().getWidth() - 10, 200, 2); // Position am rechten Rand
 | 
			
		||||
        app.getGuiNode().attachChild(rightBar);
 | 
			
		||||
        
 | 
			
		||||
        // Übersicht und Konto
 | 
			
		||||
        accountContainer = container.addChild(new Container());
 | 
			
		||||
        overviewContainer = container.addChild(new Container());
 | 
			
		||||
        receivedEvent(new UpdatePlayerView()); // Initiale Aktualisierung
 | 
			
		||||
    
 | 
			
		||||
        // Würfel-Bereich
 | 
			
		||||
        container.addChild(createDiceSection());
 | 
			
		||||
    
 | 
			
		||||
        // Aktionsmenü
 | 
			
		||||
        setupBorders(container);
 | 
			
		||||
        setupSpacer(container);
 | 
			
		||||
        setupPlayerInfoSection(container);
 | 
			
		||||
        setupSpacer(container);
 | 
			
		||||
        setupDiceSection(container);
 | 
			
		||||
        setupActionMenu(container);
 | 
			
		||||
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up the borders for the toolbar interface.
 | 
			
		||||
     *
 | 
			
		||||
     * @param container The container representing the toolbar interface.
 | 
			
		||||
     */
 | 
			
		||||
    private void setupBorders(Container container) {
 | 
			
		||||
        addBorder(0, 205, app.getCamera().getWidth(), 5, ColorRGBA.DarkGray); // Top
 | 
			
		||||
        addBorder(0, 5, app.getCamera().getWidth(), 10, ColorRGBA.DarkGray); // Bottom
 | 
			
		||||
        addBorder(0, 200, 8, 210, ColorRGBA.DarkGray); // Left
 | 
			
		||||
        addBorder(app.getCamera().getWidth() - 5, 200, 8, 210, ColorRGBA.DarkGray); // Right
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a border to the toolbar interface with the specified dimensions and color.
 | 
			
		||||
     *
 | 
			
		||||
     * @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());
 | 
			
		||||
        menuContainer.addChild(createTradeButton());
 | 
			
		||||
        menuContainer.addChild(createPropertyMenuButton());
 | 
			
		||||
        menuContainer.addChild(createEndTurnButton());
 | 
			
		||||
        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);
 | 
			
		||||
            endTurnButton.setEnabled(true);
 | 
			
		||||
            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() {
 | 
			
		||||
        Container horizontalContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        horizontalContainer.setPreferredSize(new Vector3f(200, 150, 0));
 | 
			
		||||
        horizontalContainer.setBackground(null);
 | 
			
		||||
 | 
			
		||||
        imageLabel = createDiceLabel("Pictures/dice/one.png");
 | 
			
		||||
        imageLabel2 = createDiceLabel("Pictures/dice/two.png");
 | 
			
		||||
 | 
			
		||||
        horizontalContainer.setBackground(null);
 | 
			
		||||
 | 
			
		||||
        horizontalContainer.addChild(createDiceContainer(imageLabel));
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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) {
 | 
			
		||||
        Label label = new Label("");
 | 
			
		||||
        IconComponent icon = new IconComponent(iconPath);
 | 
			
		||||
        icon.setIconSize(new Vector2f(100, 100));
 | 
			
		||||
        icon.setIconSize(new Vector2f(80, 80));
 | 
			
		||||
        label.setIcon(icon);
 | 
			
		||||
        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) {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(null);
 | 
			
		||||
@@ -233,77 +269,115 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Button createTradeButton() {
 | 
			
		||||
    /**
 | 
			
		||||
     * 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);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        tradeButton = new Button("", new ElementId("button-toolbar"));
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the trade button.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The trade button.
 | 
			
		||||
     */
 | 
			
		||||
    private Button createTradeButton() {
 | 
			
		||||
        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));
 | 
			
		||||
 | 
			
		||||
        String iconTradePath = "icons/icon-handeln.png";
 | 
			
		||||
        IconComponent iconTrade = new IconComponent(iconTradePath);
 | 
			
		||||
        iconTrade.setHAlignment(HAlignment.Center);
 | 
			
		||||
        iconTrade.setVAlignment(VAlignment.Center);
 | 
			
		||||
        iconTrade.setIconSize(new Vector2f(100, 100));
 | 
			
		||||
        IconComponent icon = new IconComponent(iconPath);
 | 
			
		||||
        icon.setHAlignment(HAlignment.Center);
 | 
			
		||||
        icon.setVAlignment(VAlignment.Center);
 | 
			
		||||
        icon.setIconSize(new Vector2f(75 , 75));
 | 
			
		||||
        tradeButton.setIcon(icon);
 | 
			
		||||
 | 
			
		||||
        tradeButton.setIcon(iconTrade);
 | 
			
		||||
        tradeButton.setFontSize(40);
 | 
			
		||||
 | 
			
		||||
        // Add click behavior
 | 
			
		||||
        tradeButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        tradeButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            new ChoosePartner(app).open();
 | 
			
		||||
            
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return tradeButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the property menu button.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The property menu button.
 | 
			
		||||
     */
 | 
			
		||||
    private Button createPropertyMenuButton() {
 | 
			
		||||
        propertyMenuButton = new Button("", new ElementId("button-toolbar"));
 | 
			
		||||
 | 
			
		||||
        String iconPath = "icons/icon-gebaude.png";
 | 
			
		||||
        propertyMenuButton = new ImageButton("generic", app);
 | 
			
		||||
        propertyMenuButton.setPreferredSize(new Vector3f(150, 50, 0));
 | 
			
		||||
 | 
			
		||||
        String iconBuildingPath = "icons/icon-gebaude.png";
 | 
			
		||||
        IconComponent iconBuilding = new IconComponent(iconBuildingPath);
 | 
			
		||||
        iconBuilding.setHAlignment(HAlignment.Center);
 | 
			
		||||
        iconBuilding.setVAlignment(VAlignment.Center);
 | 
			
		||||
        iconBuilding.setIconSize(new Vector2f(75, 75));
 | 
			
		||||
        IconComponent icon = new IconComponent(iconPath);
 | 
			
		||||
        icon.setHAlignment(HAlignment.Center);
 | 
			
		||||
        icon.setVAlignment(VAlignment.Center);
 | 
			
		||||
        icon.setIconSize(new Vector2f(50 , 50));
 | 
			
		||||
        propertyMenuButton.setIcon(icon);
 | 
			
		||||
 | 
			
		||||
        propertyMenuButton.setIcon(iconBuilding);
 | 
			
		||||
        propertyMenuButton.setFontSize(30);
 | 
			
		||||
        propertyMenuButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            new BuildingAdminMenu(app).open();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return propertyMenuButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the end turn button.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The end turn button.
 | 
			
		||||
     */
 | 
			
		||||
    private Button createEndTurnButton() {
 | 
			
		||||
        endTurnButton = new Button("", new ElementId("button-toolbar"));
 | 
			
		||||
        endTurnButton.setFontSize(28);
 | 
			
		||||
        // return createActionButton(playerColor, "icons/icon-zugbeenden.png", 75, () -> handleEndTurn());
 | 
			
		||||
 | 
			
		||||
        String iconPath = "icons/icon-zugbeenden.png";
 | 
			
		||||
        endTurnButton = new ImageButton("generic", app);
 | 
			
		||||
        endTurnButton.setPreferredSize(new Vector3f(150, 50, 0));
 | 
			
		||||
 | 
			
		||||
        String iconEndTurnPath = "icons/icon-zugbeenden.png";
 | 
			
		||||
        IconComponent iconEndTurn = new IconComponent(iconEndTurnPath);
 | 
			
		||||
        iconEndTurn.setHAlignment(HAlignment.Center);
 | 
			
		||||
        iconEndTurn.setVAlignment(VAlignment.Center);
 | 
			
		||||
        iconEndTurn.setIconSize(new Vector2f(75, 75));
 | 
			
		||||
        IconComponent icon = new IconComponent(iconPath);
 | 
			
		||||
        icon.setHAlignment(HAlignment.Center);
 | 
			
		||||
        icon.setVAlignment(VAlignment.Center);
 | 
			
		||||
        icon.setIconSize(new Vector2f(50 , 50));
 | 
			
		||||
        endTurnButton.setIcon(icon);
 | 
			
		||||
 | 
			
		||||
        endTurnButton.setIcon(iconEndTurn);
 | 
			
		||||
        endTurnButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            if (app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getAccountBalance() < 0 && !bankruptPopUp) {
 | 
			
		||||
                new Bankrupt(app).open();
 | 
			
		||||
                bankruptPopUp = true;
 | 
			
		||||
            } else {
 | 
			
		||||
                bankruptPopUp = false;
 | 
			
		||||
                app.getGameLogic().send(new EndTurn());
 | 
			
		||||
                receivedEvent(new ButtonStatusEvent(false));
 | 
			
		||||
            }
 | 
			
		||||
            handleEndTurn();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return endTurnButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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() {
 | 
			
		||||
        long startTime = System.currentTimeMillis();
 | 
			
		||||
    
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            try {
 | 
			
		||||
                animateDice(startTime);
 | 
			
		||||
@@ -311,35 +385,42 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
                    showFinalDiceResult(latestDiceRollEvent);
 | 
			
		||||
                }
 | 
			
		||||
            } catch (InterruptedException e) {
 | 
			
		||||
                System.err.println("Dice animation interrupted: " + e.getMessage());
 | 
			
		||||
                e.printStackTrace();
 | 
			
		||||
            }
 | 
			
		||||
        }).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 {
 | 
			
		||||
        int[] currentFace = {1};
 | 
			
		||||
        while (System.currentTimeMillis() - startTime < 2000) { // Animation duration
 | 
			
		||||
        while (System.currentTimeMillis() - startTime < 2000) {
 | 
			
		||||
            currentFace[0] = (currentFace[0] % 6) + 1;
 | 
			
		||||
    
 | 
			
		||||
            String rotatingImage1 = diceToString(currentFace[0]);
 | 
			
		||||
            String rotatingImage2 = diceToString((currentFace[0] % 6) + 1);
 | 
			
		||||
    
 | 
			
		||||
            app.enqueue(() -> {
 | 
			
		||||
                setDiceIcon(imageLabel, rotatingImage1);
 | 
			
		||||
                setDiceIcon(imageLabel2, rotatingImage2);
 | 
			
		||||
            });
 | 
			
		||||
    
 | 
			
		||||
            Thread.sleep(100); // Time between frame updates
 | 
			
		||||
            updateDiceIcons(currentFace[0]);
 | 
			
		||||
            Thread.sleep(100);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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) {
 | 
			
		||||
        app.enqueue(() -> {
 | 
			
		||||
@@ -347,28 +428,39 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
            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) {
 | 
			
		||||
        IconComponent icon = new IconComponent(imagePath);
 | 
			
		||||
        icon.setIconSize(new Vector2f(80, 80)); // Set consistent dice size
 | 
			
		||||
        icon.setIconSize(new Vector2f(80, 80));
 | 
			
		||||
        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
 | 
			
		||||
     */
 | 
			
		||||
@@ -378,77 +470,79 @@ 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
 | 
			
		||||
    public void receivedEvent(UpdatePlayerView event) {
 | 
			
		||||
        playerHandler = app.getGameLogic().getPlayerHandler();
 | 
			
		||||
        System.out.println("Update Player View");
 | 
			
		||||
        refreshPlayerView();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refreshes the player view.
 | 
			
		||||
     */
 | 
			
		||||
    private void refreshPlayerView() {
 | 
			
		||||
        accountContainer.clearChildren();
 | 
			
		||||
        overviewContainer.clearChildren();
 | 
			
		||||
 | 
			
		||||
        accountContainer.addChild(new Label("Kontostand", new ElementId("label-toolbar")));
 | 
			
		||||
        accountContainer.addChild(new Label(
 | 
			
		||||
                playerHandler.getPlayerById(app.getId()).getAccountBalance() + " EUR",
 | 
			
		||||
                new ElementId("label-account")
 | 
			
		||||
        ));
 | 
			
		||||
        accountContainer.addChild(new Label("Gulag Karten", new ElementId("label-toolbar")));
 | 
			
		||||
        accountContainer.addChild(new Label(
 | 
			
		||||
                playerHandler.getPlayerById(app.getId()).getNumJailCard() + "",
 | 
			
		||||
                new ElementId("label-account")
 | 
			
		||||
        ));
 | 
			
		||||
        accountContainer.setBackground(null);
 | 
			
		||||
        addAccountDetails();
 | 
			
		||||
        addOverviewDetails();
 | 
			
		||||
 | 
			
		||||
        overviewContainer.addChild(new Label("Übersicht", new ElementId("label-toolbar")));
 | 
			
		||||
        for (Player player : playerHandler.getPlayers()) {
 | 
			
		||||
            if (player.getId() != app.getId()) {
 | 
			
		||||
                // Spielerfarbe abrufen
 | 
			
		||||
                ColorRGBA playerColor = (Player.getColor(player.getId()).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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        accountContainer.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
 | 
			
		||||
    public void receivedEvent(ButtonStatusEvent event) {
 | 
			
		||||
        boolean enabled = event.buttonsEnabled();
 | 
			
		||||
        diceButton.setEnabled(enabled);
 | 
			
		||||
        canRollDice = enabled;
 | 
			
		||||
        tradeButton.setEnabled(enabled);
 | 
			
		||||
        propertyMenuButton.setEnabled(enabled);
 | 
			
		||||
        endTurnButton.setEnabled(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the toolbar and detaches it from the GUI.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(toolbarContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
@@ -459,7 +553,7 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update() {
 | 
			
		||||
        receivedEvent(new UpdatePlayerView());
 | 
			
		||||
        refreshPlayerView();
 | 
			
		||||
        super.update();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,10 +30,10 @@ import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the trade menu dialog in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 *
 | 
			
		||||
 * Facilitates trade interactions between players, including selection of properties,
 | 
			
		||||
 * currency, and special cards for offers and requests.
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
public class TradeMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
@@ -48,17 +48,26 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    /** Background geometry for the menu. */
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
    /** The building and card selector for the left column. */
 | 
			
		||||
    private Selector<String> leftBuildingSelector, leftSpecialCardSelector;
 | 
			
		||||
    /** The building and card selector for the right column. */
 | 
			
		||||
    private Selector<String> rightBuildingSelector, rightSpecialCardSelector;
 | 
			
		||||
    /** The labels for displaying selected properties. */
 | 
			
		||||
    private Label leftSelectionsLabel, rightSelectionsLabel;
 | 
			
		||||
    /** The text fields for currency input. */
 | 
			
		||||
    private TextField leftCurrencyInput, rightCurrencyInput;
 | 
			
		||||
 | 
			
		||||
    /** References for tracking UI changes. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> leftBuildingRef, rightBuildingRef;
 | 
			
		||||
    /** References for tracking UI changes. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> leftCardRef, rightCardRef;
 | 
			
		||||
 | 
			
		||||
    /** The selected buildings for the trade. */
 | 
			
		||||
    private Set<String> rightselBuildings = new HashSet<>();
 | 
			
		||||
    /** The selected buildings for the trade. */
 | 
			
		||||
    private Set<String> leftselBuildings = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    /** The color for the trade menu background. */
 | 
			
		||||
    private static final ColorRGBA TRANSLUCENT_WHITE = new ColorRGBA(1, 1, 1, 0.5f);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -80,7 +89,11 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
        initializeReferences();
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the main container for the trade menu UI. */
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main container for the trade menu.
 | 
			
		||||
     * @return the created main container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createMainContainer() {
 | 
			
		||||
        Container container = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(1200, 800, 0));
 | 
			
		||||
@@ -90,7 +103,11 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        container.addChild(createMainContent());
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the header label for the trade menu. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the header label for the trade menu.
 | 
			
		||||
     * @return the created header label
 | 
			
		||||
     */
 | 
			
		||||
    private Label createHeader() {
 | 
			
		||||
        Label header = new Label("Handelsmenü", new ElementId("label-Bold"));
 | 
			
		||||
        header.setFontSize(50);
 | 
			
		||||
@@ -98,7 +115,11 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        header.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE));
 | 
			
		||||
        return header;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the main content section of the trade menu. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main content for the trade menu.
 | 
			
		||||
     * @return the created main content container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createMainContent() {
 | 
			
		||||
        Container mainContent = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        mainContent.setPreferredSize(new Vector3f(1200, 700, 0));
 | 
			
		||||
@@ -110,7 +131,9 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        return mainContent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Sets the trade data based on the current selections. */
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the trade values based on the user input.
 | 
			
		||||
     */
 | 
			
		||||
    private void setTrades() {
 | 
			
		||||
        String leftCurreny = leftCurrencyInput.getText().equals("")? "0" : leftCurrencyInput.getText();
 | 
			
		||||
        String rightCurreny = rightCurrencyInput.getText().equals("")? "0" : rightCurrencyInput.getText();
 | 
			
		||||
@@ -232,13 +255,21 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        combinedProperties = combinedProperties.stream().sorted(Comparator.comparingInt(PropertyField::getId)).collect(Collectors.toList());
 | 
			
		||||
        return combinedProperties;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates a text field for currency input. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a currency input field for the trade menu.
 | 
			
		||||
     * @return the created currency input field
 | 
			
		||||
     */
 | 
			
		||||
    private TextField createCurrencyInput() {
 | 
			
		||||
        TextField currencyInput = new TextField("0");
 | 
			
		||||
        styleTextField(currencyInput);
 | 
			
		||||
        return currencyInput;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the middle section containing buttons and summary fields. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the middle section of the trade menu.
 | 
			
		||||
     * @return the created middle section container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createMiddleSection() {
 | 
			
		||||
        Container middleSection = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        middleSection.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)));
 | 
			
		||||
@@ -281,13 +312,19 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        return middleSection;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Styles the given selector with insets and background color. */
 | 
			
		||||
    /**
 | 
			
		||||
     * Styles the given selector with insets and background color.
 | 
			
		||||
     * @param selector  the selector to style
 | 
			
		||||
     */
 | 
			
		||||
    private void styleSelector(Selector<String> selector) {
 | 
			
		||||
        selector.setInsets(new Insets3f(5, 10, 5, 10));
 | 
			
		||||
        selector.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Styles the given text field with insets and background color. */
 | 
			
		||||
    /**
 | 
			
		||||
     * Styles the given text field with insets and background color.
 | 
			
		||||
     * @param textField the text field to style
 | 
			
		||||
     */
 | 
			
		||||
    private void styleTextField(TextField textField) {
 | 
			
		||||
        textField.setInsets(new Insets3f(5, 10, 5, 10));
 | 
			
		||||
        textField.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
 | 
			
		||||
@@ -314,7 +351,10 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
            rightCurrencyInput = currencyInput;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    /** Positions the main container at the center of the screen. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Positions the main container in the center of the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void positionMainContainer() {
 | 
			
		||||
        mainContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2,
 | 
			
		||||
@@ -322,7 +362,10 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    /** Adds a background image to the trade menu. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a background image to the trade menu.
 | 
			
		||||
     */
 | 
			
		||||
    private void addBackgroundImage() {
 | 
			
		||||
        Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
@@ -333,6 +376,7 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        background.setLocalTranslation(0, 0, 6);
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /** Initializes references for tracking UI changes. */
 | 
			
		||||
    private void initializeReferences() {
 | 
			
		||||
        leftBuildingRef = leftBuildingSelector.getSelectionModel().createReference();
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,9 @@ import pp.monopoly.client.GameMusic;
 | 
			
		||||
 */
 | 
			
		||||
public class VolumeSlider extends Slider {
 | 
			
		||||
 | 
			
		||||
    private final pp.monopoly.client.GameMusic music;
 | 
			
		||||
    /** The GameMusic instance to handel */
 | 
			
		||||
    private final GameMusic music;
 | 
			
		||||
    /** The volume of the music */
 | 
			
		||||
    private double vol;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -910,7 +910,6 @@
 | 
			
		||||
         }
 | 
			
		||||
         sliderhorsetup();
 | 
			
		||||
         adjustothercolumnmodel();
 | 
			
		||||
         //     System.out.println("Columns available: " +availableColumns);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @StyleAttribute(value="visibleColumns")
 | 
			
		||||
@@ -923,7 +922,6 @@
 | 
			
		||||
         sliderhorsetup();
 | 
			
		||||
         grid.refreshGrid();
 | 
			
		||||
         refreshSelector();
 | 
			
		||||
         //  System.out.println("Columns visble: " +grid.getVisibleColumns());
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     // Column Operations
 | 
			
		||||
 
 | 
			
		||||
@@ -12,33 +12,31 @@ 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.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a confirmation dialog that appears when a trade is accepted .
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Displays a message to the user informing them that the trade they proposed has been accepted,
 | 
			
		||||
 * along with a confirmation button to close the dialog.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the dialog. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Container for the warning message content. */
 | 
			
		||||
    private final Container noMoneyWarningContainer;
 | 
			
		||||
    private Container noMoneyWarningContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the accept trade dialog.
 | 
			
		||||
     * Constructs the AcceptTrade dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     * @param msg the trade reply message containing details about the trade
 | 
			
		||||
@@ -47,80 +45,99 @@ public class AcceptTrade extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        noMoneyWarningContainer = new Container();
 | 
			
		||||
        noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Handel angenommen!", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast Spieler"+ " " + msg.getTradeHandler().getReceiver().getName() + " " + "einen Handel vorgeschlagen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Der Handel wurde angenommen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
        // Initialize GUI elements
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createWarningContainer(msg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
    private void createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        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)); // Halbtransparent
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
        overlayBackground.setMaterial(material);
 | 
			
		||||
        overlayBackground.setLocalTranslation(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container for the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    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 warning container for the dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the trade reply message
 | 
			
		||||
     */
 | 
			
		||||
    private void createWarningContainer(TradeReply msg) {
 | 
			
		||||
        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;
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = noMoneyWarningContainer.addChild(new Label("Handel angenommen!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Message
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.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 angenommen.", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
 | 
			
		||||
        // Confirmation button
 | 
			
		||||
        Button confirmButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Centers the warning and background containers on the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void centerContainers() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Center main container
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Center background container with padding
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Displays the dialog by attaching it to the GUI through the DialogManager.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
        centerContainers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -128,9 +145,9 @@ public class AcceptTrade extends Dialog {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -139,6 +156,6 @@ public class AcceptTrade extends Dialog {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,24 +12,24 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the bankruptcy warning content. */
 | 
			
		||||
    private final Container bankruptContainer;
 | 
			
		||||
    private Container bankruptContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the bankruptcy warning popup.
 | 
			
		||||
@@ -40,93 +40,101 @@ public class Bankrupt extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        bankruptContainer = new Container();
 | 
			
		||||
        bankruptContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        bankruptContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = bankruptContainer.addChild(new Label("Vorsicht !", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = bankruptContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast noch einen negativen Kontostand. Wenn du jetzt deinen Zug beendest, gehst du Bankrott und verlierst das Spiel!", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = bankruptContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(this::close));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        bankruptContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(bankruptContainer);
 | 
			
		||||
        // Initialize the components
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createBankruptContainer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
    private void createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        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)); // Halbtransparent
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
        overlayBackground.setMaterial(material);
 | 
			
		||||
        overlayBackground.setLocalTranslation(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the menu and removes the GUI elements.
 | 
			
		||||
     * Creates the background container for the popup.
 | 
			
		||||
     */
 | 
			
		||||
    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 container for the bankruptcy warning content.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBankruptContainer() {
 | 
			
		||||
        bankruptContainer = new Container();
 | 
			
		||||
        bankruptContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        bankruptContainer.setPreferredSize(new Vector3f(550, 350, 10));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = bankruptContainer.addChild(new Label("Vorsicht!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text content
 | 
			
		||||
        Container textContainer = bankruptContainer.addChild(new Container());
 | 
			
		||||
        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.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
 | 
			
		||||
        // Confirmation button
 | 
			
		||||
        Button confirmButton = bankruptContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(this::close));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Centers the popup containers on the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void centerContainers() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Center bankrupt container
 | 
			
		||||
        bankruptContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Center background container with padding
 | 
			
		||||
        backgroundContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(bankruptContainer);
 | 
			
		||||
        centerContainers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(bankruptContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(bankruptContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape key action by closing the popup.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
@@ -8,6 +9,7 @@ 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.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
@@ -16,16 +18,15 @@ import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
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 {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
public class BuildingPropertyCard extends Dialog implements PopupDialog {
 | 
			
		||||
 | 
			
		||||
    /**The Monopoly application instance*/
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the building property information. */
 | 
			
		||||
    /**The main container for the popup*/
 | 
			
		||||
    private final Container buildingPropertyContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the property card. */
 | 
			
		||||
    /**The background container for the popup*/
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -37,92 +38,122 @@ public class BuildingPropertyCard extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponding field
 | 
			
		||||
        int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
 | 
			
		||||
        BuildingProperty field = (BuildingProperty) new BoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
        // Create the main container for the popup
 | 
			
		||||
        buildingPropertyContainer = new Container();
 | 
			
		||||
        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));
 | 
			
		||||
 | 
			
		||||
        //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
 | 
			
		||||
        // Die Preise werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        Container propertyValuesContainer = buildingPropertyContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 1 Haus: " + field.getAllRent().get(1) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 2 Häuser: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 3 Häuser: " + field.getAllRent().get(3) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 4 Häuser: " + field.getAllRent().get(4) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 1 Hotel: " + field.getAllRent().get(5) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        System.out.println(backgroundContainer.getPreferredSize());
 | 
			
		||||
 | 
			
		||||
        // Position the containers
 | 
			
		||||
        centerContainers(padding);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds the property details and buttons to the container.
 | 
			
		||||
     *
 | 
			
		||||
     * @param container the main container for the property card
 | 
			
		||||
     * @param field     the building property to display
 | 
			
		||||
     */
 | 
			
		||||
    private void addContentToContainer(Container container, BuildingProperty field) {
 | 
			
		||||
        // 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)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = buildingPropertyContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        // Add buttons
 | 
			
		||||
        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.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            System.err.println("Button does something?");
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            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.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
            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(
 | 
			
		||||
            (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        // Center background container with padding
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
            (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
            7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(buildingPropertyContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes the associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(buildingPropertyContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(buildingPropertyContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
@@ -40,8 +39,8 @@ public class BuyHouse extends Dialog {
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** TextField to display selected properties. */
 | 
			
		||||
    private TextField selectionDisplay;
 | 
			
		||||
    /** Label to display selected properties. */
 | 
			
		||||
    private Label selectionDisplay;
 | 
			
		||||
 | 
			
		||||
    /** Reference for tracking dropdown selection changes. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
@@ -77,7 +76,7 @@ public class BuyHouse extends Dialog {
 | 
			
		||||
        backgroundContainer.setPreferredSize(buyHouseContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // 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.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
@@ -145,7 +144,7 @@ public class BuyHouse extends Dialog {
 | 
			
		||||
    private Container createPropertyDropdown() {
 | 
			
		||||
        Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> propertyOptions = new VersionedList<>();
 | 
			
		||||
        List<BuildingProperty> playerProperties = getPlayerProperties();
 | 
			
		||||
@@ -162,8 +161,9 @@ public class BuyHouse extends Dialog {
 | 
			
		||||
        selectionRef = propertySelector.getSelectionModel().createReference();
 | 
			
		||||
 | 
			
		||||
        // Initialize the selection display here
 | 
			
		||||
        selectionDisplay = new TextField(""); // Create TextField for displaying selections
 | 
			
		||||
        selectionDisplay = new Label("");
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
        // Set initial selection
 | 
			
		||||
@@ -227,9 +227,6 @@ public class BuyHouse extends Dialog {
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(buyHouseContainer);
 | 
			
		||||
@@ -237,9 +234,6 @@ public class BuyHouse extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ 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.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.client.gui.TradeMenu;
 | 
			
		||||
@@ -18,18 +19,18 @@ import pp.monopoly.notification.Sound;
 | 
			
		||||
/**
 | 
			
		||||
 * ConfirmTrade is a popup which appears when a trade is proposed to this certain player.
 | 
			
		||||
 */
 | 
			
		||||
public class ConfirmTrade extends Dialog {
 | 
			
		||||
public class ConfirmTrade extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the "Confirm Trade" popup UI. */
 | 
			
		||||
    private final Container confirmTradeContainer;
 | 
			
		||||
    private Container confirmTradeContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** The trade handler managing the details of the trade proposal. */
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
    private final TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the "Confirm Trade" popup.
 | 
			
		||||
@@ -39,53 +40,61 @@ public class ConfirmTrade extends Dialog {
 | 
			
		||||
    public ConfirmTrade(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        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.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the main confirm trade container and its UI components.
 | 
			
		||||
     */
 | 
			
		||||
    private void createConfirmTradeContainer() {
 | 
			
		||||
        confirmTradeContainer = new Container();
 | 
			
		||||
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        backgroundContainer.setPreferredSize(confirmTradeContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label title = confirmTradeContainer.addChild(new Label( "Handel", new ElementId("warning-title")));
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = confirmTradeContainer.addChild(new Label("Handel", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Build trade information strings
 | 
			
		||||
        StringBuilder offeredProperties = new StringBuilder();
 | 
			
		||||
        for (PropertyField field : tradeHandler.getOfferedProperties()) {
 | 
			
		||||
            offeredProperties.append(field.getName());
 | 
			
		||||
            offeredProperties.append(", ");
 | 
			
		||||
            offeredProperties.append(field.getName()).append(", ");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        StringBuilder requestedProperties = new StringBuilder();
 | 
			
		||||
        for (PropertyField field : tradeHandler.getRequestedProperties()) {
 | 
			
		||||
            requestedProperties.append(field.getName());
 | 
			
		||||
            requestedProperties.append(", ");
 | 
			
		||||
            requestedProperties.append(field.getName()).append(", ");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Trade details
 | 
			
		||||
        Container propertyValuesContainer = confirmTradeContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Spieler " + " " + tradeHandler.getSender().getName() + " " +" möchte:", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label( tradeHandler.getSender().getName() + " möchte:", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", 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.getOfferedJailCards() +" Sonderkarten", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedJailCards() + " Sonderkarten", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", 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("- "+ requestedProperties, new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedAmount() +" EUR", 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("- " + requestedProperties, new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + tradeHandler.getRequestedAmount() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + tradeHandler.getRequestedJailCards() + " Sonderkarten", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", 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)));
 | 
			
		||||
 | 
			
		||||
        // Ablehnen-Button
 | 
			
		||||
        // Decline button
 | 
			
		||||
        Button declineButton = confirmTradeContainer.addChild(new Button("Ablehnen", new ElementId("button")));
 | 
			
		||||
        declineButton.setFontSize(32);
 | 
			
		||||
        declineButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
@@ -93,45 +102,50 @@ public class ConfirmTrade extends Dialog {
 | 
			
		||||
            app.getGameLogic().send(new TradeResponse(false, tradeHandler));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Verhandeln-Button
 | 
			
		||||
 | 
			
		||||
        // Negotiate button
 | 
			
		||||
        Button negotiateButton = confirmTradeContainer.addChild(new Button("Verhandeln", new ElementId("button")));
 | 
			
		||||
        negotiateButton.setFontSize(32);
 | 
			
		||||
        negotiateButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        negotiateButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
            TradeHandler t = new TradeHandler(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getSender().getId()));
 | 
			
		||||
            t.setReceiver(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getReceiver().getId()));
 | 
			
		||||
            new TradeMenu(app, t).open();
 | 
			
		||||
        }));
 | 
			
		||||
        // Confirm-Button
 | 
			
		||||
 | 
			
		||||
        // Confirm button
 | 
			
		||||
        Button confirmButton = confirmTradeContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new TradeResponse(true, tradeHandler));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Center and adjust sizes
 | 
			
		||||
        backgroundContainer.setPreferredSize(confirmTradeContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        confirmTradeContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
                (app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach to GUI node
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(confirmTradeContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(confirmTradeContainer);
 | 
			
		||||
@@ -139,9 +153,6 @@ public class ConfirmTrade extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,25 +12,25 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the event card information. */
 | 
			
		||||
    private final Container eventCardContainer;
 | 
			
		||||
    private Container eventCardContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the EventCardPopup to display the details of a triggered event card.
 | 
			
		||||
@@ -42,92 +42,96 @@ public class EventCardPopup extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        // Initialize the UI components
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        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.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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.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;
 | 
			
		||||
        backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
        // Event description
 | 
			
		||||
        Container textContainer = eventCardContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label(description, new ElementId("label-Text")));
 | 
			
		||||
        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
 | 
			
		||||
        // Die Erklärungsfelder werden automatisch den descriptions der Message entnommen
 | 
			
		||||
        Container propertyValuesContainer = eventCardContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label(description, new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        propertyValuesContainer.setPreferredSize(new Vector3f(300,200,10));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog( () -> {
 | 
			
		||||
        // Confirm button
 | 
			
		||||
        Button confirmButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Adjust sizes and center elements
 | 
			
		||||
        backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        eventCardContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            10
 | 
			
		||||
                (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                9
 | 
			
		||||
                (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach components to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(eventCardContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    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));
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(eventCardContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape key action by closing the popup.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package pp.monopoly.client.gui.popups;
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
@@ -12,27 +13,27 @@ 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.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
import pp.monopoly.model.fields.FoodField;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the food field information. */
 | 
			
		||||
    private final Container foodFieldContainer;
 | 
			
		||||
    private Container foodFieldContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a FoodFieldCard popup displaying details about a food field.
 | 
			
		||||
@@ -43,108 +44,118 @@ public class FoodFieldCard extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Retrieve field information
 | 
			
		||||
        int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
 | 
			
		||||
        FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        // Create UI elements
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createFoodFieldContainer(field);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
 | 
			
		||||
        foodFieldContainer.setPreferredSize(new Vector3f(360,445,1));
 | 
			
		||||
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        settingsTitle.setFontSize(48);
 | 
			
		||||
        settingsTitle.setColor(ColorRGBA.White);
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.White);
 | 
			
		||||
 | 
			
		||||
        // Field details
 | 
			
		||||
        Container propertyValuesContainer = foodFieldContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Wenn man Besitzer des", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label(field.getName()+" ist, so ist die", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete 40-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("„Wenn man Besitzer beider", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Restaurants ist, so ist die", new ElementId("label-Text")));
 | 
			
		||||
        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("", new ElementId("label-Text"))); // Empty line
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Miete: 40x Würfel-Augen,", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„wenn Besitzer eines ", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Restaurants.", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Miete: 100x Würfel-Augen, ", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„wenn Besitzer eines ", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Restaurants.", 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.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")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
 | 
			
		||||
        // Buy button
 | 
			
		||||
        Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new BuyPropertyResponse());
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Adjust sizes and center elements
 | 
			
		||||
        backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        foodFieldContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
                (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach components to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(foodFieldContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(foodFieldContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(foodFieldContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,15 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
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.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
@@ -14,17 +17,17 @@ import pp.monopoly.model.fields.GateField;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the gate field information. */
 | 
			
		||||
    private final Container gateFieldContainer;
 | 
			
		||||
    private Container gateFieldContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a GateFieldCard popup displaying details about a gate field.
 | 
			
		||||
@@ -35,89 +38,101 @@ public class GateFieldCard extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        // Generate the corresponding field
 | 
			
		||||
        int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
 | 
			
		||||
        GateField field = (GateField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
        // Initialize UI elements
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createGateFieldContainer(field);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // 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();
 | 
			
		||||
        //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)));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des gateFieldContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe
 | 
			
		||||
        // Title
 | 
			
		||||
        Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Preise werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        // Field details
 | 
			
		||||
        Container propertyValuesContainer = gateFieldContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete: 250 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("2 Bahnhof besitzt: 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("3 Bahnhof besitzt: 1000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("4 Bahnhof besitzt: 2000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 2 Tore", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("besitzt: 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 3 Tore", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("besitzt: 1000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 4 Tore", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("besitzt: 2000 EUR", 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.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")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
 | 
			
		||||
        // Buy button
 | 
			
		||||
        Button buyButton = gateFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new BuyPropertyResponse());
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        // Adjust sizes and center elements
 | 
			
		||||
        backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        gateFieldContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach components to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(gateFieldContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(gateFieldContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(gateFieldContainer); // Remove main container
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); // Remove background container
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -11,31 +11,33 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the Gulag warning message. */
 | 
			
		||||
    private final Container gulagContainer;
 | 
			
		||||
    private Container gulagContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Gulag popup, displaying a warning when a player lands on the "Wache" field.
 | 
			
		||||
     * Constructs the Gulag popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
@@ -43,90 +45,88 @@ public class Gulag extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Initialize UI elements
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createGulagContainer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the semi-transparent overlay background for the popup.
 | 
			
		||||
     */
 | 
			
		||||
    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.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main container for the Gulag warning message.
 | 
			
		||||
     */
 | 
			
		||||
    private void createGulagContainer() {
 | 
			
		||||
        gulagContainer = new Container();
 | 
			
		||||
        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
 | 
			
		||||
        backgroundContainer.setPreferredSize(gulagContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = gulagContainer.addChild(new Label("Du kommst ins Gulag!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = gulagContainer.addChild(new Label("Du kommst ins Gulag!", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
        // Confirmation Button
 | 
			
		||||
        Button confirmButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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(
 | 
			
		||||
            (app.getCamera().getWidth() - gulagContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - gulagContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gulagContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
            (app.getCamera().getWidth() - gulagContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
            7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach components to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(gulagContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(gulagContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(gulagContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the popup.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -7,130 +7,147 @@ 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.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.NotificationAnswer;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * GulagInfo is a popup that provides options for a player who is stuck in the "Gulag" (jail) field.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * This dialog offers multiple actions, including paying a bribe, using a "Get Out of Jail" card, or waiting.
 | 
			
		||||
 * </p>
 | 
			
		||||
 */
 | 
			
		||||
public class GulagInfo extends Dialog {
 | 
			
		||||
public class GulagInfo extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the Gulag information dialog. */
 | 
			
		||||
    private final Container gulagInfoContainer;
 | 
			
		||||
    private Container gulagInfoContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a styled border around the dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    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 app  the Monopoly application instance
 | 
			
		||||
     * @param trys the number of failed attempts to roll doubles for release
 | 
			
		||||
     */
 | 
			
		||||
    public GulagInfo(MonopolyApp app, int trys) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        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.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // 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.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
 | 
			
		||||
        backgroundContainer.setPreferredSize(gulagInfoContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label title = gulagInfoContainer.addChild(new Label( "Gulag", new ElementId("warning-title")));
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = gulagInfoContainer.addChild(new Label("Gulag", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Werte werden dem Handel entnommen (Iwas auch immer da dann ist)
 | 
			
		||||
        Container propertyValuesContainer = gulagInfoContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Du sitzt im Gefänginis und kommst nicht raus ...", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Es sei denn, du ...", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- bestichst die Wache mit 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- löst eine Gulag-Frei-Karte ein", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- wartest 3 Runden und bezahlst dann", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- oder du würfelst einen Pasch", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        // Text Description
 | 
			
		||||
        Container textContainer = gulagInfoContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("„Du sitzt im Gefängnis und kommst nicht raus ...", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Es sei denn, du ...", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("- bestichst die Wache mit 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("- löst eine Gulag-Frei-Karte ein", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("- wartest 3 Runden und bezahlst dann", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("- oder du würfelst einen Pasch", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.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")));
 | 
			
		||||
        payButton.setFontSize(32);
 | 
			
		||||
        payButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        payButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new NotificationAnswer("PayJail"));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Ereigniskarte-Button
 | 
			
		||||
        Button eventCardButton = gulagInfoContainer.addChild(new Button("Ereigniskarte nutzen", new ElementId("button")));
 | 
			
		||||
 | 
			
		||||
        // Use Jail-Free Card Button
 | 
			
		||||
        Button eventCardButton = gulagInfoContainer.addChild(new Button("Ereigniskarte nutzen", new ElementId("button-toolbar2")));
 | 
			
		||||
        eventCardButton.setFontSize(32);
 | 
			
		||||
        eventCardButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        eventCardButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new NotificationAnswer("UseJailCard"));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Schließen-Button
 | 
			
		||||
 | 
			
		||||
        // Close Button
 | 
			
		||||
        Button closeButton = gulagInfoContainer.addChild(new Button("Schließen", new ElementId("button")));
 | 
			
		||||
        closeButton.setFontSize(32);
 | 
			
		||||
        closeButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        closeButton.addClickCommands(s -> ifTopDialog(this::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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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(
 | 
			
		||||
            (app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
            (app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
            7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if(app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getNumJailCard() == 0) {
 | 
			
		||||
            eventCardButton.setEnabled(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(trys == 3) {
 | 
			
		||||
            closeButton.setEnabled(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Attach containers to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(gulagInfoContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the GulagInfo popup and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(gulagInfoContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(gulagInfoContainer); // Remove dialog
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); // Remove background
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the GulagInfo dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,9 @@ 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 {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
@@ -123,9 +123,6 @@ public class LooserPopUp extends Dialog {
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the LooserPopUp dialog and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(LooserContainer);  // Entferne das Menü
 | 
			
		||||
@@ -134,9 +131,6 @@ public class LooserPopUp extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,19 +12,14 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * NoMoneyWarning is a warning popup that appears when a player tries to perform
 | 
			
		||||
 * an action they cannot afford due to insufficient funds, such as attempting
 | 
			
		||||
 * to purchase a property or building.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * This dialog notifies the player of their lack of funds and provides a single
 | 
			
		||||
 * confirmation button to close the dialog.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
@@ -46,66 +41,15 @@ public class NoMoneyWarning extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        backgroundContainer = createBackgroundContainer();
 | 
			
		||||
        noMoneyWarningContainer = createNoMoneyWarningContainer();
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        noMoneyWarningContainer = new Container();
 | 
			
		||||
        noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Na, schon wieder Pleite?", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(38);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast nicht genug Geld, um dieses Gebäude zu kaufen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Bestätigen-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);
 | 
			
		||||
        adjustPaddingAndCenter();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background for the dialog.
 | 
			
		||||
     * Creates the semi-transparent overlay background.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The geometry representing the overlay background.
 | 
			
		||||
     */
 | 
			
		||||
@@ -113,7 +57,7 @@ public class NoMoneyWarning extends Dialog {
 | 
			
		||||
        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.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
@@ -121,21 +65,85 @@ 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.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     * 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
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,115 +12,95 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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>
 | 
			
		||||
 * ReceivedRent is a popup that informs a player about rent they have received.
 | 
			
		||||
 */
 | 
			
		||||
public class ReceivedRent extends Dialog {
 | 
			
		||||
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 final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the rent information and action. */
 | 
			
		||||
    private final Container rentContainer;
 | 
			
		||||
    private Container rentContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the rent popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Rent popup displaying the rent amount and recipient player.
 | 
			
		||||
     * Constructs the ReceivedRent popup displaying the rent amount and payer.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app        the Monopoly application instance
 | 
			
		||||
     * @param playerName the name of the player to whom the rent is owed
 | 
			
		||||
     * @param amount     the amount of rent to be paid
 | 
			
		||||
     * @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;
 | 
			
		||||
 | 
			
		||||
        // Create the overlay
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create and position the background container
 | 
			
		||||
        backgroundContainer = createBackgroundContainer();
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Create and position the rent container
 | 
			
		||||
        rentContainer = createRentContainer(playerName, amount);
 | 
			
		||||
        app.getGuiNode().attachChild(rentContainer);
 | 
			
		||||
 | 
			
		||||
        centerContainers();
 | 
			
		||||
        // Initialize GUI elements
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createRentContainer(playerName, amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the overlay geometry
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
    private void createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        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);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
        overlayBackground.setMaterial(material);
 | 
			
		||||
        overlayBackground.setLocalTranslation(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container with styling.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the styled background container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createBackgroundContainer() {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
        return container;
 | 
			
		||||
    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 to whom the rent is owed
 | 
			
		||||
     * @param playerName the name of the player who paid the rent
 | 
			
		||||
     * @param amount     the rent amount
 | 
			
		||||
     * @return the rent container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createRentContainer(String playerName, int amount) {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
    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 = container.addChild(new Label("Miete!", new ElementId("warning-title")));
 | 
			
		||||
        Label title = rentContainer.addChild(new Label("Miete!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Rent message
 | 
			
		||||
        Container textContainer = container.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label(playerName+ " zahlt dir " + amount + " EUR Miete",
 | 
			
		||||
        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(container.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
        textContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
 | 
			
		||||
        // Payment button
 | 
			
		||||
        Button payButton = container.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        payButton.setFontSize(32);
 | 
			
		||||
        payButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
                app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
                close();
 | 
			
		||||
        // 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();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -145,20 +125,22 @@ public class ReceivedRent extends Dialog {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(rentContainer);
 | 
			
		||||
        centerContainers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(rentContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        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();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,19 +12,16 @@ 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.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * RejectTrade is a popup that appears when a trade proposal is rejected by another player
 | 
			
		||||
 * in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Displays a message indicating that the proposed trade has been declined, along with
 | 
			
		||||
 * details of the involved players and provides an option to close the popup.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
@@ -32,12 +29,11 @@ public class RejectTrade extends Dialog {
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the rejection message content. */
 | 
			
		||||
    private final Container noMoneyWarningContainer;
 | 
			
		||||
    private final Container rejectTradeContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the RejectTrade popup displaying the rejection of a trade proposal.
 | 
			
		||||
     *
 | 
			
		||||
@@ -48,68 +44,15 @@ public class RejectTrade extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        backgroundContainer = createBackgroundContainer();
 | 
			
		||||
        rejectTradeContainer = createRejectTradeContainer(msg);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        noMoneyWarningContainer = new Container();
 | 
			
		||||
        noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Handel abgelehnt!", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast Spieler"+ " " + msg.getTradeHandler().getReceiver().getName() + " " + "einen Handel vorgeschlagen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Der Handel wurde abgelehnt", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
        adjustPaddingAndCenter();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     * Creates the semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
@@ -117,7 +60,7 @@ public class RejectTrade extends Dialog {
 | 
			
		||||
        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.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
@@ -125,21 +68,89 @@ public class RejectTrade 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.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape key action by closing the popup.
 | 
			
		||||
     * 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
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(rejectTradeContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(rejectTradeContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,65 +12,58 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 {
 | 
			
		||||
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the rent information and action. */
 | 
			
		||||
    private final Container rentContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the rent popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Rent popup displaying the rent amount and recipient player.
 | 
			
		||||
     * Constructs the Rent popup displaying the rent amount and recipient player's name.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app        the Monopoly application instance
 | 
			
		||||
     * @param playerName the name of the player to whom the rent is owed
 | 
			
		||||
     * @param amount     the amount of rent to be paid
 | 
			
		||||
     * @param playerName the name of the player to pay rent to
 | 
			
		||||
     * @param amount     the amount of rent to pay
 | 
			
		||||
     */
 | 
			
		||||
    public Rent(MonopolyApp app, String playerName, int amount) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the overlay
 | 
			
		||||
        // Create the overlay and containers
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create and position the background container
 | 
			
		||||
        backgroundContainer = createBackgroundContainer();
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Create and position the rent container
 | 
			
		||||
        rentContainer = createRentContainer(playerName, amount);
 | 
			
		||||
        app.getGuiNode().attachChild(rentContainer);
 | 
			
		||||
 | 
			
		||||
        // Center containers (positioning logic only, no GUI attachment)
 | 
			
		||||
        centerContainers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background.
 | 
			
		||||
     * Creates the semi-transparent overlay background for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the overlay geometry
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f));
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
@@ -78,21 +71,21 @@ public class Rent extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container with styling.
 | 
			
		||||
     * Creates the background container for the rent popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the styled background container
 | 
			
		||||
     * @return the background container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createBackgroundContainer() {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main rent container with title, text, and button.
 | 
			
		||||
     * Creates the main container for the rent popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerName the name of the player to whom the rent is owed
 | 
			
		||||
     * @param amount     the rent amount
 | 
			
		||||
     * @param playerName the name of the player to pay rent to
 | 
			
		||||
     * @param amount     the amount of rent to pay
 | 
			
		||||
     * @return the rent container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createRentContainer(String playerName, int amount) {
 | 
			
		||||
@@ -100,25 +93,21 @@ public class Rent extends Dialog {
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = container.addChild(new Label("Miete!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Rent message
 | 
			
		||||
        Container textContainer = container.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du musst " + amount  + " EUR Miete an " + playerName + " zahlen",
 | 
			
		||||
        textContainer.addChild(new Label("Du musst " + amount + " EUR Miete an " + playerName + " zahlen",
 | 
			
		||||
                new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
 | 
			
		||||
        // Payment button
 | 
			
		||||
        Button payButton = container.addChild(new Button("Überweisen", new ElementId("button")));
 | 
			
		||||
        payButton.setFontSize(32);
 | 
			
		||||
        payButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
                app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
                close();
 | 
			
		||||
 | 
			
		||||
        payButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return container;
 | 
			
		||||
@@ -130,14 +119,12 @@ public class Rent extends Dialog {
 | 
			
		||||
    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,
 | 
			
		||||
@@ -146,22 +133,25 @@ public class Rent extends Dialog {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    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
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(rentContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
@@ -30,10 +29,10 @@ import java.util.stream.Collectors;
 | 
			
		||||
/**
 | 
			
		||||
 * 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 {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
@@ -45,8 +44,8 @@ public class RepayMortage extends Dialog {
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** Text field to display selected properties. */
 | 
			
		||||
    private TextField selectionDisplay;
 | 
			
		||||
    /** Label to display selected properties. */
 | 
			
		||||
    private Label selectionDisplay;
 | 
			
		||||
 | 
			
		||||
    /** Reference to track property selections in the dropdown menu. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
@@ -82,7 +81,7 @@ public class RepayMortage extends Dialog {
 | 
			
		||||
        backgroundContainer.setPreferredSize(repayMortageContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // 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.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
@@ -97,7 +96,7 @@ public class RepayMortage extends Dialog {
 | 
			
		||||
        upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
 | 
			
		||||
        middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
        middleContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        middleContainer.addChild(createPropertyDropdown());
 | 
			
		||||
 | 
			
		||||
@@ -149,7 +148,7 @@ public class RepayMortage extends Dialog {
 | 
			
		||||
    private Container createPropertyDropdown() {
 | 
			
		||||
        Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> propertyOptions = new VersionedList<>();
 | 
			
		||||
        List<PropertyField> playerProperties = getPlayerProperties();
 | 
			
		||||
@@ -166,8 +165,9 @@ public class RepayMortage extends Dialog {
 | 
			
		||||
        selectionRef = propertySelector.getSelectionModel().createReference();
 | 
			
		||||
 | 
			
		||||
        // 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.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
 | 
			
		||||
 | 
			
		||||
        // Set initial selection
 | 
			
		||||
@@ -231,9 +231,6 @@ public class RepayMortage extends Dialog {
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(repayMortageContainer);  // Entferne das Menü
 | 
			
		||||
@@ -241,9 +238,6 @@ public class RepayMortage extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
@@ -30,10 +29,10 @@ import java.util.stream.Collectors;
 | 
			
		||||
/**
 | 
			
		||||
 * 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 {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
@@ -45,8 +44,8 @@ public class SellHouse extends Dialog {
 | 
			
		||||
    /** Background container providing a styled border around the main dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** Text field to display selected properties. */
 | 
			
		||||
    private TextField selectionDisplay;
 | 
			
		||||
    /** Label to display selected properties. */
 | 
			
		||||
    private Label selectionDisplay;
 | 
			
		||||
 | 
			
		||||
    /** Reference to track selection changes in the property selector. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
@@ -82,11 +81,11 @@ public class SellHouse extends Dialog {
 | 
			
		||||
        backgroundContainer.setPreferredSize(sellhouseContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // 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.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        //Unterteilund des sellHouseContainer in drei "Untercontainer"
 | 
			
		||||
        //Unterteilung des sellHouseContainer in drei "Untercontainer"
 | 
			
		||||
        Container upContainer = sellhouseContainer.addChild(new Container());
 | 
			
		||||
        Container middleContainer = sellhouseContainer.addChild(new Container());
 | 
			
		||||
        Container downContainer = sellhouseContainer.addChild(new Container());
 | 
			
		||||
@@ -119,13 +118,7 @@ public class SellHouse extends Dialog {
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            AlterProperty msg = new AlterProperty("SellHouse");
 | 
			
		||||
            for (String string : selectedProperties) {
 | 
			
		||||
                System.out.println(string);
 | 
			
		||||
            }
 | 
			
		||||
            msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
 | 
			
		||||
            for (Integer integer : msg.getProperties()) {
 | 
			
		||||
                System.out.println("ID des verkaufs: "+integer);
 | 
			
		||||
            }
 | 
			
		||||
            app.getGameLogic().send(msg);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
@@ -155,7 +148,7 @@ public class SellHouse extends Dialog {
 | 
			
		||||
    private Container createPropertyDropdown() {
 | 
			
		||||
        Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> propertyOptions = new VersionedList<>();
 | 
			
		||||
        List<BuildingProperty> playerProperties = getPlayerProperties();
 | 
			
		||||
@@ -172,8 +165,9 @@ public class SellHouse extends Dialog {
 | 
			
		||||
        selectionRef = propertySelector.getSelectionModel().createReference();
 | 
			
		||||
 | 
			
		||||
        // Initialize the selection display here
 | 
			
		||||
        selectionDisplay = new TextField(""); // Create TextField for displaying selections
 | 
			
		||||
        selectionDisplay = new Label("");
 | 
			
		||||
        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
 | 
			
		||||
        
 | 
			
		||||
        // Set initial selection
 | 
			
		||||
@@ -236,9 +230,6 @@ public class SellHouse extends Dialog {
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the dialog and removes GUI elements from the screen.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(sellhouseContainer);  // Entferne das Menü
 | 
			
		||||
@@ -246,9 +237,6 @@ public class SellHouse extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
@@ -46,8 +45,8 @@ public class TakeMortage extends Dialog {
 | 
			
		||||
    /** Background container providing a styled border around the main dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** Text field to display selected properties. */
 | 
			
		||||
    private TextField selectionDisplay;
 | 
			
		||||
    /** Label to display selected properties. */
 | 
			
		||||
    private Label selectionDisplay;
 | 
			
		||||
 | 
			
		||||
    /** Reference to track selection changes in the property selector. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
@@ -83,7 +82,7 @@ public class TakeMortage extends Dialog {
 | 
			
		||||
        backgroundContainer.setPreferredSize(takeMortageContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // 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.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
@@ -150,7 +149,7 @@ public class TakeMortage extends Dialog {
 | 
			
		||||
    private Container createPropertyDropdown() {
 | 
			
		||||
        Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> propertyOptions = new VersionedList<>();
 | 
			
		||||
        List<PropertyField> playerProperties = getPlayerProperties();
 | 
			
		||||
@@ -172,8 +171,9 @@ public class TakeMortage extends Dialog {
 | 
			
		||||
        selectionRef = propertySelector.getSelectionModel().createReference();
 | 
			
		||||
 | 
			
		||||
        // 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.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
 | 
			
		||||
 | 
			
		||||
        // Set initial selection
 | 
			
		||||
@@ -240,9 +240,6 @@ public class TakeMortage extends Dialog {
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the dialog and removes GUI elements from the screen.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(takeMortageContainer);  // Entferne das Menü
 | 
			
		||||
@@ -250,9 +247,6 @@ public class TakeMortage extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,9 @@ 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 {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
@@ -121,9 +121,6 @@ public class WinnerPopUp extends Dialog {
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the WinnerPopUp dialog and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(WinnerContainer);  // Entferne das Menü
 | 
			
		||||
@@ -132,9 +129,6 @@ public class WinnerPopUp extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
| 
		 After Width: | Height: | Size: 8.0 KiB  | 
| 
		 After Width: | Height: | Size: 121 KiB  | 
| 
		 After Width: | Height: | Size: 114 KiB  | 
| 
		 After Width: | Height: | Size: 304 KiB  | 
| 
		 After Width: | Height: | Size: 473 KiB  | 
| 
		 After Width: | Height: | Size: 80 KiB  | 
| 
		 After Width: | Height: | Size: 58 KiB  | 
| 
		 After Width: | Height: | Size: 58 KiB  | 
| 
		 After Width: | Height: | Size: 94 KiB  | 
| 
		 After Width: | Height: | Size: 136 KiB  | 
| 
		 After Width: | Height: | Size: 136 KiB  | 
| 
		 After Width: | Height: | Size: 72 KiB  | 
| 
		 After Width: | Height: | Size: 25 KiB  | 
| 
		 After Width: | Height: | Size: 17 KiB  | 
| 
		 After Width: | Height: | Size: 39 KiB  | 
| 
		 After Width: | Height: | Size: 26 KiB  | 
| 
		 After Width: | Height: | Size: 17 KiB  | 
| 
		 After Width: | Height: | Size: 46 KiB  | 
| 
		 After Width: | Height: | Size: 27 KiB  | 
| 
		 After Width: | Height: | Size: 18 KiB  | 
| 
		 After Width: | Height: | Size: 49 KiB  | 
| 
		 After Width: | Height: | Size: 26 KiB  | 
| 
		 After Width: | Height: | Size: 18 KiB  | 
| 
		 After Width: | Height: | Size: 46 KiB  | 
| 
		 After Width: | Height: | Size: 24 KiB  | 
| 
		 After Width: | Height: | Size: 16 KiB  | 
| 
		 After Width: | Height: | Size: 37 KiB  | 
| 
		 After Width: | Height: | Size: 27 KiB  | 
| 
		 After Width: | Height: | Size: 17 KiB  | 
| 
		 After Width: | Height: | Size: 48 KiB  | 
| 
		 After Width: | Height: | Size: 195 KiB  | 
| 
		 After Width: | Height: | Size: 205 KiB  | 
| 
		 After Width: | Height: | Size: 170 KiB  | 
| 
		 After Width: | Height: | Size: 193 KiB  | 
| 
		 After Width: | Height: | Size: 198 KiB  | 
| 
		 After Width: | Height: | Size: 201 KiB  | 
| 
		 Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.9 MiB  | 
| 
		 Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 132 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Pictures/kontobg.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 195 KiB  | 
| 
		 After Width: | Height: | Size: 588 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Textures/Bot.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 707 KiB  | 
| 
		 Before Width: | Height: | Size: 18 MiB After Width: | Height: | Size: 14 MiB  | 
| 
		 After Width: | Height: | Size: 215 KiB  | 
| 
		 After Width: | Height: | Size: 60 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Textures/Top.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 478 KiB  |