Compare commits
	
		
			382 Commits
		
	
	
		
			logic
			...
			0acb23ab8b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					0acb23ab8b | ||
| 
						 | 
					831974cb63 | ||
| 
						 | 
					031ac52670 | ||
| 
						 | 
					14ceb9dc67 | ||
| 
						 | 
					aa86c25e7c | ||
| 
						 | 
					cb0788e44c | ||
| 
						 | 
					9e88353bd5 | ||
| 
						 | 
					6db96f0a1d | ||
| 
						 | 
					b01bb3cf7b | ||
| 
						 | 
					95b9da9377 | ||
| 
						 | 
					957bf8ffcc | ||
| 
						 | 
					446ecfd4b5 | ||
| 
						 | 
					821c9ec3fb | ||
| 
						 | 
					531a3e263c | ||
| 
						 | 
					4917208818 | ||
| 
						 | 
					e81cdf3b40 | ||
| 
						 | 
					bffe614b54 | ||
| 
						 | 
					69ad19757d | ||
| 
						 | 
					a4c0afe277 | ||
| 
						 | 
					cc157a3cf3 | ||
| 
						 | 
					ff2b64d476 | ||
| 
						 | 
					459a54ac5d | ||
| 
						 | 
					a50821f2e6 | ||
| 
						 | 
					72e0fc7cbd | ||
| 
						 | 
					3260d06bc8 | ||
| 
						 | 
					e07db0129f | ||
| 
						 | 
					3bfa7ff69f | ||
| 
						 | 
					160fff88ea | ||
| 
						 | 
					7a658cb3d6 | ||
| 
						 | 
					25361933d7 | ||
| 
						 | 
					4ac02a1a7b | ||
| 
						 | 
					6f15f12b49 | ||
| 
						 | 
					9e50c1afe2 | ||
| 
						 | 
					3a43ea10d9 | ||
| 
						 | 
					3539b1cf23 | ||
| 
						 | 
					d0ba0d011f | ||
| 
						 | 
					1f07affbef | ||
| 
						 | 
					c83f7de30c | ||
| 
						 | 
					acb5c75379 | ||
| 
						 | 
					a73384c436 | ||
| 
						 | 
					96542fa42b | ||
| 
						 | 
					0d885203a7 | ||
| 
						 | 
					e08654bb20 | ||
| 
						 | 
					486c0a9810 | ||
| 
						 | 
					0b71c2cb96 | ||
| 
						 | 
					737576e0ca | ||
| 
						 | 
					db7a99dc59 | ||
| 
						 | 
					4b48229329 | ||
| 
						 | 
					1a41b548c4 | ||
| 
						 | 
					7f58558da4 | ||
| 
						 | 
					1503e18585 | ||
| 
						 | 
					94155d2816 | ||
| 
						 | 
					ec42cc2c07 | ||
| 
						 | 
					af79e39492 | ||
| 
						 | 
					0698c29410 | ||
| 
						 | 
					08c1854885 | ||
| 
						 | 
					ff39402d82 | ||
| 
						 | 
					4e375131d1 | ||
| 
						 | 
					ac9ced2cf4 | ||
| 
						 | 
					e93791e6e8 | ||
| 
						 | 
					fa554cbffc | ||
| 
						 | 
					f317d7723e | ||
| 
						 | 
					07fd92c9b2 | ||
| 
						 | 
					91fea83f26 | ||
| 
						 | 
					471f703634 | ||
| 
						 | 
					065049f663 | ||
| 
						 | 
					580d81a621 | ||
| 
						 | 
					7acf448c0c | ||
| 
						 | 
					bcf4956d2d | ||
| 
						 | 
					13754c843a | ||
| 
						 | 
					4743a6882c | ||
| 
						 | 
					2dbc727728 | ||
| 
						 | 
					560bedc80b | ||
| 
						 | 
					7ace959f1f | ||
| 
						 | 
					95dc7b07e2 | ||
| 
						 | 
					fa20a6cb2a | ||
| 
						 | 
					36b308e616 | ||
| 
						 | 
					b912835edb | ||
| 
						 | 
					add5dab611 | ||
| 
						 | 
					5172766216 | ||
| 
						 | 
					fcb55e52fc | ||
| 
						 | 
					411f7ea25b | ||
| 
						 | 
					e05ad71fff | ||
| 
						 | 
					d08a172227 | ||
| 
						 | 
					4fff8394d9 | ||
| 
						 | 
					5bb438c221 | ||
| 
						 | 
					a753017fcd | ||
| 
						 | 
					5522be228b | ||
| 
						 | 
					3b729c9a04 | ||
| 
						 | 
					eda2fcd327 | ||
| 
						 | 
					09e12fc610 | ||
| 
						 | 
					93152f4073 | ||
| 
						 | 
					17a1d3fbbb | ||
| 
						 | 
					a0e2b6e8e2 | ||
| 
						 | 
					79a08a0c9e | ||
| 
						 | 
					a24d6fd4b6 | ||
| 
						 | 
					f220aeb78c | ||
| 
						 | 
					85e0c68a36 | ||
| 
						 | 
					113e1b7aa5 | ||
| 
						 | 
					cfcc232432 | ||
| 
						 | 
					29e9b54cc4 | ||
| 
						 | 
					0c90d1f185 | ||
| 
						 | 
					b5090ea179 | ||
| 
						 | 
					cfbf20f745 | ||
| 
						 | 
					dd002746aa | ||
| 
						 | 
					11f4560745 | ||
| 
						 | 
					b702e3a14d | ||
| 
						 | 
					3b2cfad774 | ||
| 
						 | 
					9164dc6893 | ||
| 
						 | 
					d3cf36ecb1 | ||
| 
						 | 
					7d0a0123e0 | ||
| 
						 | 
					2f025e2e1a | ||
| 
						 | 
					9bf9e8406b | ||
| 
						 | 
					6bd1ed6e3a | ||
| 
						 | 
					0f6205fbc7 | ||
| 
						 | 
					f2a6888fb2 | ||
| 
						 | 
					5143e21ba6 | ||
| 
						 | 
					26dc24a1f4 | ||
| 
						 | 
					350c157493 | ||
| 
						 | 
					51b879a7c8 | ||
| 
						 | 
					528126aa29 | ||
| 
						 | 
					73bfafa7f7 | ||
| 
						 | 
					686a12e465 | ||
| 
						 | 
					358beacc65 | ||
| 
						 | 
					69db0aa29b | ||
| 
						 | 
					20f44ad2d4 | ||
| 
						 | 
					d73c5e0904 | ||
| 
						 | 
					f322e9bd8f | ||
| 
						 | 
					b8e1645eb8 | ||
| 
						 | 
					73a908cd71 | ||
| 
						 | 
					a6b7ea4ce8 | ||
| 
						 | 
					4af08ffffd | ||
| 
						 | 
					dc66fd7384 | ||
| 
						 | 
					16ff61264b | ||
| 
						 | 
					f3ec17b0b1 | ||
| 
						 | 
					1c31915627 | ||
| 
						 | 
					79c96677bd | ||
| 
						 | 
					54118071cb | ||
| 
						 | 
					2e28b54936 | ||
| 
						 | 
					f333e2d2c0 | ||
| 
						 | 
					b89d40b39f | ||
| 
						 | 
					488ae154cf | ||
| 
						 | 
					c1e501c271 | ||
| 
						 | 
					89d5185c91 | ||
| 
						 | 
					f4bf38bca1 | ||
| 
						 | 
					b87b3f054b | ||
| 
						 | 
					f6137b8b68 | ||
| 
						 | 
					87309235bd | ||
| 
						 | 
					d37017bfa0 | ||
| 
						 | 
					5d6440bd50 | ||
| 
						 | 
					a70295f1ff | ||
| 
						 | 
					b681b13468 | ||
| 
						 | 
					2c536f32cf | ||
| 
						 | 
					991fe5280f | ||
| 
						 | 
					174fe5cfb3 | ||
| 
						 | 
					119284f256 | ||
| 
						 | 
					05680af726 | ||
| 
						 | 
					fba82f670b | ||
| 
						 | 
					afa2ebd004 | ||
| 
						 | 
					f0eeff3493 | ||
| 
						 | 
					44d64c4e0f | ||
| 
						 | 
					86ece3b70d | ||
| 
						 | 
					6cdad71693 | ||
| 
						 | 
					cf6d5ea22e | ||
| 
						 | 
					ecf227daa6 | ||
| 
						 | 
					4b5a156865 | ||
| 
						 | 
					cfae369fd3 | ||
| 
						 | 
					b05eabbbf8 | ||
| 
						 | 
					fd178eee43 | ||
| 
						 | 
					aef2ef34fb | ||
| 
						 | 
					fcbffa1189 | ||
| 
						 | 
					0d8240381e | ||
| 
						 | 
					77da6679ef | ||
| 
						 | 
					5845254caa | ||
| 
						 | 
					5d92d7cfcc | ||
| 
						 | 
					67f6649242 | ||
| 
						 | 
					1438ae5e4f | ||
| 
						 | 
					01c351e64b | ||
| 
						 | 
					b0c21dfcb8 | ||
| 
						 | 
					f4cddbc87f | ||
| 
						 | 
					cfce176c82 | ||
| 
						 | 
					782b1a10c3 | ||
| 
						 | 
					2d9cd0e4e1 | ||
| 
						 | 
					908ba09e2a | ||
| 
						 | 
					4a84ef4b3c | ||
| 
						 | 
					f3353327dd | ||
| 
						 | 
					316433f592 | ||
| 
						 | 
					1ccdea0c87 | ||
| 
						 | 
					7d9af0c4c7 | ||
| 
						 | 
					a1247cdae5 | ||
| 
						 | 
					5696192cce | ||
| 
						 | 
					91826b730f | ||
| 
						 | 
					48b1cf817a | ||
| 
						 | 
					94ba9f0af2 | ||
| 
						 | 
					333f27a016 | ||
| 
						 | 
					b67379a6c3 | ||
| 
						 | 
					1e6188cf24 | ||
| 
						 | 
					12e859edd5 | ||
| 
						 | 
					e000dcfc51 | ||
| 
						 | 
					e7a06159bb | ||
| 
						 | 
					c900b6384d | ||
| 
						 | 
					970a0ae254 | ||
| 
						 | 
					5e0ac0abc7 | ||
| 
						 | 
					bcd6711965 | ||
| 
						 | 
					bb63a4df9f | ||
| 
						 | 
					b4d7349583 | ||
| 
						 | 
					fed8a3fd2d | ||
| 
						 | 
					bc6e7174ec | ||
| 
						 | 
					075f98883a | ||
| 
						 | 
					c9df3a6176 | ||
| 
						 | 
					b2d2a79b00 | ||
| 
						 | 
					26d8283930 | ||
| 
						 | 
					4079c0a32c | ||
| 
						 | 
					6d72a94fe4 | ||
| 
						 | 
					227a7a027f | ||
| 
						 | 
					9e595b92ba | ||
| 
						 | 
					c346058631 | ||
| 
						 | 
					f2678ea33d | ||
| 
						 | 
					45a43d6998 | ||
| 
						 | 
					cb9888af7a | ||
| 
						 | 
					93b183254f | ||
| 
						 | 
					e92b305a56 | ||
| 
						 | 
					5b0628da15 | ||
| 
						 | 
					8d087a8e84 | ||
| 
						 | 
					1715926c1c | ||
| 
						 | 
					c8b69efca2 | ||
| 
						 | 
					7f6011720c | ||
| 
						 | 
					bdc5f0269f | ||
| 
						 | 
					a6054e825e | ||
| 
						 | 
					156e76fe0a | ||
| 
						 | 
					89587a4c78 | ||
| 
						 | 
					29cc73e83b | ||
| 
						 | 
					e56cdb1dcb | ||
| 
						 | 
					9107a08011 | ||
| 
						 | 
					0242587a5f | ||
| 
						 | 
					3ce27023c2 | ||
| 
						 | 
					174958c6b1 | ||
| 
						 | 
					c71e8b1e8e | ||
| 
						 | 
					ada067a2a0 | ||
| 
						 | 
					f4c4f6bc93 | ||
| 
						 | 
					6eeb6fd209 | ||
| 
						 | 
					efba3c496a | ||
| 
						 | 
					27a0ab52e6 | ||
| 
						 | 
					d6ce859fcd | ||
| 
						 | 
					e5f69c9536 | ||
| 
						 | 
					d8a2225038 | ||
| 
						 | 
					7b91a679f5 | ||
| 
						 | 
					840658b590 | ||
| 
						 | 
					c5e7ef855e | ||
| 
						 | 
					170227c97f | ||
| 
						 | 
					379803278b | ||
| 
						 | 
					3956d8efa7 | ||
| 
						 | 
					269aceaf1a | ||
| 
						 | 
					41127565fc | ||
| 
						 | 
					0e405d2f90 | ||
| 
						 | 
					f67810b288 | ||
| 
						 | 
					4095d9e79d | ||
| 
						 | 
					547a4c2353 | ||
| 
						 | 
					9120e4d53c | ||
| 
						 | 
					1a62b76104 | ||
| 
						 | 
					cc7f277bef | ||
| 
						 | 
					274df8dfd1 | ||
| 
						 | 
					0c2b266f5e | ||
| 
						 | 
					16b4dbae18 | ||
| 
						 | 
					88409dcc99 | ||
| 
						 | 
					5cacff39b7 | ||
| 
						 | 
					093723a9d0 | ||
| 
						 | 
					dfdbcdc9f3 | ||
| 
						 | 
					bd725e2dc4 | ||
| 
						 | 
					dd9d9144dd | ||
| 
						 | 
					1a429e4bb6 | ||
| 
						 | 
					ad6fb5e926 | ||
| 
						 | 
					72cb7049ba | ||
| 
						 | 
					2e42f3afac | ||
| 
						 | 
					8474c9f5bc | ||
| 
						 | 
					b7ed03f7e8 | ||
| 
						 | 
					a44b6b5e4c | ||
| 
						 | 
					5268f75e17 | ||
| 
						 | 
					687d1621fc | ||
| 
						 | 
					a6944aa6e3 | ||
| 
						 | 
					b8365c76a1 | ||
| 
						 | 
					19216cc174 | ||
| 
						 | 
					c6a23b9b8e | ||
| 
						 | 
					c0f42fb1eb | ||
| 
						 | 
					160873e2cc | ||
| 
						 | 
					8df859bbef | ||
| 
						 | 
					e30d10a85d | ||
| 
						 | 
					bafc3f1db6 | ||
| 
						 | 
					03571fcf74 | ||
| 
						 | 
					e7a6802488 | ||
| 
						 | 
					a6e6b5e158 | ||
| 
						 | 
					74c3d925e6 | ||
| 
						 | 
					f67fa4d7f0 | ||
| 
						 | 
					225a8c0e08 | ||
| 
						 | 
					9a6ce27fe1 | ||
| 
						 | 
					437114704a | ||
| 
						 | 
					9b4cac4e56 | ||
| 
						 | 
					e780513b35 | ||
| 
						 | 
					d582c59a7d | ||
| 
						 | 
					7d2c85f617 | ||
| 
						 | 
					4a882bc4ac | ||
| 
						 | 
					3c4eac1fcd | ||
| 
						 | 
					75d5a15bdb | ||
| 
						 | 
					17f121f7d1 | ||
| 
						 | 
					a66c570b51 | ||
| 
						 | 
					e1e7f2eaf6 | ||
| 
						 | 
					46d2dce372 | ||
| 
						 | 
					c39f1f6d4c | ||
| 
						 | 
					738b04f2d9 | ||
| 
						 | 
					ecba1c3135 | ||
| 
						 | 
					748226f4ed | ||
| 
						 | 
					f658f53ba9 | ||
| 
						 | 
					4a8304ee4f | ||
| 
						 | 
					7fe9604338 | ||
| 
						 | 
					7f09a6dae8 | ||
| 
						 | 
					270129bc97 | ||
| 
						 | 
					62ec6f6bef | ||
| 
						 | 
					b24c14900c | ||
| 
						 | 
					44c55ce3a6 | ||
| 
						 | 
					895bea048c | ||
| 
						 | 
					885ab5bdc9 | ||
| 
						 | 
					c6355b2c09 | ||
| 
						 | 
					ada6bf3f24 | ||
| 
						 | 
					db471ac679 | ||
| 
						 | 
					84059c4085 | ||
| 
						 | 
					09b363f943 | ||
| 
						 | 
					fd347c7780 | ||
| 
						 | 
					b38a34efa5 | ||
| 
						 | 
					10e24cf30e | ||
| 
						 | 
					3369057afb | ||
| 
						 | 
					7ada56e215 | ||
| 
						 | 
					373b9e6d53 | ||
| 
						 | 
					3de31de9f7 | ||
| 
						 | 
					7252259ab3 | ||
| 
						 | 
					f33c673a05 | ||
| 
						 | 
					65a7958b66 | ||
| 
						 | 
					91e4df7478 | ||
| 
						 | 
					399606d9a0 | ||
| 
						 | 
					559afcaffd | ||
| 
						 | 
					15f5f91ddb | ||
| 
						 | 
					067a8063a5 | ||
| 
						 | 
					35e367ba24 | ||
| 
						 | 
					fe68d991fc | ||
| 
						 | 
					88dc633e8e | ||
| 
						 | 
					0b9cbb0f5f | ||
| 
						 | 
					c3a33b4402 | ||
| 
						 | 
					e12f00aad6 | ||
| 
						 | 
					47bac0185f | ||
| 
						 | 
					dafe1dab2a | ||
| 
						 | 
					8ba4ea2819 | ||
| 
						 | 
					f6f708fd5b | ||
| 
						 | 
					1203077aed | ||
| 
						 | 
					ddbf79c928 | ||
| 
						 | 
					aa47dd579f | ||
| 
						 | 
					cdce478d77 | ||
| 
						 | 
					f11f4a59f1 | ||
| 
						 | 
					d631e8df1e | ||
| 
						 | 
					af80d40700 | ||
| 
						 | 
					3a6f8a945a | ||
| 
						 | 
					bb9727d54a | ||
| 
						 | 
					7da8b3e545 | ||
| 
						 | 
					b6968df451 | ||
| 
						 | 
					aa986fb948 | ||
| 
						 | 
					6e63de6e99 | ||
| 
						 | 
					962ecd08fa | ||
| 
						 | 
					580a26b3ea | ||
| 
						 | 
					0cda6b5fa0 | ||
| 
						 | 
					cc8c3795b8 | ||
| 
						 | 
					3c21165efb | ||
| 
						 | 
					818fdf4670 | ||
| 
						 | 
					b7d679b492 | ||
| 
						 | 
					a42093df23 | ||
| 
						 | 
					6157db51da | ||
| 
						 | 
					843052989b | ||
| 
						 | 
					8e01fa3192 | ||
| 
						 | 
					e2126a7ea7 | ||
| 
						 | 
					0b46d14650 | ||
| 
						 | 
					9e28deedf7 | ||
| 
						 | 
					9c0172b413 | ||
| 
						 | 
					2933d022aa | ||
| 
						 | 
					bdefb7193e | ||
| 
						 | 
					69b68a6975 | 
@@ -1,6 +1,5 @@
 | 
			
		||||
// Styling of Lemur components
 | 
			
		||||
// For documentation, see:
 | 
			
		||||
// For documentation, see:
 | 
			
		||||
// https://github.com/jMonkeyEngine-Contributions/Lemur/wiki/Styling
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA
 | 
			
		||||
@@ -12,6 +11,7 @@ import com.simsilica.lemur.Command
 | 
			
		||||
import com.simsilica.lemur.HAlignment
 | 
			
		||||
import com.simsilica.lemur.Insets3f
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent
 | 
			
		||||
import com.simsilica.lemur.component.TbtQuadBackgroundComponent
 | 
			
		||||
 | 
			
		||||
def bgColor = color(1, 1, 1, 1)
 | 
			
		||||
def buttonEnabledColor = color(0, 0, 0, 1)
 | 
			
		||||
@@ -19,7 +19,7 @@ def buttonDisabledColor = color(0.8, 0.9, 1, 0.2)
 | 
			
		||||
def buttonBgColor = color(1, 1, 1, 1)
 | 
			
		||||
def sliderColor = color(0.6, 0.8, 0.8, 1)
 | 
			
		||||
def sliderBgColor = color(0.5, 0.75, 0.75, 1)
 | 
			
		||||
def gradientColor = color(1, 1, 1, 1)
 | 
			
		||||
def gradientColor = color(0.5, 0.75, 0.85, 0.5)
 | 
			
		||||
def tabbuttonEnabledColor = color(0.4, 0.45, 0.5, 1)
 | 
			
		||||
def solidWhiteBackground = new QuadBackgroundComponent(new ColorRGBA(1, 1, 1, 1))
 | 
			
		||||
def greyBackground = new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 1.0f));
 | 
			
		||||
@@ -30,8 +30,10 @@ def lightGrey = color(0.6, 0.6, 0.6, 1.0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gradient = TbtQuadBackgroundComponent.create(
 | 
			
		||||
        texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png", generateMips: false),
 | 
			
		||||
       1, 1, 1, 126, 126, 1f, false)
 | 
			
		||||
        texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png",
 | 
			
		||||
                generateMips: false),
 | 
			
		||||
        1, 1, 1, 126, 126,
 | 
			
		||||
        1f, false)
 | 
			
		||||
 | 
			
		||||
def doubleGradient = new QuadBackgroundComponent(gradientColor)
 | 
			
		||||
doubleGradient.texture = texture(name: "/com/simsilica/lemur/icons/double-gradient-128.png",
 | 
			
		||||
@@ -62,6 +64,16 @@ selector("label-Bold", "pp") {
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
selector("label-toolbar", "pp") {
 | 
			
		||||
    insets = new Insets3f(2, 2, 2, 2)
 | 
			
		||||
    font = font("Interface/Fonts/Metropolis/Metropolis-Bold-32.fnt")
 | 
			
		||||
    fontSize = 30
 | 
			
		||||
    color = new ColorRGBA(ColorRGBA.White)
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
selector("label-Text", "pp") {
 | 
			
		||||
    insets = new Insets3f(2, 2, 2, 2)
 | 
			
		||||
@@ -69,6 +81,19 @@ selector("label-Text", "pp") {
 | 
			
		||||
    color = buttonEnabledColor
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
selector("label-account", "pp") {
 | 
			
		||||
    insets = new Insets3f(2, 2, 2, 2)
 | 
			
		||||
    fontSize = 25
 | 
			
		||||
    color = new ColorRGBA(ColorRGBA.White)
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
selector("card-label", "pp") {
 | 
			
		||||
    insets = new Insets3f(2, 2, 2, 2)
 | 
			
		||||
    color = ColorRGBA.Black
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
selector("header", "pp") {
 | 
			
		||||
    font = font("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt")
 | 
			
		||||
    insets = new Insets3f(2, 2, 2, 2)
 | 
			
		||||
@@ -77,7 +102,6 @@ selector("header", "pp") {
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Container Stil
 | 
			
		||||
selector("container", "pp") {
 | 
			
		||||
    background = solidWhiteBackground.clone()
 | 
			
		||||
    background.setColor(bgColor)
 | 
			
		||||
@@ -90,8 +114,8 @@ selector("toolbar") {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
selector("slider", "pp") {
 | 
			
		||||
    insets = new Insets3f(5, 10, 5, 10) // Abstand
 | 
			
		||||
    background = new QuadBackgroundComponent(sliderBgColor)
 | 
			
		||||
    background = gradient.clone()
 | 
			
		||||
    background.setColor(bgColor)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def pressedCommand = new Command<Button>() {
 | 
			
		||||
@@ -112,6 +136,30 @@ def enabledCommand = new Command<Button>() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def repeatCommand = new Command<Button>() {
 | 
			
		||||
    private long startTime
 | 
			
		||||
    private long lastClick
 | 
			
		||||
 | 
			
		||||
    void execute(Button source) {
 | 
			
		||||
        // Only do the repeating click while the mouse is
 | 
			
		||||
        // over the button (and pressed of course)
 | 
			
		||||
        if (source.isPressed() && source.isHighlightOn()) {
 | 
			
		||||
            long elapsedTime = System.currentTimeMillis() - startTime
 | 
			
		||||
            // After half a second pause, click 8 times a second
 | 
			
		||||
            if (elapsedTime > 500 && elapsedTime > lastClick + 125) {
 | 
			
		||||
                source.click()
 | 
			
		||||
 | 
			
		||||
                // Try to quantize the last click time to prevent drift
 | 
			
		||||
                lastClick = ((elapsedTime - 500) / 125) * 125 + 500
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            startTime = System.currentTimeMillis()
 | 
			
		||||
            lastClick = 0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def stdButtonCommands = [
 | 
			
		||||
        (ButtonAction.Down)    : [pressedCommand],
 | 
			
		||||
        (ButtonAction.Up)      : [pressedCommand],
 | 
			
		||||
@@ -232,6 +280,16 @@ selector("settings-title", "pp") {
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
 }
 | 
			
		||||
selector("warning-title", "pp") {
 | 
			
		||||
    def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Grey inner border
 | 
			
		||||
    def innerBackground = new QuadBackgroundComponent(buttonBgColor) // White outer border background
 | 
			
		||||
    font = font("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt")
 | 
			
		||||
    background = outerBackground
 | 
			
		||||
    fontSize = 40
 | 
			
		||||
    insets = new Insets3f(3, 3, 3, 3)
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
selector("menu-button", "pp") {
 | 
			
		||||
    fontSize = 40 // Set font size
 | 
			
		||||
@@ -267,3 +325,44 @@ selector("selector.item.label", "hover") {
 | 
			
		||||
    background = new QuadBackgroundComponent(new ColorRGBA(0.2f, 0.6f, 1.0f, 0.9f))  // Highlighted background
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def enabledCommandToolbar = new Command<Button>() {
 | 
			
		||||
    void execute(Button source) {
 | 
			
		||||
        if (source.isEnabled()){
 | 
			
		||||
            source.setColor(ColorRGBA.White)
 | 
			
		||||
            def orangeBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)); // Orange background
 | 
			
		||||
            source.setBackground(orangeBackground);
 | 
			
		||||
        } else{
 | 
			
		||||
            source.setColor(ColorRGBA.White)
 | 
			
		||||
            def grayBackground = new QuadBackgroundComponent(ColorRGBA.Gray); // Gray background
 | 
			
		||||
            source.setBackground(grayBackground);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def stdButtonCommandsToolbar = [
 | 
			
		||||
        (ButtonAction.Down)    : [pressedCommand],
 | 
			
		||||
        (ButtonAction.Up)      : [pressedCommand],
 | 
			
		||||
        (ButtonAction.Enabled) : [enabledCommandToolbar],
 | 
			
		||||
        (ButtonAction.Disabled): [enabledCommandToolbar]
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
selector("button-toolbar", "pp") {
 | 
			
		||||
    def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Orange border
 | 
			
		||||
    def innerBackground = new QuadBackgroundComponent(buttonBgColor) // Inner button background
 | 
			
		||||
 | 
			
		||||
    // Apply the outer border as the main background
 | 
			
		||||
    background = outerBackground
 | 
			
		||||
 | 
			
		||||
    // Use insets to create a margin/padding effect for the inner background
 | 
			
		||||
    insets = new Insets3f(3, 3, 3, 3) // Adjust the border thickness
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
    buttonCommands = stdButtonCommandsToolbar
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
plugins {
 | 
			
		||||
    id 'buildlogic.jme-application-conventions'
 | 
			
		||||
    id 'com.github.johnrengelman.shadow' version '8.1.1'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
description = 'Monopoly Client'
 | 
			
		||||
@@ -26,3 +27,12 @@ application {
 | 
			
		||||
    mainClass = 'pp.monopoly.client.MonopolyApp'
 | 
			
		||||
    applicationName = 'monopoly'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
shadowJar {
 | 
			
		||||
    manifest {
 | 
			
		||||
        attributes(
 | 
			
		||||
            'Main-Class': 'pp.monopoly.client.MonopolyApp'
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,113 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.jme3.input.controls.ActionListener;
 | 
			
		||||
import com.jme3.scene.Node;
 | 
			
		||||
import com.jme3.system.AppSettings;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.gui.TestWorld;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the state responsible for managing the battle interface within the Battleship game.
 | 
			
		||||
 * This state handles the display and interaction of the battle map, including the opponent's map.
 | 
			
		||||
 * It manages GUI components, input events, and the layout of the interface when this state is enabled.
 | 
			
		||||
 */
 | 
			
		||||
public class GameAppState extends MonopolyAppState {
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(MonopolyAppState.class.getName());
 | 
			
		||||
    private static final float DEPTH = 0f;
 | 
			
		||||
    private static final float GAP = 20f;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A listener for handling click events in the battle interface.
 | 
			
		||||
     * When a click is detected, it triggers the corresponding actions on the opponent's map.
 | 
			
		||||
     */
 | 
			
		||||
    private final ActionListener clickListener = (name, isPressed, tpf) -> click(isPressed);
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * The root node for all GUI components in the battle state.
 | 
			
		||||
     */
 | 
			
		||||
    private final Node battleNode = new Node("Game"); //NON-NLS
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A view representing the opponent's map in the GUI.
 | 
			
		||||
     */
 | 
			
		||||
    private TestWorld testWorld;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Enables the battle state by initializing, laying out, and adding GUI components.
 | 
			
		||||
     * Attaches the components to the GUI node and registers input listeners.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void enableState() {
 | 
			
		||||
        battleNode.detachAllChildren();
 | 
			
		||||
        initializeGuiComponents();
 | 
			
		||||
        layoutGuiComponents();
 | 
			
		||||
        addGuiComponents();
 | 
			
		||||
        getApp().getGuiNode().attachChild(battleNode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Disables the battle state by removing GUI components and unregistering input listeners.
 | 
			
		||||
     * Also handles cleanup of resources, such as the opponent's map view.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void disableState() {
 | 
			
		||||
        getApp().getGuiNode().detachChild(battleNode);
 | 
			
		||||
        getApp().getInputManager().removeListener(clickListener);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the GUI components used in the battle state.
 | 
			
		||||
     * Creates the opponent's map view and adds a grid overlay to it.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeGuiComponents() {
 | 
			
		||||
 | 
			
		||||
        // Initialisiere TestWorld mit Spielern
 | 
			
		||||
        testWorld = new TestWorld(getApp());
 | 
			
		||||
        testWorld.initializeScene();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds the initialized GUI components to the battle node.
 | 
			
		||||
     * Currently, it attaches the opponent's map view to the node.
 | 
			
		||||
     */
 | 
			
		||||
    private void addGuiComponents() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lays out the GUI components within the window, positioning them appropriately.
 | 
			
		||||
     * The opponent's map view is positioned based on the window's dimensions and a specified gap.
 | 
			
		||||
     */
 | 
			
		||||
    private void layoutGuiComponents() {
 | 
			
		||||
        final AppSettings s = getApp().getContext().getSettings();
 | 
			
		||||
        final float windowWidth = s.getWidth();
 | 
			
		||||
        final float windowHeight = s.getHeight();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles click events in the battle interface. If the event indicates a click (not a release),
 | 
			
		||||
     * it translates the cursor position to the model's coordinate system and triggers the game logic
 | 
			
		||||
     * for interacting with the opponent's map.
 | 
			
		||||
     *
 | 
			
		||||
     * @param isPressed whether the mouse button is currently pressed (true) or released (false)
 | 
			
		||||
     */
 | 
			
		||||
    private void click(boolean isPressed) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        // testWorld.update(tpf);
 | 
			
		||||
        super.update(tpf);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -15,7 +15,7 @@ import com.jme3.audio.AudioData;
 | 
			
		||||
import com.jme3.audio.AudioNode;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handles the background music beeing played. Is able to start and stop the music. Set the Volume of the Audio.
 | 
			
		||||
 * Handles the background music being played. Is able to start and stop the music. Set the Volume of the Audio.
 | 
			
		||||
 */
 | 
			
		||||
public class GameMusic extends AbstractAppState{
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(GameMusic.class.getName());
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,11 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.prefs.Preferences;
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
@@ -11,21 +14,38 @@ import java.util.prefs.Preferences;
 | 
			
		||||
import com.jme3.app.Application;
 | 
			
		||||
import com.jme3.app.state.AbstractAppState;
 | 
			
		||||
import com.jme3.app.state.AppStateManager;
 | 
			
		||||
import com.jme3.asset.AssetLoadException;
 | 
			
		||||
import com.jme3.asset.AssetNotFoundException;
 | 
			
		||||
import com.jme3.audio.AudioData;
 | 
			
		||||
import com.jme3.audio.AudioNode;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.SoundEvent;
 | 
			
		||||
import static pp.util.PreferencesUtils.getPreferences;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An application state that plays sounds based on game events.
 | 
			
		||||
 * An application state that plays sounds.
 | 
			
		||||
 */
 | 
			
		||||
public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Logger instance for logging messages related to GameSound.
 | 
			
		||||
     */
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(GameSound.class.getName());
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *  Preferences instance for managing GameSound-related settings.
 | 
			
		||||
     */
 | 
			
		||||
    private static final Preferences PREFERENCES = getPreferences(GameSound.class);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Preference key for enabling or disabling GameSound.
 | 
			
		||||
     */
 | 
			
		||||
    private static final String ENABLED_PREF = "enabled"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Preference key for storing the volume level of GameSound.
 | 
			
		||||
     */
 | 
			
		||||
    private static final String VOLUME_PREF = "volume"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    private AudioNode passStartSound;
 | 
			
		||||
@@ -67,6 +87,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the enabled state of this AppState.
 | 
			
		||||
     * Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
 | 
			
		||||
     *
 | 
			
		||||
     * @param enabled {@code true} to enable the AppState, {@code false} to disable it.
 | 
			
		||||
     */
 | 
			
		||||
@@ -74,15 +95,16 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
    public void setEnabled(boolean enabled) {
 | 
			
		||||
        if (isEnabled() == enabled) return;
 | 
			
		||||
        super.setEnabled(enabled);
 | 
			
		||||
        LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled);
 | 
			
		||||
        LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS
 | 
			
		||||
        PREFERENCES.putBoolean(ENABLED_PREF, enabled);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the sound effects for the game and stores the application reference.
 | 
			
		||||
     * Initializes the sound effects for the game.
 | 
			
		||||
     * Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
 | 
			
		||||
     *
 | 
			
		||||
     * @param stateManager The state manager
 | 
			
		||||
     * @param app          The application instance
 | 
			
		||||
     * @param app          The application
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void initialize(AppStateManager stateManager, Application app) {
 | 
			
		||||
@@ -103,16 +125,18 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a sound from the specified file.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app  The application
 | 
			
		||||
     * @param name The name of the sound file.
 | 
			
		||||
     * @return The loaded AudioNode.
 | 
			
		||||
     */
 | 
			
		||||
    private AudioNode loadSound(String name) {
 | 
			
		||||
    private AudioNode loadSound(Application app, String name) {
 | 
			
		||||
        try {
 | 
			
		||||
            AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
 | 
			
		||||
            final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
 | 
			
		||||
            sound.setLooping(false);
 | 
			
		||||
            sound.setPositional(false);
 | 
			
		||||
            return sound;
 | 
			
		||||
        } catch (Exception ex) {
 | 
			
		||||
        }
 | 
			
		||||
        catch (AssetLoadException | AssetNotFoundException ex) {
 | 
			
		||||
            LOGGER.log(Level.ERROR, ex.getMessage(), ex);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
@@ -215,6 +239,11 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
        PREFERENCES.putFloat(VOLUME_PREF, vol);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Overrides  {@link SoundEvent#notifyListener(GameEventListener)}
 | 
			
		||||
     * @param event the received event
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(SoundEvent event) {
 | 
			
		||||
        switch (event.sound()) {
 | 
			
		||||
@@ -231,4 +260,4 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
            case BUTTON -> button();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}//heloo
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,15 @@
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.concurrent.ExecutorService;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
import java.util.logging.LogManager;
 | 
			
		||||
 | 
			
		||||
import com.jme3.app.DebugKeysAppState;
 | 
			
		||||
import com.jme3.app.SimpleApplication;
 | 
			
		||||
import com.jme3.app.StatsAppState;
 | 
			
		||||
@@ -18,43 +27,26 @@ import com.jme3.input.controls.ActionListener;
 | 
			
		||||
import com.jme3.input.controls.KeyTrigger;
 | 
			
		||||
import com.jme3.input.controls.MouseButtonTrigger;
 | 
			
		||||
import com.jme3.system.AppSettings;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.simsilica.lemur.GuiGlobals;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.style.BaseStyles;
 | 
			
		||||
import pp.monopoly.game.client.MonopolyClient;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.DialogBuilder;
 | 
			
		||||
import pp.dialog.DialogManager;
 | 
			
		||||
import pp.graphics.Draw;
 | 
			
		||||
import static pp.monopoly.Resources.lookup;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.client.gui.StartMenu;
 | 
			
		||||
import pp.monopoly.client.gui.TestWorld;
 | 
			
		||||
import pp.monopoly.client.gui.popups.BuildingPropertyCard;
 | 
			
		||||
import pp.monopoly.client.gui.popups.BuyCard;
 | 
			
		||||
import pp.monopoly.client.gui.popups.EventCard;
 | 
			
		||||
import pp.monopoly.client.gui.popups.FoodFieldCard;
 | 
			
		||||
import pp.monopoly.client.gui.popups.GateFieldCard;
 | 
			
		||||
import pp.monopoly.game.client.ClientGameLogic;
 | 
			
		||||
import pp.monopoly.game.client.MonopolyClient;
 | 
			
		||||
import pp.monopoly.game.client.ServerConnection;
 | 
			
		||||
import pp.monopoly.message.client.NotificationAnswer;
 | 
			
		||||
import pp.monopoly.notification.ClientStateEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.InfoTextEvent;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.DialogBuilder;
 | 
			
		||||
import pp.dialog.DialogManager;
 | 
			
		||||
import pp.graphics.Draw;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.concurrent.ExecutorService;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
import java.util.logging.LogManager;
 | 
			
		||||
 | 
			
		||||
import static pp.monopoly.Resources.lookup;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The main class for the Battleship client application.
 | 
			
		||||
 * The main class for the Monopoly client application.
 | 
			
		||||
 * It manages the initialization, input setup, GUI setup, and game states for the client.
 | 
			
		||||
 */
 | 
			
		||||
public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener {
 | 
			
		||||
@@ -129,16 +121,10 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
     */
 | 
			
		||||
    private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
 | 
			
		||||
 | 
			
		||||
    //TODO temp for testing
 | 
			
		||||
    private EventCard eventCard;
 | 
			
		||||
    private BuildingPropertyCard buildingProperty;
 | 
			
		||||
    private FoodFieldCard foodField;
 | 
			
		||||
    private GateFieldCard gateField;
 | 
			
		||||
    private BuyCard buyCard;
 | 
			
		||||
    private boolean isBuyCardPopupOpen = false;
 | 
			
		||||
    private final ActionListener BListener = (name, isPressed, tpf) -> handleB(isPressed);
 | 
			
		||||
    private final ActionListener TListener = (name, isPressed, tpf) -> handleT(isPressed);
 | 
			
		||||
    private TestWorld testWorld;
 | 
			
		||||
    /**
 | 
			
		||||
     * Listener for handeling Demo Mode (Minas mode)
 | 
			
		||||
     */
 | 
			
		||||
    private final ActionListener f8Listener = (name, isPressed, tpf) -> handleF8(isPressed);
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        // Configure logging
 | 
			
		||||
@@ -153,7 +139,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts the Battleship application.
 | 
			
		||||
     * Starts the Monopoly application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param args Command-line arguments for launching the application.
 | 
			
		||||
     */
 | 
			
		||||
@@ -165,7 +151,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
     * Constructs a new {@code MonopolyApp} instance.
 | 
			
		||||
     * Initializes the configuration, server connection, and game logic listeners.
 | 
			
		||||
     */
 | 
			
		||||
    private MonopolyApp() {
 | 
			
		||||
    public MonopolyApp() {
 | 
			
		||||
        config = new MonopolyAppConfig();
 | 
			
		||||
        config.readFromIfExists(CONFIG_FILE);
 | 
			
		||||
        serverConnection = makeServerConnection();
 | 
			
		||||
@@ -220,9 +206,9 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current configuration settings for the Battleship client.
 | 
			
		||||
     * Returns the current configuration settings for the Monopoly client.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The {@link BattleshipClientConfig} instance.
 | 
			
		||||
     * @return The {@link pp.monopoly.game.client.MonopolyClientConfig} instance.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public MonopolyAppConfig getConfig() {
 | 
			
		||||
@@ -267,45 +253,23 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
        inputManager.setCursorVisible(false);
 | 
			
		||||
        inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE));
 | 
			
		||||
        inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
 | 
			
		||||
        inputManager.addMapping("F8", new KeyTrigger(KeyInput.KEY_F8));
 | 
			
		||||
        inputManager.addListener(f8Listener, "F8");
 | 
			
		||||
        inputManager.addListener(escapeListener, ESC);
 | 
			
		||||
 | 
			
		||||
        //TODO tmp for testing
 | 
			
		||||
        inputManager.addMapping("B", new KeyTrigger(KeyInput.KEY_B));
 | 
			
		||||
        inputManager.addListener(BListener, "B");
 | 
			
		||||
        inputManager.addMapping("T", new KeyTrigger(KeyInput.KEY_T));
 | 
			
		||||
        inputManager.addListener(TListener, "T");
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //logik zum wechselnden erscheinen und verschwinden beim drücken von B //TODO süäter entfernen
 | 
			
		||||
    private void handleB(boolean isPressed) {
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the action on alt m for demo mode
 | 
			
		||||
     * @param isPressed {@code true} is alt + m is pressed, {@code false} otherwise
 | 
			
		||||
     */
 | 
			
		||||
    private void handleF8(boolean isPressed) {
 | 
			
		||||
        if (isPressed) {
 | 
			
		||||
            Dialog tmp = new BuyCard(this);
 | 
			
		||||
            if (eventCard != null && isBuyCardPopupOpen) {
 | 
			
		||||
                // Schließe das SettingsMenu
 | 
			
		||||
                System.out.println("Schließe BuyCardPopup...");
 | 
			
		||||
                eventCard.close();
 | 
			
		||||
                eventCard = null;
 | 
			
		||||
                tmp.open();
 | 
			
		||||
            } else {
 | 
			
		||||
                // Öffne das SettingsMenu
 | 
			
		||||
                System.out.println("Öffne BuyCardPopup...");
 | 
			
		||||
                eventCard = new EventCard(this);
 | 
			
		||||
                eventCard.open();
 | 
			
		||||
                dialogManager.close(tmp);
 | 
			
		||||
            }
 | 
			
		||||
            LOGGER.log(Level.INFO, "F detected."); // Debug logging
 | 
			
		||||
            getGameLogic().send(new NotificationAnswer("hack"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //logik zum wechselnden erscheinen und verschwinden beim drücken von B //TODO süäter entfernen
 | 
			
		||||
    private void handleT(boolean isPressed) {
 | 
			
		||||
        if (isPressed) {
 | 
			
		||||
            testWorld = new TestWorld(this);
 | 
			
		||||
            testWorld.initializeScene();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes and attaches the necessary application states for the game.
 | 
			
		||||
     */
 | 
			
		||||
@@ -321,6 +285,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
 | 
			
		||||
        attachGameSound();
 | 
			
		||||
        attachGameMusic();
 | 
			
		||||
        stateManager.attach(new GameAppState());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -353,11 +318,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
        super.simpleUpdate(tpf);
 | 
			
		||||
        dialogManager.update(tpf);
 | 
			
		||||
        logic.update(tpf);
 | 
			
		||||
 | 
			
		||||
        //TODO testing replace later
 | 
			
		||||
        if (testWorld != null) {
 | 
			
		||||
            testWorld.update(tpf);
 | 
			
		||||
        }
 | 
			
		||||
        stateManager.update(tpf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -444,6 +405,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(ClientStateEvent event) {
 | 
			
		||||
        stateManager.getState(GameAppState.class).setEnabled(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -501,7 +463,26 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
                     .open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Disconnects the current server connection.
 | 
			
		||||
     *
 | 
			
		||||
     * This method delegates the disconnection operation to the `disconnect` method of the
 | 
			
		||||
     * `serverConnection` object.
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    public void disconnect() {
 | 
			
		||||
        serverConnection.disconnect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the unique identifier associated with the server connection.
 | 
			
		||||
     *
 | 
			
		||||
     * Checks if a Server is connected and returns 0 if there is no connection
 | 
			
		||||
     *
 | 
			
		||||
     * @return the ID of the connected Server instance.
 | 
			
		||||
     */
 | 
			
		||||
    public int getId() {
 | 
			
		||||
        if (serverConnection != null && serverConnection instanceof NetworkSupport) return ((NetworkSupport) serverConnection).getId();
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ import java.lang.System.Logger.Level;
 | 
			
		||||
import static pp.monopoly.Resources.lookup;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Manages the network connection for the Battleship application.
 | 
			
		||||
 * Manages the network connection for the Monopoly application.
 | 
			
		||||
 * Handles connecting to and disconnecting from the server, and sending messages.
 | 
			
		||||
 */
 | 
			
		||||
public class NetworkSupport implements MessageListener<Client>, ClientStateListener, ServerConnection {
 | 
			
		||||
@@ -34,9 +34,9 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
    private Client client;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a NetworkSupport instance for the given Battleship application.
 | 
			
		||||
     * Constructs a NetworkSupport instance for the given Monopoly application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The Battleship application instance.
 | 
			
		||||
     * @param app The Monopoly application instance.
 | 
			
		||||
     */
 | 
			
		||||
    public NetworkSupport(MonopolyApp app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
@@ -44,6 +44,7 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the client connections Id
 | 
			
		||||
     *
 | 
			
		||||
     * @return the client id
 | 
			
		||||
     */
 | 
			
		||||
    public int getId() {
 | 
			
		||||
@@ -52,9 +53,9 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the Battleship application instance.
 | 
			
		||||
     * Returns the Monopoly application instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Battleship application instance
 | 
			
		||||
     * @return Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public MonopolyApp getApp() {
 | 
			
		||||
        return app;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,10 +3,8 @@ 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.Item;
 | 
			
		||||
import pp.monopoly.model.Visitor;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.ItemAddedEvent;
 | 
			
		||||
@@ -26,14 +24,10 @@ abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements
 | 
			
		||||
     *
 | 
			
		||||
     * @param board the game board to synchronize
 | 
			
		||||
     * @param root  the root node to which the view representations of the board items are attached
 | 
			
		||||
     * @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) {
 | 
			
		||||
    protected BoardSynchronizer(Board board, Node root) {
 | 
			
		||||
        super(root);
 | 
			
		||||
        this.board = board;
 | 
			
		||||
        this.board = board;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -48,7 +42,6 @@ abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds the existing items from the board to the view during initialization.
 | 
			
		||||
     * Adds the existing items from the board to the view during initialization.
 | 
			
		||||
     */
 | 
			
		||||
    protected void addExisting() {
 | 
			
		||||
@@ -56,36 +49,26 @@ abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the event when an item is removed from the board.
 | 
			
		||||
     * 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
 | 
			
		||||
     * @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());
 | 
			
		||||
        }
 | 
			
		||||
        if (board == event.getBoard()) {
 | 
			
		||||
            delete(event.getItem());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the event when an item is added to the board.
 | 
			
		||||
     * 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
 | 
			
		||||
     * @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());
 | 
			
		||||
        }
 | 
			
		||||
        if (board == event.getBoard()) {
 | 
			
		||||
            add(event.getItem());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,221 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.simsilica.lemur.*;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.popups.BuyHouse;
 | 
			
		||||
import pp.monopoly.client.gui.popups.RepayMortage;
 | 
			
		||||
import pp.monopoly.client.gui.popups.SellHouse;
 | 
			
		||||
import pp.monopoly.client.gui.popups.TakeMortage;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the building administration menu in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Provides options to manage properties, including building houses, demolishing houses,
 | 
			
		||||
 * taking mortgages, repaying mortgages, and viewing an overview of owned properties.
 | 
			
		||||
 * </p>
 | 
			
		||||
 */
 | 
			
		||||
public class BuildingAdminMenu extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the menu's UI components. */
 | 
			
		||||
    private final Container mainContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background geometry for the menu. */
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
 | 
			
		||||
    /** Button to navigate back to the previous menu. */
 | 
			
		||||
    private final Button backButton = new Button("Zurück");
 | 
			
		||||
 | 
			
		||||
    /** Button to build houses on properties. */
 | 
			
		||||
    private final Button buildButton = new Button("Bauen");
 | 
			
		||||
 | 
			
		||||
    /** Button to demolish houses on properties. */
 | 
			
		||||
    private final Button demolishButton = new Button("Abriss");
 | 
			
		||||
 | 
			
		||||
    /** Button to take out a mortgage on properties. */
 | 
			
		||||
    private final Button takeMortgageButton = new Button("Hypothek aufnehmen");
 | 
			
		||||
 | 
			
		||||
    /** Button to repay a mortgage on properties. */
 | 
			
		||||
    private final Button payMortgageButton = new Button("Hypothek bezahlen");
 | 
			
		||||
 | 
			
		||||
    /** Button to open the property overview menu. */
 | 
			
		||||
    private final Button overviewButton = new Button("Übersicht");
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the building administration menu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public BuildingAdminMenu(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Background Image
 | 
			
		||||
        addBackgroundImage();
 | 
			
		||||
 | 
			
		||||
        // Main container for the UI components
 | 
			
		||||
        mainContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        mainContainer.setPreferredSize(new Vector3f(800, 600, 0));
 | 
			
		||||
        mainContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(1, 1, 1, 0.7f))); // Translucent white background
 | 
			
		||||
 | 
			
		||||
        // Add header
 | 
			
		||||
        mainContainer.addChild(createHeaderContainer());
 | 
			
		||||
        // Add content
 | 
			
		||||
        mainContainer.addChild(createContent());
 | 
			
		||||
        // Attach main container to GUI node
 | 
			
		||||
        app.getGuiNode().attachChild(mainContainer);
 | 
			
		||||
        mainContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + mainContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the header container.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The header container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createHeaderContainer() {
 | 
			
		||||
        Container headerContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        headerContainer.setPreferredSize(new Vector3f(800, 100, 0));
 | 
			
		||||
        Label headerLabel = headerContainer.addChild(new Label("Grundstücke Verwalten", new ElementId("header")));
 | 
			
		||||
        headerLabel.setFontSize(45);
 | 
			
		||||
        headerLabel.setInsets(new Insets3f(10, 10, 10, 10));
 | 
			
		||||
        return headerContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main content container with columns for Overview, Build, and Mortgage.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The content container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createContent() {
 | 
			
		||||
        Container contentContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        contentContainer.setPreferredSize(new Vector3f(800, 500, 0));
 | 
			
		||||
 | 
			
		||||
        // Overview Column
 | 
			
		||||
        Container overviewColumn = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        overviewColumn.addChild(new Label("Übersicht:")).setFontSize(30);
 | 
			
		||||
 | 
			
		||||
        //Building Overview Button
 | 
			
		||||
        overviewButton.setPreferredSize(new Vector3f(200, 50, 0));
 | 
			
		||||
        overviewButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            new PropertyOverviewMenu(app).open();
 | 
			
		||||
        }));
 | 
			
		||||
        overviewColumn.addChild(overviewButton);
 | 
			
		||||
 | 
			
		||||
        // Back Button
 | 
			
		||||
        backButton.setPreferredSize(new Vector3f(200, 50, 0));
 | 
			
		||||
        backButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        overviewColumn.addChild(backButton);
 | 
			
		||||
 | 
			
		||||
        contentContainer.addChild(overviewColumn);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Build Column
 | 
			
		||||
        Container buildColumn = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        buildColumn.addChild(new Label("Bauen:")).setFontSize(30);
 | 
			
		||||
 | 
			
		||||
        // Build Houses Button
 | 
			
		||||
        buildButton.setPreferredSize(new Vector3f(200, 50, 0));
 | 
			
		||||
        buildButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            new BuyHouse(app).open();
 | 
			
		||||
        }));
 | 
			
		||||
        buildColumn.addChild(buildButton);
 | 
			
		||||
 | 
			
		||||
        //Demolish Houses Button
 | 
			
		||||
        demolishButton.setPreferredSize(new Vector3f(200, 50, 0));
 | 
			
		||||
        demolishButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            new SellHouse(app).open();
 | 
			
		||||
        }));
 | 
			
		||||
        buildColumn.addChild(demolishButton);
 | 
			
		||||
 | 
			
		||||
        contentContainer.addChild(buildColumn);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Mortgage Column
 | 
			
		||||
        Container mortgageColumn = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        mortgageColumn.addChild(new Label("Hypotheken:")).setFontSize(30);
 | 
			
		||||
 | 
			
		||||
        // Lend Mortgage Button
 | 
			
		||||
        takeMortgageButton.setPreferredSize(new Vector3f(200, 50, 0));
 | 
			
		||||
        takeMortgageButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            new TakeMortage(app).open();
 | 
			
		||||
        }));
 | 
			
		||||
        mortgageColumn.addChild(takeMortgageButton);
 | 
			
		||||
 | 
			
		||||
        //Repay Mortgage Button
 | 
			
		||||
        payMortgageButton.setPreferredSize(new Vector3f(200, 50, 0));
 | 
			
		||||
        payMortgageButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            new RepayMortage(app).open();
 | 
			
		||||
        }));
 | 
			
		||||
        mortgageColumn.addChild(payMortgageButton);  
 | 
			
		||||
 | 
			
		||||
        contentContainer.addChild(mortgageColumn);
 | 
			
		||||
 | 
			
		||||
        return contentContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a background image to the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    private void addBackgroundImage() {
 | 
			
		||||
        Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        background = new Geometry("Background", quad);
 | 
			
		||||
        Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        backgroundMaterial.setTexture("ColorMap", backgroundImage);
 | 
			
		||||
        background.setMaterial(backgroundMaterial);
 | 
			
		||||
        background.setLocalTranslation(0, 0, 6); // Position behind other GUI elements
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the building administration menu and detaches its elements from the GUI.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(mainContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(background);
 | 
			
		||||
        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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,60 +1,66 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.FastMath;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.renderer.Camera;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Steuert die Kamerabewegung in der Szene.
 | 
			
		||||
 * Controls the movement of the camera within the scene.
 | 
			
		||||
 */
 | 
			
		||||
public class CameraController {
 | 
			
		||||
    private final Camera camera;
 | 
			
		||||
    private final Vector3f center; // Fokuspunkt der Kamera
 | 
			
		||||
    private final float radius;    // Radius der Kreisbewegung
 | 
			
		||||
    private final float height;    // Höhe der Kamera über dem Spielfeld
 | 
			
		||||
    private final float speed;     // Geschwindigkeit der Kamerabewegung
 | 
			
		||||
    private float angle;           // Aktueller Winkel in der Kreisbewegung
 | 
			
		||||
    private final float height = 25;    // Height of the camera above the game board
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Konstruktor für den CameraController.
 | 
			
		||||
     * Constructor for the CameraController.
 | 
			
		||||
     *
 | 
			
		||||
     * @param camera Die Kamera, die gesteuert werden soll
 | 
			
		||||
     * @param center Der Mittelpunkt der Kreisbewegung (Fokuspunkt)
 | 
			
		||||
     * @param radius Der Radius der Kreisbewegung
 | 
			
		||||
     * @param height Die Höhe der Kamera über dem Fokuspunkt
 | 
			
		||||
     * @param speed  Die Geschwindigkeit der Kamerabewegung
 | 
			
		||||
     * @param camera The camera to be controlled
 | 
			
		||||
     */
 | 
			
		||||
    public CameraController(Camera camera, Vector3f center, float radius, float height, float speed) {
 | 
			
		||||
    public CameraController(Camera camera) {
 | 
			
		||||
        this.camera = camera;
 | 
			
		||||
        this.center = center;
 | 
			
		||||
        this.radius = radius;
 | 
			
		||||
        this.height = height;
 | 
			
		||||
        this.speed = speed;
 | 
			
		||||
        this.angle = 0; // Starte bei Winkel 0
 | 
			
		||||
        setPosition(0);
 | 
			
		||||
        camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Aktualisiert die Kameraposition und -ausrichtung.
 | 
			
		||||
     * Updates the camera's position and orientation.
 | 
			
		||||
     *
 | 
			
		||||
     * @param tpf Zeit pro Frame
 | 
			
		||||
     * @param tpf Time per frame
 | 
			
		||||
     */
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        camera.lookAt(center, Vector3f.UNIT_Y);
 | 
			
		||||
        camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the camera's position based on the field ID.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fieldID The ID of the field to which the camera should move
 | 
			
		||||
     */
 | 
			
		||||
    public void setPosition(int fieldID) {
 | 
			
		||||
        camera.setLocation(fieldIdToVector(fieldID));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
     */
 | 
			
		||||
    public void setPosition(float x, float y) {
 | 
			
		||||
        camera.setLocation(new Vector3f(x,height,y));
 | 
			
		||||
        camera.setLocation(new Vector3f(x, height, y));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
     */
 | 
			
		||||
    private Vector3f fieldIdToVector(int fieldID) {
 | 
			
		||||
        if (fieldID <= 10) return new Vector3f(30,height,0);
 | 
			
		||||
        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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,54 +1,162 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.*;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.message.client.ViewAssetsRequest;
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
public class ChoosePartner extends Dialog {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Container menuContainer;
 | 
			
		||||
    private Selector<String> playerSelector;
 | 
			
		||||
    private final Button cancelButton = new Button("Abbrechen");
 | 
			
		||||
    private final Button confirmButton = new Button("Bestätigen");
 | 
			
		||||
    private final Container mainContainer;
 | 
			
		||||
    private Container lowerLeftMenu;
 | 
			
		||||
    private Container lowerRightMenu;
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef; // Reference to track selector changes
 | 
			
		||||
    private String lastSelected = ""; // To keep track of the last selected value
 | 
			
		||||
 | 
			
		||||
    QuadBackgroundComponent translucentWhiteBackground =
 | 
			
		||||
            new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the ChoosePartner dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The Monopoly application instance.
 | 
			
		||||
     */
 | 
			
		||||
    public ChoosePartner(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        tradeHandler = new TradeHandler(app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()));
 | 
			
		||||
        app.getGameLogic().send(new ViewAssetsRequest());
 | 
			
		||||
 | 
			
		||||
        // Hintergrundbild laden und hinzufügen
 | 
			
		||||
        // Background Image
 | 
			
		||||
        addBackgroundImage();
 | 
			
		||||
 | 
			
		||||
        QuadBackgroundComponent translucentWhiteBackground =
 | 
			
		||||
                new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
 | 
			
		||||
        // Main container for the UI components
 | 
			
		||||
        mainContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        mainContainer.setPreferredSize(new Vector3f(1000, 600, 0));
 | 
			
		||||
        mainContainer.setBackground(translucentWhiteBackground);
 | 
			
		||||
 | 
			
		||||
        menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        menuContainer.setPreferredSize(new Vector3f(1000, 600, 0)); // Fixed size of the container
 | 
			
		||||
        menuContainer.setBackground(translucentWhiteBackground);
 | 
			
		||||
        // Add title with background
 | 
			
		||||
        Label headerLabel = mainContainer.addChild(new Label("Wähle deinen Handelspartner:", new ElementId("label-Bold")));
 | 
			
		||||
        headerLabel.setFontSize(40);
 | 
			
		||||
        headerLabel.setBackground(new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f)));
 | 
			
		||||
 | 
			
		||||
        // Create a smaller horizontal container for the label, input field, and spacers
 | 
			
		||||
        Container horizontalContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
 | 
			
		||||
        horizontalContainer.setPreferredSize(new Vector3f(600, 40, 0)); // Adjust container size
 | 
			
		||||
        horizontalContainer.setBackground(null);
 | 
			
		||||
        // Dropdown for player selection
 | 
			
		||||
        mainContainer.addChild(createDropdown());
 | 
			
		||||
 | 
			
		||||
        Label title = horizontalContainer.addChild(new Label("Wähle deinen Handelspartner:", new ElementId("label-Bold")));
 | 
			
		||||
        title.setFontSize(40);
 | 
			
		||||
        // Add buttons
 | 
			
		||||
        mainContainer.addChild(createButtonContainer());
 | 
			
		||||
 | 
			
		||||
        // Attach main container to GUI node
 | 
			
		||||
        app.getGuiNode().attachChild(mainContainer);
 | 
			
		||||
        mainContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + mainContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                4
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Initialize selection reference for tracking changes
 | 
			
		||||
        selectionRef = playerSelector.getSelectionModel().createReference();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu.
 | 
			
		||||
     * Creates the dropdown menu for selecting a partner.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The dropdown container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createDropdown() {
 | 
			
		||||
        Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(100, 80, 0));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(ColorRGBA.Black)));
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> playerOptions = new VersionedList<>();
 | 
			
		||||
 | 
			
		||||
        for (Player player : app.getGameLogic().getPlayerHandler().getPlayers()) {
 | 
			
		||||
            if (player.getId() != app.getId()) {
 | 
			
		||||
                playerOptions.add(player.getName() + " (ID: " + player.getId() + ")");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        playerSelector = new Selector<>(playerOptions, "glass");
 | 
			
		||||
        dropdownContainer.addChild(playerSelector);
 | 
			
		||||
        Vector3f dimens = dropdownContainer.getPreferredSize();
 | 
			
		||||
        Vector3f dimens2 = playerSelector.getPopupContainer().getPreferredSize();
 | 
			
		||||
        dimens2.setX(dimens.getX());
 | 
			
		||||
        playerSelector.getPopupContainer().setPreferredSize(new Vector3f(200, 200, 3));
 | 
			
		||||
        playerSelector.setLocalTranslation(0, 0, 5);
 | 
			
		||||
 | 
			
		||||
        // Set initial selection
 | 
			
		||||
        if (!playerOptions.isEmpty()) {
 | 
			
		||||
            onDropdownSelectionChanged(playerOptions.get(0));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return dropdownContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the button container with cancel and confirm buttons.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The button container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createButtonContainer() {
 | 
			
		||||
        Container buttonContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        buttonContainer.setBackground(translucentWhiteBackground);
 | 
			
		||||
 | 
			
		||||
        // "Abbrechen" button
 | 
			
		||||
        lowerLeftMenu = new Container();
 | 
			
		||||
        cancelButton.setPreferredSize(new Vector3f(200, 60, 0));
 | 
			
		||||
        cancelButton.setFontSize(30);
 | 
			
		||||
        cancelButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        lowerLeftMenu.addChild(cancelButton);
 | 
			
		||||
 | 
			
		||||
        // Position the container near the bottom-left corner
 | 
			
		||||
        lowerLeftMenu.setLocalTranslation(new Vector3f(120, 170, 5)); // Adjust X and Y to align with the bottom-left corner
 | 
			
		||||
        app.getGuiNode().attachChild(lowerLeftMenu);
 | 
			
		||||
 | 
			
		||||
        // "Bestätigen" button
 | 
			
		||||
        lowerRightMenu = new Container();
 | 
			
		||||
        confirmButton.setPreferredSize(new Vector3f(200, 60, 0));
 | 
			
		||||
        confirmButton.setFontSize(30);
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
            new TradeMenu(app, tradeHandler).open();
 | 
			
		||||
        }));
 | 
			
		||||
        lowerRightMenu.addChild(confirmButton);
 | 
			
		||||
 | 
			
		||||
        // Position the container near the bottom-right corner
 | 
			
		||||
        lowerRightMenu.setLocalTranslation(new Vector3f(app.getCamera().getWidth() - 320, 170, 5)); // X: 220px from the right, Y: 50px above the bottom
 | 
			
		||||
        app.getGuiNode().attachChild(lowerRightMenu);
 | 
			
		||||
 | 
			
		||||
        return buttonContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a background image to the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    private void addBackgroundImage() {
 | 
			
		||||
        Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
 | 
			
		||||
@@ -57,8 +165,60 @@ public class ChoosePartner extends Dialog {
 | 
			
		||||
        Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        backgroundMaterial.setTexture("ColorMap", backgroundImage);
 | 
			
		||||
        background.setMaterial(backgroundMaterial);
 | 
			
		||||
        background.setLocalTranslation(0, 0, -1); // Hintergrundebene
 | 
			
		||||
 | 
			
		||||
        background.setLocalTranslation(0, 0, 3); // Position behind other GUI elements
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action for the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the dialog periodically, called by the dialog manager.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta The time elapsed since the last update.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        // Check if the selection has changed
 | 
			
		||||
        if (selectionRef.update()) {
 | 
			
		||||
            String selected = playerSelector.getSelectedItem();
 | 
			
		||||
            if (!selected.equals(lastSelected)) {
 | 
			
		||||
                lastSelected = selected;
 | 
			
		||||
                onDropdownSelectionChanged(selected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(playerSelector);
 | 
			
		||||
        app.getGuiNode().detachChild(lowerLeftMenu);
 | 
			
		||||
        app.getGuiNode().detachChild(lowerRightMenu);
 | 
			
		||||
        app.getGuiNode().detachChild(mainContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(background);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Callback for when the dropdown selection changes.
 | 
			
		||||
     */
 | 
			
		||||
    private void onDropdownSelectionChanged(String selected) {
 | 
			
		||||
        app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        int idStart = selected.indexOf("(ID: ") + 5; // Find start of the ID
 | 
			
		||||
        int idEnd = selected.indexOf(")", idStart); // Find end of the ID
 | 
			
		||||
        String idStr = selected.substring(idStart, idEnd); // Extract the ID as a string
 | 
			
		||||
        int playerId = Integer.parseInt(idStr); // Convert the ID to an integer
 | 
			
		||||
 | 
			
		||||
        // Find the player by ID
 | 
			
		||||
        Player selectedPlayer = app.getGameLogic().getPlayerHandler().getPlayerById(playerId);
 | 
			
		||||
 | 
			
		||||
        if (selectedPlayer != null) {
 | 
			
		||||
            tradeHandler.setReceiver(selectedPlayer); // Set the receiver in TradeHandler
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ public class CreateGameMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
        final MonopolyApp app = network.getApp();
 | 
			
		||||
 | 
			
		||||
                int screenWidth = app.getContext().getSettings().getWidth();
 | 
			
		||||
        int screenWidth = app.getContext().getSettings().getWidth();
 | 
			
		||||
        int screenHeight = app.getContext().getSettings().getHeight();
 | 
			
		||||
 | 
			
		||||
        // Set up the background image
 | 
			
		||||
 
 | 
			
		||||
@@ -26,9 +26,9 @@ import static pp.util.FloatMath.PI;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The {@code GameBoardSynchronizer} class is responsible for synchronizing the graphical
 | 
			
		||||
 * representation of the ships and shots on the sea map with the underlying data model.
 | 
			
		||||
 * representation of the Game board and figures with the underlying data model.
 | 
			
		||||
 * It extends the {@link BoardSynchronizer} to provide specific synchronization
 | 
			
		||||
 * logic for the sea map.
 | 
			
		||||
 * logic for the Game board.
 | 
			
		||||
 */
 | 
			
		||||
class GameBoardSynchronizer extends BoardSynchronizer {
 | 
			
		||||
    private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
 | 
			
		||||
@@ -42,9 +42,9 @@ class GameBoardSynchronizer extends BoardSynchronizer {
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a {@code GameBoardSynchronizer} object with the specified application, root node, and ship map.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app  the Battleship application
 | 
			
		||||
     * @param app  the Monopoly application
 | 
			
		||||
     * @param root the root node to which graphical elements will be attached
 | 
			
		||||
     * @param map  the ship map containing the ships and shots
 | 
			
		||||
     * @param map  the Game Board containing fields and figures
 | 
			
		||||
     */
 | 
			
		||||
    public GameBoardSynchronizer(MonopolyApp app, Node root, Board board) {
 | 
			
		||||
        super(board, root);
 | 
			
		||||
@@ -54,17 +54,15 @@ class GameBoardSynchronizer extends BoardSynchronizer {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Visits a {@link Battleship} and creates a graphical representation of it.
 | 
			
		||||
     * The representation is either a 3D model or a simple box depending on the
 | 
			
		||||
     * type of battleship.
 | 
			
		||||
     * Visits a {@link Figure} and creates a graphical representation of it.
 | 
			
		||||
     * The representation is a 3D model.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ship the battleship to be represented
 | 
			
		||||
     * @return the node containing the graphical representation of the battleship
 | 
			
		||||
     * @param figure the figure to be represented
 | 
			
		||||
     * @return the node containing the graphical representation of the figure
 | 
			
		||||
     */
 | 
			
		||||
    public Spatial visit(Figure figure) {
 | 
			
		||||
        final Node node = new Node(FIGURE);
 | 
			
		||||
        node.attachChild(createBox(figure));
 | 
			
		||||
        // compute the center of the ship in world coordinates
 | 
			
		||||
        final float x = 1;
 | 
			
		||||
        final float z = 1;
 | 
			
		||||
        node.setLocalTranslation(x, 0f, z);
 | 
			
		||||
@@ -72,10 +70,10 @@ class GameBoardSynchronizer extends BoardSynchronizer {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a simple box to represent a battleship that is not of the "King George V" type.
 | 
			
		||||
     * Creates a representation of a figure
 | 
			
		||||
     *
 | 
			
		||||
     * @param ship the battleship to be represented
 | 
			
		||||
     * @return the geometry representing the battleship as a box
 | 
			
		||||
     * @param figure the figure to be represented
 | 
			
		||||
     * @return the geometry representing the figure
 | 
			
		||||
     */
 | 
			
		||||
    private Spatial createBox(Figure figure) {
 | 
			
		||||
        final Box box = new Box(0.5f * (figure.getMaxY() - figure.getMinY()) + 0.3f,
 | 
			
		||||
 
 | 
			
		||||
@@ -25,28 +25,58 @@ import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.game.server.PlayerColor;
 | 
			
		||||
import pp.monopoly.message.client.PlayerReady;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the lobby menu UI. */
 | 
			
		||||
    private final Container menuContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background geometry for the menu. */
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
 | 
			
		||||
    /** Colored circle displayed between input fields and dropdown menus. */
 | 
			
		||||
    private Geometry circle;
 | 
			
		||||
 | 
			
		||||
    /** Container for the lower-left section of the menu. */
 | 
			
		||||
    private Container lowerLeftMenu;
 | 
			
		||||
 | 
			
		||||
    /** Container for the lower-right section of the menu. */
 | 
			
		||||
    private Container lowerRightMenu;
 | 
			
		||||
 | 
			
		||||
    private TextField playerInputField = new TextField("Spieler 1");
 | 
			
		||||
    /** Text field for entering the player's name. */
 | 
			
		||||
    private TextField playerInputField;
 | 
			
		||||
 | 
			
		||||
    /** Text field for entering the starting capital. */
 | 
			
		||||
    private TextField startingCapital = new TextField("15000");
 | 
			
		||||
 | 
			
		||||
    /** Selected player figure. */
 | 
			
		||||
    private String figure;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the lobby menu for player configuration.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public LobbyMenu(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        playerInputField = new TextField("Spieler "+(app.getId()+1));
 | 
			
		||||
        // Hintergrundbild laden und hinzufügen
 | 
			
		||||
        addBackgroundImage();
 | 
			
		||||
 | 
			
		||||
@@ -88,6 +118,7 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
        // Dropdowns and Labels
 | 
			
		||||
        Container dropdownContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(ColorRGBA.Black)));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(800, 200, 0));
 | 
			
		||||
        dropdownContainer.setBackground(null);
 | 
			
		||||
        dropdownContainer.setInsets(new Insets3f(10, 0, 0, 0));
 | 
			
		||||
@@ -118,10 +149,18 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        figures.add("OOP");
 | 
			
		||||
        figures.add("Handyholster");
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Selector<String> figureDropdown = new Selector<>(figures, "glass");
 | 
			
		||||
        figureDropdown.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
 | 
			
		||||
        figureDropdown.setPreferredSize(new Vector3f(100, 20, 0));
 | 
			
		||||
        figureDropdownContainer.addChild(figureDropdown);
 | 
			
		||||
        Vector3f dimens = dropdownContainer.getPreferredSize();
 | 
			
		||||
        Vector3f dimens2 = figureDropdown.getPopupContainer().getPreferredSize();
 | 
			
		||||
        dimens2.setX( dimens.getX() );
 | 
			
		||||
        figureDropdown.getPopupContainer().setPreferredSize(new Vector3f(200,200,5));
 | 
			
		||||
        figureDropdown.getSelectionModel().setSelection(0);
 | 
			
		||||
        figure = "Laptop";
 | 
			
		||||
 | 
			
		||||
        addSelectionActionListener(figureDropdown, this::onDropdownSelectionChanged);
 | 
			
		||||
 | 
			
		||||
@@ -153,6 +192,7 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        readyButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            toggleReady();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
 | 
			
		||||
        }));
 | 
			
		||||
        lowerRightMenu.addChild(readyButton);
 | 
			
		||||
 | 
			
		||||
@@ -161,7 +201,7 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(lowerRightMenu);
 | 
			
		||||
 | 
			
		||||
        // Add a colored circle between the input field and the dropdown menu
 | 
			
		||||
        circle = createCircle( ColorRGBA.Red); // 50 is the diameter, Red is the color
 | 
			
		||||
        circle = createCircle(); // 50 is the diameter, Red is the color
 | 
			
		||||
        circle.setLocalTranslation(new Vector3f(
 | 
			
		||||
                (app.getCamera().getWidth()) / 2, // Center horizontally
 | 
			
		||||
                (app.getCamera().getHeight() / 2) - 90, // Adjust Y position
 | 
			
		||||
@@ -181,7 +221,7 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu.
 | 
			
		||||
     *  Adds a background image to the lobby menu.
 | 
			
		||||
     */
 | 
			
		||||
    private void addBackgroundImage() {
 | 
			
		||||
        Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/lobby.png");
 | 
			
		||||
@@ -195,33 +235,63 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Geometry createCircle(ColorRGBA color) {
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a circle graphic element for the menu.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the created circle geometry
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createCircle() {
 | 
			
		||||
 | 
			
		||||
        Sphere sphere = new Sphere(90,90,60.0f);
 | 
			
		||||
        Geometry circleGeometry = new Geometry("Circle", sphere);
 | 
			
		||||
 | 
			
		||||
        // Create a material with a solid color
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", color); // Set the desired color
 | 
			
		||||
        material.setColor("Color", idToColor()); // Set the desired color
 | 
			
		||||
        circleGeometry.setMaterial(material);
 | 
			
		||||
 | 
			
		||||
        return circleGeometry;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Schaltet den "Bereit"-Status um.
 | 
			
		||||
     * Maps the player's ID to a corresponding color.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the color associated with the player's ID
 | 
			
		||||
     */
 | 
			
		||||
    private ColorRGBA idToColor() {
 | 
			
		||||
        switch (app.getId()+1) {
 | 
			
		||||
            case 1: return PlayerColor.CYAN.getColor();
 | 
			
		||||
            case 2: return PlayerColor.YELLOW.getColor();
 | 
			
		||||
            case 3: return PlayerColor.RED.getColor();
 | 
			
		||||
            case 4: return PlayerColor.PINK.getColor();
 | 
			
		||||
            case 5: return PlayerColor.GREEN.getColor();
 | 
			
		||||
            case 6: return PlayerColor.PURPLE.getColor();
 | 
			
		||||
        
 | 
			
		||||
            default:
 | 
			
		||||
                return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Toggles the player's ready state and sends the configuration to the server.
 | 
			
		||||
     */
 | 
			
		||||
    private void toggleReady() {
 | 
			
		||||
        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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a custom action listener to the Selector.
 | 
			
		||||
     * Adds a custom action listener to a dropdown selector.
 | 
			
		||||
     *
 | 
			
		||||
     * @param selector the selector to add the listener to
 | 
			
		||||
     * @param listener the action to perform when a selection changes
 | 
			
		||||
     */
 | 
			
		||||
    private void addSelectionActionListener(Selector<String> selector, SelectionActionListener<String> listener) {
 | 
			
		||||
        VersionedReference<Set<Integer>> selectionRef = selector.getSelectionModel().createReference();
 | 
			
		||||
@@ -231,7 +301,6 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
            public void update(float tpf) {
 | 
			
		||||
                if (selectionRef.update()) {
 | 
			
		||||
                    String selected = selectionRef.get().toString();
 | 
			
		||||
                    System.out.println(selected);
 | 
			
		||||
                    listener.onSelectionChanged(selected);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -257,20 +326,21 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Callback for when the dropdown selection changes.
 | 
			
		||||
     * Updates the selected figure based on the dropdown menu selection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param selected the selected figure
 | 
			
		||||
     */
 | 
			
		||||
    private void onDropdownSelectionChanged(String selected) {
 | 
			
		||||
        System.out.println("Selected: " + selected);
 | 
			
		||||
        app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        switch (selected) {
 | 
			
		||||
            case "[0]":
 | 
			
		||||
                figure = "Laptop";
 | 
			
		||||
                figure = "Computer";
 | 
			
		||||
                break;
 | 
			
		||||
            case "[1]":
 | 
			
		||||
                figure = "Flugzeug";
 | 
			
		||||
                break;
 | 
			
		||||
            case "[2]":
 | 
			
		||||
                figure = "Jägermeister";
 | 
			
		||||
                figure = "Jaegermeister";
 | 
			
		||||
                break;
 | 
			
		||||
            case "[3]":
 | 
			
		||||
                figure = "Katze";
 | 
			
		||||
@@ -279,7 +349,7 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
                figure = "OOP";
 | 
			
		||||
                break;
 | 
			
		||||
            case "[5]":
 | 
			
		||||
                figure = "Handyholster";
 | 
			
		||||
                figure = "Holster";
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                break;    
 | 
			
		||||
@@ -287,10 +357,17 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Functional interface for a selection action listener.
 | 
			
		||||
     * Functional interface for handling selection changes in dropdown menus.
 | 
			
		||||
     *
 | 
			
		||||
     * @param <T> the type of the selection
 | 
			
		||||
     */
 | 
			
		||||
    @FunctionalInterface
 | 
			
		||||
    private interface SelectionActionListener<T> {
 | 
			
		||||
        /**
 | 
			
		||||
         * Triggered when the selection changes.
 | 
			
		||||
         *
 | 
			
		||||
         * @param selection the new selection
 | 
			
		||||
         */
 | 
			
		||||
        void onSelectionChanged(T selection);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,267 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.renderer.RenderManager;
 | 
			
		||||
import com.jme3.renderer.ViewPort;
 | 
			
		||||
import com.jme3.scene.control.AbstractControl;
 | 
			
		||||
import com.simsilica.lemur.*;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
import pp.monopoly.model.fields.FoodField;
 | 
			
		||||
import pp.monopoly.model.fields.GateField;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
 | 
			
		||||
import java.text.Collator;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * PropertyOverviewMenu is a dialog for displaying the player's properties in the game.
 | 
			
		||||
 */
 | 
			
		||||
public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Container mainContainer;
 | 
			
		||||
    private final Container displayContainer;
 | 
			
		||||
    private final Slider horizontalSlider;
 | 
			
		||||
    private final List<Container> cards;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the PropertyOverviewMenu dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The Monopoly application instance.
 | 
			
		||||
     */
 | 
			
		||||
    public PropertyOverviewMenu(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Make the menu fullscreen
 | 
			
		||||
        Vector3f screenSize = new Vector3f(app.getCamera().getWidth(), app.getCamera().getHeight(), 0);
 | 
			
		||||
 | 
			
		||||
        // Main container for the menu layout
 | 
			
		||||
        mainContainer = new Container();
 | 
			
		||||
        mainContainer.setPreferredSize(screenSize); // Make fullscreen
 | 
			
		||||
        mainContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.8f))); // Semi-transparent background
 | 
			
		||||
 | 
			
		||||
        // Header label
 | 
			
		||||
        Label headerLabel = mainContainer.addChild(new Label("Meine Grundstücke", new ElementId("header")));
 | 
			
		||||
        headerLabel.setFontSize(40);
 | 
			
		||||
 | 
			
		||||
        // Central display container (to hold the "Gebäude" cards)
 | 
			
		||||
        displayContainer = mainContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y, FillMode.Even, FillMode.None))); // Horizontal layout
 | 
			
		||||
        displayContainer.setPreferredSize(new Vector3f(screenSize.x - 300, 550, 0)); // Take up the remaining width
 | 
			
		||||
        displayContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.White));
 | 
			
		||||
        displayContainer.setLocalTranslation(0, 0, 11);
 | 
			
		||||
 | 
			
		||||
        // Add some placeholder "Gebäude" cards to the display container
 | 
			
		||||
        cards = new ArrayList<>();
 | 
			
		||||
        populatePlayerProperties();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Initially add only visible cards to the displayContainer
 | 
			
		||||
        refreshVisibleCards(0);
 | 
			
		||||
 | 
			
		||||
        // Horizontal slider for scrolling through cards
 | 
			
		||||
        horizontalSlider = mainContainer.addChild(new Slider(Axis.X));
 | 
			
		||||
        horizontalSlider.setPreferredSize(new Vector3f(screenSize.x - 300, 20, 5));
 | 
			
		||||
        horizontalSlider.setModel(new DefaultRangedValueModel(0, Math.max(0, cards.size() - 5), 0));
 | 
			
		||||
        horizontalSlider.addControl(new SliderValueChangeListener());
 | 
			
		||||
 | 
			
		||||
        // Add the "Zurück" button at the bottom
 | 
			
		||||
        Button backButton = mainContainer.addChild(new Button("Zurück", new ElementId("button")));
 | 
			
		||||
        backButton.setPreferredSize(new Vector3f(200, 60, 0));
 | 
			
		||||
        backButton.addClickCommands(source -> this.close());
 | 
			
		||||
 | 
			
		||||
        // Attach the main container to the GUI node
 | 
			
		||||
        app.getGuiNode().attachChild(mainContainer);
 | 
			
		||||
        mainContainer.setLocalTranslation(
 | 
			
		||||
                0,
 | 
			
		||||
                app.getCamera().getHeight(), // Align to the top
 | 
			
		||||
                10
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetches the player's properties and populates them into the cards list.
 | 
			
		||||
     */
 | 
			
		||||
    private void populatePlayerProperties() {
 | 
			
		||||
        // Fetch the current player
 | 
			
		||||
        Player currentPlayer = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
 | 
			
		||||
 | 
			
		||||
        // Fetch the player's properties using their indices
 | 
			
		||||
        List<PropertyField> fields = new ArrayList<>();
 | 
			
		||||
        for (Integer i : currentPlayer.getProperties()) {
 | 
			
		||||
            fields.add((PropertyField) app.getGameLogic().getBoardManager().getFieldAtIndex(i));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Iterate through the fetched properties
 | 
			
		||||
        for (PropertyField property : fields.stream().sorted(Comparator.comparingInt(PropertyField::getId)).collect(Collectors.toList())) {
 | 
			
		||||
            if (property instanceof BuildingProperty) {
 | 
			
		||||
                BuildingProperty building = (BuildingProperty) property;
 | 
			
		||||
                cards.add(createBuildingCard(building));
 | 
			
		||||
            } else if (property instanceof FoodField) {
 | 
			
		||||
                FoodField foodField = (FoodField) property;
 | 
			
		||||
                cards.add(createFoodFieldCard(foodField));
 | 
			
		||||
            } else if (property instanceof GateField) {
 | 
			
		||||
                GateField gateField = (GateField) property;
 | 
			
		||||
                cards.add(createGateFieldCard(gateField));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card for BuildingProperty with detailed rent and cost information.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createBuildingCard(BuildingProperty field) {
 | 
			
		||||
        Container card = new Container();
 | 
			
		||||
        card.setPreferredSize(new Vector3f(200, 300, 2)); // Match the size of the BuildingPropertyCard
 | 
			
		||||
        card.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
 | 
			
		||||
        card.setInsets(new Insets3f(5, 5, 5, 5)); // Add 5-pixel inset
 | 
			
		||||
 | 
			
		||||
        card.addChild(new Label(field.getName(), new ElementId("label-Bold"))).setFontSize(25);
 | 
			
		||||
 | 
			
		||||
        // Add property details
 | 
			
		||||
        Container propertyValuesContainer = card.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Grundstückswert: " + field.getPrice()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 1 Haus: " + field.getAllRent().get(1)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 2 Häuser: " + field.getAllRent().get(2)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 3 Häuser: " + field.getAllRent().get(3)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 4 Häuser: " + field.getAllRent().get(4)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 1 Hotel: " + field.getAllRent().get(5)+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- 1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
 | 
			
		||||
        Label hypo = new Label("Hypothek: " + field.getHypo()+ " EUR", new ElementId("label-Text"));
 | 
			
		||||
        hypo.setFontSize(14);
 | 
			
		||||
        if (field.isMortgaged()) hypo.setColor(ColorRGBA.Red);
 | 
			
		||||
        propertyValuesContainer.addChild(hypo);
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        return card;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card for FoodField with dynamic pricing and rent details.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createFoodFieldCard(FoodField field) {
 | 
			
		||||
        Container card = new Container();
 | 
			
		||||
        card.setPreferredSize(new Vector3f(200, 300, 2)); // Adjust card size
 | 
			
		||||
        card.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f))); // Dark background for card
 | 
			
		||||
        card.setInsets(new Insets3f(5, 5, 5, 5)); // Add 5-pixel inset
 | 
			
		||||
 | 
			
		||||
        // Title Section
 | 
			
		||||
        Label title = card.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        title.setFontSize(30);
 | 
			
		||||
        title.setColor(ColorRGBA.White); // Ensure readability on dark background
 | 
			
		||||
 | 
			
		||||
        // Property Values Section
 | 
			
		||||
        Container propertyValuesContainer = card.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Grey background
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Preis: " + field.getPrice()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man Besitzer der", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label(field.getName() + " ist, so ist", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("die Miete 40x Würfelwert.", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Besitzer beider", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Restaurants zahlt", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("100x Würfelwert.", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14); // Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Hypothek: " + field.getHypo()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
 | 
			
		||||
        return card;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card for GateField with rent details for owning multiple gates.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createGateFieldCard(GateField field) {
 | 
			
		||||
        Container card = new Container();
 | 
			
		||||
        card.setPreferredSize(new Vector3f(200, 300, 2)); // Adjust card size
 | 
			
		||||
        card.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light grey background
 | 
			
		||||
        card.setInsets(new Insets3f(5, 5, 5, 5)); // Add 5-pixel inset
 | 
			
		||||
 | 
			
		||||
        // Title Section
 | 
			
		||||
        Label title = card.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        title.setFontSize(30);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Property Values Section
 | 
			
		||||
        Container propertyValuesContainer = card.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Preis: " + field.getPrice()+ " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete: 250 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("2 Bahnhof besitzt: 500 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("3 Bahnhof besitzt: 1000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("4 Bahnhof besitzt: 2000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Dark grey background
 | 
			
		||||
 | 
			
		||||
        return card;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the visible cards in the displayContainer based on the slider value.
 | 
			
		||||
     *
 | 
			
		||||
     * @param startIndex The starting index of the visible cards.
 | 
			
		||||
     */
 | 
			
		||||
    private void refreshVisibleCards(int startIndex) {
 | 
			
		||||
        displayContainer.clearChildren(); // Remove all current children
 | 
			
		||||
        int maxVisible = 5; // Number of cards to display at once
 | 
			
		||||
        for (int i = startIndex; i < startIndex + maxVisible && i < cards.size(); i++) {
 | 
			
		||||
            displayContainer.addChild(cards.get(i));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Custom listener for slider value changes.
 | 
			
		||||
     * Extends {@link AbstractControl} to respond to updates in the slider's value and refresh
 | 
			
		||||
     *  the visible cards accordingly.
 | 
			
		||||
     */
 | 
			
		||||
    private class SliderValueChangeListener extends AbstractControl {
 | 
			
		||||
        @Override
 | 
			
		||||
        protected void controlUpdate(float tpf) {
 | 
			
		||||
            // Get the slider's current value and refresh visible cards
 | 
			
		||||
            int sliderValue = (int) ((Slider) getSpatial()).getModel().getValue();
 | 
			
		||||
            refreshVisibleCards(sliderValue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Overrides the rendering logic for the control.
 | 
			
		||||
         * <p>
 | 
			
		||||
         * This implementation does not require any rendering operations, so the method is left empty.
 | 
			
		||||
         *
 | 
			
		||||
         * @param renderManager the {@link RenderManager} handling the rendering process.
 | 
			
		||||
         * @param viewPort the {@link ViewPort} associated with the rendering context.
 | 
			
		||||
         */
 | 
			
		||||
        @Override
 | 
			
		||||
        protected void controlRender(RenderManager renderManager, ViewPort viewPort) {
 | 
			
		||||
            // No rendering logic needed
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the dialog and detaches it from the GUI node.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(mainContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,7 +14,6 @@ import com.simsilica.lemur.Checkbox;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import static pp.monopoly.Resources.lookup;
 | 
			
		||||
import pp.monopoly.client.GameMusic;
 | 
			
		||||
import pp.monopoly.client.GameSound;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
@@ -25,15 +24,30 @@ import pp.monopoly.notification.Sound;
 | 
			
		||||
import static pp.util.PreferencesUtils.getPreferences;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The Menu class represents the main menu in the Battleship game application.
 | 
			
		||||
 * It extends the Dialog class and provides functionalities for loading, saving,
 | 
			
		||||
 * The Menu class represents the main menu in the Monopoly game application.
 | 
			
		||||
 * It extends the Dialog class and provides functionalities for Volume adjustment, Sound adjustment,
 | 
			
		||||
 * returning to the game, and quitting the application.
 | 
			
		||||
 */
 | 
			
		||||
public class SettingsMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Preferences instance for storing and retrieving settings specific to the SettingsMenu.
 | 
			
		||||
     */
 | 
			
		||||
    private static final Preferences PREFERENCES = getPreferences(SettingsMenu.class);
 | 
			
		||||
    private static final String LAST_PATH = "last.file.path";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reference to the main Monopoly application instance.
 | 
			
		||||
     */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Slider control for adjusting the music volume.
 | 
			
		||||
     */
 | 
			
		||||
    private final VolumeSlider musicSlider;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Slider control for adjusting the sound effects volume.
 | 
			
		||||
     */
 | 
			
		||||
    private final SoundSlider soundSlider;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,14 @@ import pp.monopoly.client.GameSound;
 | 
			
		||||
 | 
			
		||||
public class SoundSlider extends Slider {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Manages sound effects for the game.
 | 
			
		||||
     */
 | 
			
		||||
    private final pp.monopoly.client.GameSound sound;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Volume level for the game sounds.
 | 
			
		||||
     */
 | 
			
		||||
    private double vol;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -20,7 +27,7 @@ public class SoundSlider extends Slider {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * when triggered it updates the volume to the value set with the slider
 | 
			
		||||
     * When triggered it updates the volume to the value set with the slider
 | 
			
		||||
     */
 | 
			
		||||
    public void update() {
 | 
			
		||||
        if (vol != getModel().getPercent()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,31 +6,23 @@ import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.HAlignment;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.HAlignment;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Constructs the startup menu dialog for the Monopoly application.
 | 
			
		||||
import pp.monopoly.client.gui.GameMenu;
 | 
			
		||||
 */
 | 
			
		||||
 */
 | 
			
		||||
public class StartMenu extends Dialog {
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Startup Menu dialog for the Monopoly application.
 | 
			
		||||
     * Constructs the Startup Menu dialog for the Monopoly application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the MonopolyApp instance
 | 
			
		||||
@@ -48,28 +40,25 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        Geometry background = new Geometry("Background", quad);
 | 
			
		||||
        Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        backgroundMaterial.setTexture("ColorMap", backgroundImage);
 | 
			
		||||
        backgroundMaterial.setTexture("ColorMap", backgroundImage);
 | 
			
		||||
        background.setMaterial(backgroundMaterial);
 | 
			
		||||
        background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
 | 
			
		||||
        background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
 | 
			
		||||
        background.setLocalTranslation(0, 0, -1);
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
 | 
			
		||||
        // Center container for title and play button
 | 
			
		||||
        Container centerMenu = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
 | 
			
		||||
        Button startButton = new Button("Spielen");
 | 
			
		||||
        startButton.setPreferredSize(new Vector3f(190, 60, 0)); // Increase button size (width, height)
 | 
			
		||||
        startButton.setFontSize(40); // Set the font size for the button text
 | 
			
		||||
        startButton.setTextHAlignment(HAlignment.Center); // Center the text horizontally
 | 
			
		||||
        startButton.setPreferredSize(new Vector3f(190, 60, 0));
 | 
			
		||||
        startButton.setFontSize(40);
 | 
			
		||||
        startButton.setTextHAlignment(HAlignment.Center);
 | 
			
		||||
 | 
			
		||||
        startButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            this.close();  // Close the StartMenu dialog
 | 
			
		||||
            app.connect(); // Perform the connection logic
 | 
			
		||||
            close();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.connect();
 | 
			
		||||
        }));
 | 
			
		||||
        centerMenu.addChild(startButton);
 | 
			
		||||
 | 
			
		||||
        // Position the center container in the middle of the screen
 | 
			
		||||
 | 
			
		||||
        centerMenu.setLocalTranslation(new Vector3f(screenWidth / 2f - centerMenu.getPreferredSize().x / 2f,
 | 
			
		||||
                                                    screenHeight / 2f - 280 + centerMenu.getPreferredSize().y / 2f,
 | 
			
		||||
                                                    0));
 | 
			
		||||
@@ -83,38 +72,32 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        QuadBackgroundComponent logoBackground = new QuadBackgroundComponent(logoTexture);
 | 
			
		||||
        logoContainer.setBackground(logoBackground);
 | 
			
		||||
 | 
			
		||||
        // Set the size of the container to fit the logo
 | 
			
		||||
        float logoWidth = 512;  // Adjust these values based on the logo dimensions
 | 
			
		||||
        float logoHeight = 128; // Adjust these values based on the logo dimensions
 | 
			
		||||
 | 
			
		||||
        float logoWidth = 512;
 | 
			
		||||
        float logoHeight = 128;
 | 
			
		||||
        logoContainer.setPreferredSize(new Vector3f(logoWidth, logoHeight, 0));
 | 
			
		||||
 | 
			
		||||
        // Position the container at the center of the screen
 | 
			
		||||
        logoContainer.setLocalTranslation(new Vector3f(
 | 
			
		||||
                screenWidth / 2f - logoWidth / 2f,
 | 
			
		||||
                screenHeight / 2f + 200, // Adjust this value for vertical position
 | 
			
		||||
                screenHeight / 2f + 200,
 | 
			
		||||
                0
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        // Attach the container to the GUI node
 | 
			
		||||
        app.getGuiNode().attachChild(logoContainer);
 | 
			
		||||
 | 
			
		||||
        // Load the Unibw logo as a texture
 | 
			
		||||
        Texture unibwTexture = app.getAssetManager().loadTexture("Pictures/logo-unibw.png");
 | 
			
		||||
 | 
			
		||||
        // Create a container for the Unibw logo
 | 
			
		||||
        Container unibwContainer = new Container();
 | 
			
		||||
        QuadBackgroundComponent unibwBackground = new QuadBackgroundComponent(unibwTexture);
 | 
			
		||||
        unibwContainer.setBackground(unibwBackground);
 | 
			
		||||
 | 
			
		||||
        // Set the size of the container to fit the Unibw logo
 | 
			
		||||
        float unibwWidth = 512;  // Adjust these values based on the logo dimensions
 | 
			
		||||
        float unibwHeight = 128; // Adjust these values based on the logo dimensions
 | 
			
		||||
        float unibwWidth = 512;
 | 
			
		||||
        float unibwHeight = 128;
 | 
			
		||||
        unibwContainer.setPreferredSize(new Vector3f(unibwWidth, unibwHeight, 0));
 | 
			
		||||
 | 
			
		||||
        // Position the container slightly below the Monopoly logo
 | 
			
		||||
        unibwContainer.setLocalTranslation(new Vector3f(
 | 
			
		||||
                screenWidth / 2f - unibwWidth / 2f,
 | 
			
		||||
                screenHeight / 2f + 100, // Adjust this value for vertical position
 | 
			
		||||
                screenHeight / 2f + 100,
 | 
			
		||||
                0
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
@@ -122,11 +105,17 @@ 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,94 +1,565 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
import java.util.concurrent.ScheduledExecutorService;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Timer;
 | 
			
		||||
import java.util.TimerTask;
 | 
			
		||||
 | 
			
		||||
import com.jme3.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.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Box;
 | 
			
		||||
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 einem texturierten Quadrat.
 | 
			
		||||
 * Die Kamera wird durch den CameraController gesteuert.
 | 
			
		||||
 * TestWorld zeigt eine einfache Szene mit Spielfeld und Spielfiguren.
 | 
			
		||||
 */
 | 
			
		||||
public class TestWorld {
 | 
			
		||||
public class TestWorld implements GameEventListener {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private CameraController cameraController; // Steuert die Kamera
 | 
			
		||||
    private PlayerHandler playerHandler;
 | 
			
		||||
    private CameraController cameraController;
 | 
			
		||||
    private Toolbar toolbar;
 | 
			
		||||
    private List<String> existingHouses = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Konstruktor für TestWorld.
 | 
			
		||||
     * Konstruktor für die TestWorld.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app Die Hauptanwendung (MonopolyApp)
 | 
			
		||||
     * @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 und startet die Kamerabewegung.
 | 
			
		||||
     * Initialisiert die Szene mit Spielfeld und Figuren.
 | 
			
		||||
     */
 | 
			
		||||
    public void initializeScene() {
 | 
			
		||||
        app.getGuiNode().detachAllChildren(); // Entferne GUI
 | 
			
		||||
        app.getRootNode().detachAllChildren(); // Entferne andere Szenenobjekte
 | 
			
		||||
        // Entferne bestehende Inhalte
 | 
			
		||||
        app.getGuiNode().detachAllChildren();
 | 
			
		||||
        app.getRootNode().detachAllChildren();
 | 
			
		||||
 | 
			
		||||
        setSkyColor(); // Setze den Himmel auf hellblau
 | 
			
		||||
        createBoard(); // Erstelle das Spielfeld
 | 
			
		||||
        System.out.println("Szene initialisiert.");
 | 
			
		||||
 | 
			
		||||
        // Erstelle den CameraController
 | 
			
		||||
        cameraController = new CameraController(
 | 
			
		||||
                app.getCamera(),           // Die Kamera der App
 | 
			
		||||
                Vector3f.ZERO,            // Fokus auf die Mitte des Spielfelds
 | 
			
		||||
                4,                        // Radius des Kreises
 | 
			
		||||
                15,                        // Höhe der Kamera
 | 
			
		||||
                0                     // Geschwindigkeit der Bewegung
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Füge die Toolbar hinzu
 | 
			
		||||
        new Toolbar(app).open();
 | 
			
		||||
        
 | 
			
		||||
        cameraController.setPosition(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Aktualisiert die Kameraposition.
 | 
			
		||||
     *
 | 
			
		||||
     * @param tpf Zeit pro Frame
 | 
			
		||||
     */
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        if (cameraController != null) {
 | 
			
		||||
            cameraController.update(tpf);
 | 
			
		||||
        }
 | 
			
		||||
        //Füge Inhalte ein
 | 
			
		||||
        setSkyColor();
 | 
			
		||||
        createBoard();
 | 
			
		||||
        addLighting();
 | 
			
		||||
        createPlayerFigures();
 | 
			
		||||
        toolbar = new Toolbar(app);
 | 
			
		||||
        toolbar.open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Setzt die Hintergrundfarbe der Szene auf hellblau.
 | 
			
		||||
     */
 | 
			
		||||
    private void setSkyColor() {
 | 
			
		||||
        app.getViewPort().setBackgroundColor(new ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f)); // Hellblauer Himmel
 | 
			
		||||
        app.getViewPort().setBackgroundColor(new com.jme3.math.ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstelle das Spielfeld.
 | 
			
		||||
     * Erstellt das Spielfeld und fügt es zur Szene hinzu.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBoard() {
 | 
			
		||||
        // Erstelle ein Quadrat
 | 
			
		||||
        Box box = new Box(10, 0.1f, 10);  // Dünnes Quadrat für die Textur
 | 
			
		||||
        Geometry geom = new Geometry("Board", box);
 | 
			
		||||
        try {
 | 
			
		||||
            com.jme3.scene.shape.Box box = new com.jme3.scene.shape.Box(10, 0.1f, 10);
 | 
			
		||||
            com.jme3.scene.Geometry geom = new com.jme3.scene.Geometry("Board", box);
 | 
			
		||||
 | 
			
		||||
        // Setze das Material mit Textur
 | 
			
		||||
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        Texture texture = app.getAssetManager().loadTexture("Pictures/board2.png");
 | 
			
		||||
        mat.setTexture("ColorMap", texture);
 | 
			
		||||
        geom.setMaterial(mat);
 | 
			
		||||
            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);
 | 
			
		||||
 | 
			
		||||
        app.getRootNode().attachChild(geom);
 | 
			
		||||
            geom.setLocalTranslation(0, -0.1f, 0);
 | 
			
		||||
 | 
			
		||||
            com.jme3.math.Quaternion rotation = new com.jme3.math.Quaternion();
 | 
			
		||||
            rotation.fromAngleAxis(FastMath.HALF_PI, com.jme3.math.Vector3f.UNIT_Y);
 | 
			
		||||
            geom.setLocalRotation(rotation);
 | 
			
		||||
 | 
			
		||||
            app.getRootNode().attachChild(geom);
 | 
			
		||||
        } 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,80 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.app.SimpleApplication;
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Box;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.jme3.system.JmeCanvasContext;
 | 
			
		||||
import com.jme3.system.AppSettings;
 | 
			
		||||
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.ActionEvent;
 | 
			
		||||
 | 
			
		||||
public class TestWorldWithMenu extends SimpleApplication {
 | 
			
		||||
 | 
			
		||||
    public static void createAndShowGUI() {
 | 
			
		||||
        // Create JFrame
 | 
			
		||||
        JFrame frame = new JFrame("Test World with Menu");
 | 
			
		||||
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 | 
			
		||||
        frame.setLayout(new BorderLayout());
 | 
			
		||||
        frame.setSize(800, 600);
 | 
			
		||||
 | 
			
		||||
        // Create Menu Bar
 | 
			
		||||
        JMenuBar menuBar = new JMenuBar();
 | 
			
		||||
        JMenu fileMenu = new JMenu("File");
 | 
			
		||||
        JMenuItem exitItem = new JMenuItem(new AbstractAction("Exit") {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void actionPerformed(ActionEvent e) {
 | 
			
		||||
                System.exit(0);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        fileMenu.add(exitItem);
 | 
			
		||||
        menuBar.add(fileMenu);
 | 
			
		||||
        frame.setJMenuBar(menuBar);
 | 
			
		||||
 | 
			
		||||
        // Create Canvas for jMonkey
 | 
			
		||||
        AppSettings settings = new AppSettings(true);
 | 
			
		||||
        settings.setWidth(800);
 | 
			
		||||
        settings.setHeight(600);
 | 
			
		||||
 | 
			
		||||
        TestWorldWithMenu app = new TestWorldWithMenu();
 | 
			
		||||
        app.setSettings(settings);
 | 
			
		||||
        app.createCanvas(); // Create a canvas for embedding
 | 
			
		||||
        JmeCanvasContext ctx = (JmeCanvasContext) app.getContext();
 | 
			
		||||
        ctx.setSystemListener(app);
 | 
			
		||||
        Canvas canvas = ctx.getCanvas();
 | 
			
		||||
        canvas.setSize(800, 600);
 | 
			
		||||
 | 
			
		||||
        // Add the canvas to JFrame
 | 
			
		||||
        frame.add(canvas, BorderLayout.CENTER);
 | 
			
		||||
 | 
			
		||||
        // Show the frame
 | 
			
		||||
        frame.setVisible(true);
 | 
			
		||||
 | 
			
		||||
        // Start the jMonkeyEngine application
 | 
			
		||||
        app.startCanvas();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void simpleInitApp() {
 | 
			
		||||
        // Erstelle ein Quadrat
 | 
			
		||||
        Box box = new Box(1, 0.01f, 1);  // Dünnes Quadrat für die Textur
 | 
			
		||||
        Geometry geom = new Geometry("Box", box);
 | 
			
		||||
 | 
			
		||||
        // Setze das Material mit Textur
 | 
			
		||||
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        Texture texture = assetManager.loadTexture("Pictures/board.png"); // Replace with the path to your image
 | 
			
		||||
        mat.setTexture("ColorMap", texture);
 | 
			
		||||
        geom.setMaterial(mat);
 | 
			
		||||
 | 
			
		||||
        // Füge das Quadrat zur Szene hinzu
 | 
			
		||||
        rootNode.attachChild(geom);
 | 
			
		||||
 | 
			
		||||
        // Setze die Kameraposition, um das Quadrat zu fokussieren
 | 
			
		||||
        cam.setLocation(new Vector3f(0, 0, 3));  // Kamera auf der Z-Achse, nah am Quadrat
 | 
			
		||||
        cam.lookAt(geom.getLocalTranslation(), Vector3f.UNIT_Y);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,292 +1,441 @@
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
 | 
			
		||||
import com.jme3.font.BitmapText;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector2f;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.simsilica.lemur.*;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.IconComponent;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.popups.Bankrupt;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.game.server.PlayerHandler;
 | 
			
		||||
import pp.monopoly.message.client.EndTurn;
 | 
			
		||||
import pp.monopoly.message.client.RollDice;
 | 
			
		||||
import pp.monopoly.notification.ButtonStatusEvent;
 | 
			
		||||
import pp.monopoly.notification.DiceRollEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
import pp.monopoly.notification.UpdatePlayerView;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
 | 
			
		||||
 * Die Buttons bewegen den Würfel auf dem Spielfeld.
 | 
			
		||||
 * 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>
 | 
			
		||||
 */
 | 
			
		||||
public class Toolbar extends Dialog {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Container toolbarContainer;
 | 
			
		||||
    private final BitmapText positionText; // Anzeige für die aktuelle Position
 | 
			
		||||
    private final float boardLimit = 0.95f; // Grenzen des Bretts
 | 
			
		||||
    private final float stepSize = 0.18f; // Schrittgröße pro Bewegung
 | 
			
		||||
    private int currentPosition = 0; // Aktuelle Position auf dem Spielfeld
 | 
			
		||||
    private final int positionsPerSide = 10; // Anzahl der Positionen pro Seite
 | 
			
		||||
    private final Random random = new Random(); // Zufallsgenerator für den Würfelwurf
 | 
			
		||||
public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Konstruktor für die Toolbar.
 | 
			
		||||
     * Reference to the Monopoly application instance.
 | 
			
		||||
     */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The main container for the toolbar interface.
 | 
			
		||||
     */
 | 
			
		||||
    private final Container toolbarContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Container for displaying an overview of other players.
 | 
			
		||||
     */
 | 
			
		||||
    private Container overviewContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Container for displaying account-related information.
 | 
			
		||||
     */
 | 
			
		||||
    private Container accountContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles player-related data and actions.
 | 
			
		||||
     */
 | 
			
		||||
    private PlayerHandler playerHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Label for the first dice display.
 | 
			
		||||
     */
 | 
			
		||||
    private Label imageLabel;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Label for the second dice display.
 | 
			
		||||
     */
 | 
			
		||||
    private Label imageLabel2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Button for rolling the dice.
 | 
			
		||||
     */
 | 
			
		||||
    private Button diceButton;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Button for initiating trades.
 | 
			
		||||
     */
 | 
			
		||||
    private Button tradeButton;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Button for accessing the property menu.
 | 
			
		||||
     */
 | 
			
		||||
    private Button propertyMenuButton;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Button for ending the player's turn.
 | 
			
		||||
     */
 | 
			
		||||
    private Button endTurnButton;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Flag indicating if dice animation is ongoing.
 | 
			
		||||
     */
 | 
			
		||||
    private volatile boolean animatingDice = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Stores the most recent dice roll event.
 | 
			
		||||
     */
 | 
			
		||||
    private volatile DiceRollEvent latestDiceRollEvent = null;
 | 
			
		||||
 | 
			
		||||
    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>
 | 
			
		||||
     *
 | 
			
		||||
     * @param app  Die Hauptanwendung (MonopolyApp)
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public Toolbar(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Erstelle die Toolbar
 | 
			
		||||
        toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y), "toolbar");
 | 
			
		||||
        app.getGameLogic().addListener(this);
 | 
			
		||||
        this.playerHandler = app.getGameLogic().getPlayerHandler();
 | 
			
		||||
 | 
			
		||||
        // Setze die Position am unteren Rand und die Breite
 | 
			
		||||
        toolbarContainer.setLocalTranslation(
 | 
			
		||||
                0,                                 // Links bündig
 | 
			
		||||
                200,                               // Höhe über dem unteren Rand
 | 
			
		||||
                0                                  // Z-Ebene
 | 
			
		||||
        );
 | 
			
		||||
        toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 200, 0)); // Volle Breite
 | 
			
		||||
        toolbarContainer = createToolbarContainer();
 | 
			
		||||
        app.getGuiNode().attachChild(toolbarContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Container createToolbarContainer() {
 | 
			
		||||
        // Erstelle den Hauptcontainer
 | 
			
		||||
        Container container = new Container(new SpringGridLayout(Axis.X, Axis.Y), "toolbar");
 | 
			
		||||
        container.setLocalTranslation(0, 200, 0);
 | 
			
		||||
        container.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 200, 0));
 | 
			
		||||
    
 | 
			
		||||
        // Spielerfarbe abrufen
 | 
			
		||||
        Player currentPlayer = playerHandler.getPlayerById(app.getId());
 | 
			
		||||
        ColorRGBA playerColor = currentPlayer.getColor().getColor();
 | 
			
		||||
    
 | 
			
		||||
        // Oberer Balken
 | 
			
		||||
        Container playerColorBar = new Container();
 | 
			
		||||
        playerColorBar.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 15, 0)); // Höhe des oberen Balkens
 | 
			
		||||
        playerColorBar.setBackground(new QuadBackgroundComponent(playerColor));
 | 
			
		||||
        playerColorBar.setLocalTranslation(0, 210, 3); // Position über der Toolbar
 | 
			
		||||
        app.getGuiNode().attachChild(playerColorBar);
 | 
			
		||||
 | 
			
		||||
        // Füge Buttons zur Toolbar hinzu
 | 
			
		||||
        //initializeButtons();
 | 
			
		||||
        // unterer Balken
 | 
			
		||||
        Container playerColorBarbot = new Container();
 | 
			
		||||
        playerColorBarbot.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 10, 0)); // Höhe des oberen Balkens
 | 
			
		||||
        playerColorBarbot.setBackground(new QuadBackgroundComponent(playerColor));
 | 
			
		||||
        playerColorBarbot.setLocalTranslation(0, 10, 3); // Position über der Toolbar
 | 
			
		||||
        app.getGuiNode().attachChild(playerColorBarbot);
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
        // Linker Balken
 | 
			
		||||
        Container leftBar = new Container();
 | 
			
		||||
        leftBar.setPreferredSize(new Vector3f(10, 210, 0)); // Breite 10, Höhe 210
 | 
			
		||||
        leftBar.setBackground(new QuadBackgroundComponent(playerColor));
 | 
			
		||||
        leftBar.setLocalTranslation(0, 200, 3); // Position am linken Rand
 | 
			
		||||
        app.getGuiNode().attachChild(leftBar);
 | 
			
		||||
    
 | 
			
		||||
        // Rechter Balken
 | 
			
		||||
        Container rightBar = new Container();
 | 
			
		||||
        rightBar.setPreferredSize(new Vector3f(10, 210, 0)); // Breite 10, Höhe 210
 | 
			
		||||
        rightBar.setBackground(new QuadBackgroundComponent(playerColor));
 | 
			
		||||
        rightBar.setLocalTranslation(app.getCamera().getWidth() - 10, 200, 2); // Position am rechten Rand
 | 
			
		||||
        app.getGuiNode().attachChild(rightBar);
 | 
			
		||||
        
 | 
			
		||||
        // Übersicht und Konto
 | 
			
		||||
        accountContainer = container.addChild(new Container());
 | 
			
		||||
        overviewContainer = container.addChild(new Container());
 | 
			
		||||
        receivedEvent(new UpdatePlayerView()); // Initiale Aktualisierung
 | 
			
		||||
    
 | 
			
		||||
        // Würfel-Bereich
 | 
			
		||||
        container.addChild(createDiceSection());
 | 
			
		||||
    
 | 
			
		||||
        // Aktionsmenü
 | 
			
		||||
        Container menuContainer = container.addChild(new Container());
 | 
			
		||||
        menuContainer.addChild(createTradeButton());
 | 
			
		||||
        menuContainer.addChild(createPropertyMenuButton());
 | 
			
		||||
        menuContainer.addChild(createEndTurnButton());
 | 
			
		||||
        menuContainer.setBackground(createBackground());
 | 
			
		||||
    
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Menü-Container: Ein Nested-Container für Kontostand und "Meine Gulag Frei Karten"
 | 
			
		||||
        Container accountContainer = toolbarContainer.addChild(new Container());
 | 
			
		||||
        accountContainer.addChild(new Label("Kontostand", new ElementId("label-Bold")));
 | 
			
		||||
        accountContainer.addChild(new Label("6666€", new ElementId("label-Text"))); //TODO Variable hier einsetzen
 | 
			
		||||
        accountContainer.addChild(new Label("Gulag Frei Karten", new ElementId("label-Bold")));
 | 
			
		||||
        accountContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Add a spacer between accountContainer and overviewContainer
 | 
			
		||||
        Panel spacer = new Panel(); // Create an empty panel as a spacer
 | 
			
		||||
        spacer.setPreferredSize(new Vector3f(5, 0, 0)); // Adjust the width as needed
 | 
			
		||||
        spacer.setBackground(null);
 | 
			
		||||
        toolbarContainer.addChild(spacer);
 | 
			
		||||
 | 
			
		||||
        // Menü-Container: Ein Container für Übersicht
 | 
			
		||||
        Container overviewContainer = toolbarContainer.addChild(new Container());
 | 
			
		||||
        overviewContainer.addChild(new Label("Übersicht", new ElementId("label-Bold")));
 | 
			
		||||
        overviewContainer.addChild(new Label("„Spieler 1“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
 | 
			
		||||
        overviewContainer.addChild(new Label("„Spieler 2“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
 | 
			
		||||
        overviewContainer.addChild(new Label("„Spieler 3“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
 | 
			
		||||
        overviewContainer.addChild(new Label("„Spieler 4“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
 | 
			
		||||
        overviewContainer.addChild(new Label("„Spieler 5“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen
 | 
			
		||||
        overviewContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Menü-Container: Ein Container für Würfel
 | 
			
		||||
        Container diceContainer = toolbarContainer.addChild(new Container());
 | 
			
		||||
        diceContainer.setLayout(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
 | 
			
		||||
        // Create a horizontal container to align leftContainer and rightContainer side by side
 | 
			
		||||
        Container horizontalContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        horizontalContainer.setPreferredSize(new Vector3f(200, 150, 0)); // Adjust size as needed
 | 
			
		||||
 | 
			
		||||
        // Create the first container (leftContainer)
 | 
			
		||||
        Container leftContainer = new Container();
 | 
			
		||||
        leftContainer.setPreferredSize(new Vector3f(100, 150, 0)); // Adjust size as needed
 | 
			
		||||
 | 
			
		||||
        Label imageLabel = new Label("");
 | 
			
		||||
        IconComponent icon = new IconComponent("Pictures/dice/one.png"); // Icon mit Textur erstellen
 | 
			
		||||
        icon.setIconSize(new Vector2f(100,100)); // Skalierung des Bildes
 | 
			
		||||
        imageLabel.setIcon(icon);
 | 
			
		||||
 | 
			
		||||
        Label imageLabel2 = new Label("");
 | 
			
		||||
        IconComponent icon2 = new IconComponent("Pictures/dice/two.png"); // Icon mit Textur erstellen
 | 
			
		||||
        icon2.setIconSize(new Vector2f(100,100)); // Skalierung des Bildes
 | 
			
		||||
        imageLabel2.setIcon(icon2);
 | 
			
		||||
 | 
			
		||||
        // Create the second container (rightContainer)
 | 
			
		||||
        Container rightContainer = new Container();
 | 
			
		||||
        rightContainer.setPreferredSize(new Vector3f(100, 150, 0)); // Adjust size as needed
 | 
			
		||||
        leftContainer.setBackground(null);
 | 
			
		||||
        rightContainer.setBackground(null);
 | 
			
		||||
    private Container createDiceSection() {
 | 
			
		||||
        Container diceContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        diceContainer.addChild(createDiceDisplay());
 | 
			
		||||
        diceContainer.setBackground(null);
 | 
			
		||||
        horizontalContainer.setBackground(null);
 | 
			
		||||
 | 
			
		||||
        imageLabel.setTextVAlignment(VAlignment.Center);
 | 
			
		||||
        imageLabel.setTextHAlignment(HAlignment.Center);
 | 
			
		||||
        imageLabel2.setTextVAlignment(VAlignment.Center);
 | 
			
		||||
        imageLabel2.setTextHAlignment(HAlignment.Center);
 | 
			
		||||
 | 
			
		||||
        leftContainer.addChild(imageLabel);
 | 
			
		||||
        rightContainer.addChild(imageLabel2);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Add leftContainer and rightContainer to the horizontal container
 | 
			
		||||
        horizontalContainer.addChild(leftContainer);
 | 
			
		||||
        horizontalContainer.addChild(rightContainer);
 | 
			
		||||
 | 
			
		||||
        // Add the horizontalContainer to the diceContainer (top section)
 | 
			
		||||
        diceContainer.addChild(horizontalContainer);
 | 
			
		||||
 | 
			
		||||
        // Add the Würfeln button directly below the horizontalContainer
 | 
			
		||||
        Button diceButton = new Button("Würfeln");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(200, 50, 0)); // Full width for Würfeln button
 | 
			
		||||
        diceButton = new Button("Würfeln", new ElementId("button-toolbar"));
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(200, 50, 0));
 | 
			
		||||
        diceButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            rollDice();
 | 
			
		||||
            diceButton.setEnabled(false);
 | 
			
		||||
            endTurnButton.setEnabled(true);
 | 
			
		||||
            startDiceAnimation();
 | 
			
		||||
            app.getGameLogic().send(new RollDice());
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        diceContainer.addChild(diceButton);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Menü-Container: Ein Nested-Container für Handeln, Grundstücke und Zug beenden
 | 
			
		||||
        Container menuContainer = toolbarContainer.addChild(new Container());
 | 
			
		||||
        menuContainer.addChild(new Button("Handeln"));
 | 
			
		||||
        menuContainer.addChild(new Button("Grundstücke"));
 | 
			
		||||
        menuContainer.addChild(new Button("Zug beenden"));
 | 
			
		||||
        menuContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Füge die Toolbar zur GUI hinzu
 | 
			
		||||
        app.getGuiNode().attachChild(toolbarContainer);
 | 
			
		||||
 | 
			
		||||
        // Erstelle die Position-Anzeige
 | 
			
		||||
        positionText = createPositionDisplay();
 | 
			
		||||
        updatePositionDisplay(); // Initialisiere die Anzeige mit der Startposition
 | 
			
		||||
        return diceContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialisiert die Buttons in der Toolbar.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeButtons() {
 | 
			
		||||
        addTradeMenuButton();  // Bewegung nach vorne
 | 
			
		||||
        addEndTurnButton(); // Bewegung nach hinten
 | 
			
		||||
        addDiceRollButton();       // Würfel-Button
 | 
			
		||||
    private Container createDiceDisplay() {
 | 
			
		||||
        Container horizontalContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        horizontalContainer.setPreferredSize(new Vector3f(200, 150, 0));
 | 
			
		||||
        horizontalContainer.setBackground(null);
 | 
			
		||||
 | 
			
		||||
        imageLabel = createDiceLabel("Pictures/dice/one.png");
 | 
			
		||||
        imageLabel2 = createDiceLabel("Pictures/dice/two.png");
 | 
			
		||||
 | 
			
		||||
        horizontalContainer.addChild(createDiceContainer(imageLabel));
 | 
			
		||||
        horizontalContainer.addChild(createDiceContainer(imageLabel2));
 | 
			
		||||
 | 
			
		||||
        return horizontalContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fügt einen Button mit einer Bewegung hinzu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param label   Der Text des Buttons
 | 
			
		||||
     * @param step    Schrittweite (+1 für vorwärts, -1 für rückwärts)
 | 
			
		||||
     */
 | 
			
		||||
    private Label createDiceLabel(String iconPath) {
 | 
			
		||||
        Label label = new Label("");
 | 
			
		||||
        IconComponent icon = new IconComponent(iconPath);
 | 
			
		||||
        icon.setIconSize(new Vector2f(100, 100));
 | 
			
		||||
        label.setIcon(icon);
 | 
			
		||||
        return label;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*private void addButton(String label, int step) {
 | 
			
		||||
        Button button = new Button(label);
 | 
			
		||||
        button.setPreferredSize(new Vector3f(150, 50, 0)); // Größe der Buttons
 | 
			
		||||
        button.addClickCommands(source -> moveCube(step));
 | 
			
		||||
        toolbarContainer.addChild(button);
 | 
			
		||||
    }*/
 | 
			
		||||
    private Container createDiceContainer(Label label) {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(null);
 | 
			
		||||
        container.setPreferredSize(new Vector3f(100, 150, 0));
 | 
			
		||||
        container.addChild(label);
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fügt den Würfel-Button hinzu, der die Figur entsprechend der gewürfelten Zahl bewegt.
 | 
			
		||||
     */
 | 
			
		||||
    private Button addDiceRollButton() {
 | 
			
		||||
        Button diceButton = new Button("Würfeln");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(50, 20, 0));
 | 
			
		||||
        diceButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            rollDice();
 | 
			
		||||
    private Button createTradeButton() {
 | 
			
		||||
        tradeButton = new Button("Handeln", new ElementId("button-toolbar"));
 | 
			
		||||
        tradeButton.setPreferredSize(new Vector3f(150, 50, 0));
 | 
			
		||||
        tradeButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
        return diceButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void addTradeMenuButton() {
 | 
			
		||||
        Button diceButton = new Button("Handeln");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
 | 
			
		||||
        diceButton.addClickCommands(s  -> {
 | 
			
		||||
            rollDice();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            this.close();
 | 
			
		||||
            System.out.println("test");
 | 
			
		||||
            new ChoosePartner(app).open();
 | 
			
		||||
        });
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
    }// TODO Funktion der Buttons Überarbeiten und prüfen
 | 
			
		||||
 | 
			
		||||
    private void addEndTurnButton() {
 | 
			
		||||
        Button diceButton = new Button("Grundstücke");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
 | 
			
		||||
        diceButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            rollDice();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
        return tradeButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void addPropertyMenuButton() {
 | 
			
		||||
        Button diceButton = new Button("Zug beenden");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
 | 
			
		||||
        diceButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            rollDice();
 | 
			
		||||
    private Button createPropertyMenuButton() {
 | 
			
		||||
        propertyMenuButton = new Button("Grundstücke", new ElementId("button-toolbar"));
 | 
			
		||||
        propertyMenuButton.setPreferredSize(new Vector3f(150, 50, 0));
 | 
			
		||||
        propertyMenuButton.setFontSize(30);
 | 
			
		||||
        propertyMenuButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            new BuildingAdminMenu(app).open();
 | 
			
		||||
        }));
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
        return propertyMenuButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Button createEndTurnButton() {
 | 
			
		||||
        endTurnButton = new Button("Zug beenden", new ElementId("button-toolbar"));
 | 
			
		||||
        endTurnButton.setFontSize(28);
 | 
			
		||||
        endTurnButton.setPreferredSize(new Vector3f(150, 50, 0));
 | 
			
		||||
        endTurnButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            if (app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getAccountBalance() < 0 && !bankruptPopUp) {
 | 
			
		||||
                new Bankrupt(app).open();
 | 
			
		||||
                bankruptPopUp = true;
 | 
			
		||||
            } else {
 | 
			
		||||
                bankruptPopUp = false;
 | 
			
		||||
                app.getGameLogic().send(new EndTurn());
 | 
			
		||||
                receivedEvent(new ButtonStatusEvent(false));
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
        return endTurnButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private QuadBackgroundComponent createBackground() {
 | 
			
		||||
        return new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void startDiceAnimation() {
 | 
			
		||||
        animatingDice = true;
 | 
			
		||||
        long startTime = System.currentTimeMillis();
 | 
			
		||||
    
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            try {
 | 
			
		||||
                animateDice(startTime);
 | 
			
		||||
                animatingDice = false;
 | 
			
		||||
                if (latestDiceRollEvent != null) {
 | 
			
		||||
                    showFinalDiceResult(latestDiceRollEvent);
 | 
			
		||||
                }
 | 
			
		||||
            } catch (InterruptedException e) {
 | 
			
		||||
                System.err.println("Dice animation interrupted: " + e.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Simuliert einen Würfelwurf und bewegt die Figur entsprechend.
 | 
			
		||||
     * Animates the dice roll by cycling through dice images.
 | 
			
		||||
     */
 | 
			
		||||
    private void rollDice() {
 | 
			
		||||
        int diceRoll = random.nextInt(6) + 1; // Zahl zwischen 1 und 6
 | 
			
		||||
        System.out.println("Gewürfelt: " + diceRoll);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Berechnet die neue Position des Würfels basierend auf der aktuellen Brettseite und Position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param position Aktuelle Position auf dem Spielfeld
 | 
			
		||||
     * @return Die berechnete Position als Vector3f
 | 
			
		||||
     */
 | 
			
		||||
    private Vector3f calculatePosition(int position) {
 | 
			
		||||
        int side = position / positionsPerSide; // Seite des Bretts (0 = unten, 1 = rechts, 2 = oben, 3 = links)
 | 
			
		||||
        int offset = position % positionsPerSide; // Position auf der aktuellen Seite
 | 
			
		||||
 | 
			
		||||
        switch (side) {
 | 
			
		||||
            case 0: // Unten (positive x-Achse)
 | 
			
		||||
                return new Vector3f(-boardLimit + offset * stepSize, 0.1f, -boardLimit + 0.05f);
 | 
			
		||||
            case 1: // Rechts (positive z-Achse)
 | 
			
		||||
                return new Vector3f(boardLimit - 0.05f, 0.1f, -boardLimit + offset * stepSize);
 | 
			
		||||
            case 2: // Oben (negative x-Achse)
 | 
			
		||||
                return new Vector3f(boardLimit - offset * stepSize, 0.1f, boardLimit - 0.05f);
 | 
			
		||||
            case 3: // Links (negative z-Achse)
 | 
			
		||||
                return new Vector3f(-boardLimit + 0.05f, 0.1f, boardLimit - offset * stepSize);
 | 
			
		||||
            default:
 | 
			
		||||
                throw new IllegalArgumentException("Ungültige Position: " + position);
 | 
			
		||||
    private void animateDice(long startTime) throws InterruptedException {
 | 
			
		||||
        int[] currentFace = {1};
 | 
			
		||||
        while (System.currentTimeMillis() - startTime < 2000) { // Animation duration
 | 
			
		||||
            currentFace[0] = (currentFace[0] % 6) + 1;
 | 
			
		||||
    
 | 
			
		||||
            String rotatingImage1 = diceToString(currentFace[0]);
 | 
			
		||||
            String rotatingImage2 = diceToString((currentFace[0] % 6) + 1);
 | 
			
		||||
    
 | 
			
		||||
            app.enqueue(() -> {
 | 
			
		||||
                setDiceIcon(imageLabel, rotatingImage1);
 | 
			
		||||
                setDiceIcon(imageLabel2, rotatingImage2);
 | 
			
		||||
            });
 | 
			
		||||
    
 | 
			
		||||
            Thread.sleep(100); // Time between frame updates
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt die Anzeige für die aktuelle Position.
 | 
			
		||||
     * Displays the final dice result after animation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Das BitmapText-Objekt für die Anzeige
 | 
			
		||||
     * @param event the dice roll event containing the result
 | 
			
		||||
     */
 | 
			
		||||
    private BitmapText createPositionDisplay() {
 | 
			
		||||
        BitmapText text = new BitmapText(app.getAssetManager().loadFont("Interface/Fonts/Default.fnt"), false);
 | 
			
		||||
        text.setSize(20); // Schriftgröße
 | 
			
		||||
        text.setLocalTranslation(10, app.getCamera().getHeight() - 10, 0); // Oben links
 | 
			
		||||
        app.getGuiNode().attachChild(text);
 | 
			
		||||
        return text;
 | 
			
		||||
    private void showFinalDiceResult(DiceRollEvent event) {
 | 
			
		||||
        app.enqueue(() -> {
 | 
			
		||||
            setDiceIcon(imageLabel, diceToString(event.a()));
 | 
			
		||||
            setDiceIcon(imageLabel2, diceToString(event.b()));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void setDiceIcon(Label label, String imagePath) {
 | 
			
		||||
        IconComponent icon = new IconComponent(imagePath);
 | 
			
		||||
        icon.setIconSize(new Vector2f(80, 80)); // Set consistent dice size
 | 
			
		||||
        label.setIcon(icon);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Aktualisiert die Anzeige für die aktuelle Position.
 | 
			
		||||
     * Handles dice roll events by updating the dice display.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event the dice roll event containing dice values
 | 
			
		||||
     */
 | 
			
		||||
    private void updatePositionDisplay() {
 | 
			
		||||
        positionText.setText("Feld-ID: " + currentPosition);
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(DiceRollEvent event) {
 | 
			
		||||
        latestDiceRollEvent = event;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the player view with the latest account and overview data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event the update event for the player view
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(UpdatePlayerView event) {
 | 
			
		||||
        playerHandler = app.getGameLogic().getPlayerHandler();
 | 
			
		||||
        System.out.println("Update Player View");
 | 
			
		||||
        accountContainer.clearChildren();
 | 
			
		||||
        overviewContainer.clearChildren();
 | 
			
		||||
 | 
			
		||||
        accountContainer.addChild(new Label("Kontostand", new ElementId("label-toolbar")));
 | 
			
		||||
        accountContainer.addChild(new Label(
 | 
			
		||||
                playerHandler.getPlayerById(app.getId()).getAccountBalance() + " EUR",
 | 
			
		||||
                new ElementId("label-account")
 | 
			
		||||
        ));
 | 
			
		||||
        accountContainer.addChild(new Label("Gulag Karten", new ElementId("label-toolbar")));
 | 
			
		||||
        accountContainer.addChild(new Label(
 | 
			
		||||
                playerHandler.getPlayerById(app.getId()).getNumJailCard() + "",
 | 
			
		||||
                new ElementId("label-account")
 | 
			
		||||
        ));
 | 
			
		||||
        accountContainer.setBackground(null);
 | 
			
		||||
 | 
			
		||||
        overviewContainer.addChild(new Label("Übersicht", new ElementId("label-toolbar")));
 | 
			
		||||
        for (Player player : playerHandler.getPlayers()) {
 | 
			
		||||
            if (player.getId() != app.getId()) {
 | 
			
		||||
                // Spielerfarbe abrufen
 | 
			
		||||
                ColorRGBA playerColor = (player.getColor().getColor());
 | 
			
		||||
            
 | 
			
		||||
                // Label für den Spieler erstellen
 | 
			
		||||
                Label playerLabel = new Label(
 | 
			
		||||
                    player.getName() + ": " + player.getAccountBalance() + " EUR",
 | 
			
		||||
                    new ElementId("label-Text")
 | 
			
		||||
                );
 | 
			
		||||
            
 | 
			
		||||
                // Farbe setzen
 | 
			
		||||
                playerLabel.setColor(playerColor);
 | 
			
		||||
            
 | 
			
		||||
                // Label zum Container hinzufügen
 | 
			
		||||
                overviewContainer.addChild(playerLabel);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        overviewContainer.setBackground(null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the enabled status of toolbar buttons based on the event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event the button status event
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(ButtonStatusEvent event) {
 | 
			
		||||
        boolean enabled = event.buttonsEnabled();
 | 
			
		||||
        diceButton.setEnabled(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);
 | 
			
		||||
        app.getGuiNode().detachChild(positionText);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the toolbar by refreshing player information.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update() {
 | 
			
		||||
        receivedEvent(new UpdatePlayerView());
 | 
			
		||||
        super.update();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,382 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.simsilica.lemur.*;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import com.simsilica.lemur.text.DocumentModel;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.message.client.TradeOffer;
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
/**
 | 
			
		||||
 * 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 {
 | 
			
		||||
 | 
			
		||||
    /** The Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** The trade handler managing trade logic. */
 | 
			
		||||
    private final TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the trade menu UI. */
 | 
			
		||||
    private final Container mainContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background geometry for the menu. */
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
    private Selector<String> leftBuildingSelector, leftSpecialCardSelector;
 | 
			
		||||
    private Selector<String> rightBuildingSelector, rightSpecialCardSelector;
 | 
			
		||||
    private TextField leftSelectionsField, rightSelectionsField;
 | 
			
		||||
    private TextField leftCurrencyInput, rightCurrencyInput;
 | 
			
		||||
 | 
			
		||||
    private VersionedReference<Set<Integer>> leftBuildingRef, rightBuildingRef;
 | 
			
		||||
    private VersionedReference<DocumentModel> leftCurrencyRef, rightCurrencyRef;
 | 
			
		||||
    private VersionedReference<Set<Integer>> leftCardRef, rightCardRef;
 | 
			
		||||
 | 
			
		||||
    private Set<String> rightselBuildings = new HashSet<>();
 | 
			
		||||
    private Set<String> leftselBuildings = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    private static final ColorRGBA TRANSLUCENT_WHITE = new ColorRGBA(1, 1, 1, 0.5f);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the trade menu dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app          the Monopoly application instance
 | 
			
		||||
     * @param tradeHandler the handler managing trade interactions
 | 
			
		||||
     */
 | 
			
		||||
    public TradeMenu(MonopolyApp app, TradeHandler tradeHandler) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        this.tradeHandler = tradeHandler;
 | 
			
		||||
 | 
			
		||||
        addBackgroundImage();
 | 
			
		||||
 | 
			
		||||
        mainContainer = createMainContainer();
 | 
			
		||||
        app.getGuiNode().attachChild(mainContainer);
 | 
			
		||||
        positionMainContainer();
 | 
			
		||||
 | 
			
		||||
        initializeReferences();
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the main container for the trade menu UI. */
 | 
			
		||||
    private Container createMainContainer() {
 | 
			
		||||
        Container container = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(1200, 800, 0));
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE));
 | 
			
		||||
 | 
			
		||||
        container.addChild(createHeader());
 | 
			
		||||
        container.addChild(createMainContent());
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the header label for the trade menu. */
 | 
			
		||||
    private Label createHeader() {
 | 
			
		||||
        Label header = new Label("Handelsmenü", new ElementId("label-Bold"));
 | 
			
		||||
        header.setFontSize(50);
 | 
			
		||||
        header.setInsets(new Insets3f(10, 10, 10, 10));
 | 
			
		||||
        header.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE));
 | 
			
		||||
        return header;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the main content section of the trade menu. */
 | 
			
		||||
    private Container createMainContent() {
 | 
			
		||||
        Container mainContent = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        mainContent.setPreferredSize(new Vector3f(1200, 700, 0));
 | 
			
		||||
 | 
			
		||||
        mainContent.addChild(createTradeColumn("Wähle Handelsobjekt:", true));
 | 
			
		||||
        mainContent.addChild(createMiddleSection());
 | 
			
		||||
        mainContent.addChild(createTradeColumn("Wähle Zielobjekt:", false));
 | 
			
		||||
 | 
			
		||||
        return mainContent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Sets the trade data based on the current selections. */
 | 
			
		||||
    private void setTrades() {
 | 
			
		||||
        String leftCurreny = leftCurrencyInput.getText().equals("")? "0" : leftCurrencyInput.getText();
 | 
			
		||||
        String rightCurreny = rightCurrencyInput.getText().equals("")? "0" : rightCurrencyInput.getText();
 | 
			
		||||
        tradeHandler.setOfferedAmount(Integer.parseInt(leftCurreny));
 | 
			
		||||
        tradeHandler.setRequestedAmount(Integer.parseInt(rightCurreny));
 | 
			
		||||
        tradeHandler.setOfferedJailCards(Integer.parseInt(leftSpecialCardSelector.getSelectedItem()));
 | 
			
		||||
        tradeHandler.setRequestedJailCards(Integer.parseInt(rightSpecialCardSelector.getSelectedItem()));
 | 
			
		||||
 | 
			
		||||
        Set<PropertyField> offeredProperties = new HashSet<>();
 | 
			
		||||
        for (String propertyString : leftselBuildings) {
 | 
			
		||||
            offeredProperties.add( (PropertyField) app.getGameLogic().getBoardManager().getFieldByName(propertyString));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        Set<PropertyField> requestedProperties = new HashSet<>();
 | 
			
		||||
        for (String propertyString : rightselBuildings) {
 | 
			
		||||
            requestedProperties.add( (PropertyField) app.getGameLogic().getBoardManager().getFieldByName(propertyString));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        tradeHandler.setOfferedProperties(offeredProperties);
 | 
			
		||||
        tradeHandler.setRequestedProperties(requestedProperties);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a trade column for either the sender or receiver.
 | 
			
		||||
     *
 | 
			
		||||
     * @param label  the label text for the column
 | 
			
		||||
     * @param isLeft true if the column is for the sender; false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    private Container createTradeColumn(String label, boolean isLeft) {
 | 
			
		||||
        Container column = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        column.setBackground(new QuadBackgroundComponent(ColorRGBA.White));
 | 
			
		||||
 | 
			
		||||
        Label columnLabel = column.addChild(new Label(label));
 | 
			
		||||
        columnLabel.setFontSize(24);
 | 
			
		||||
        columnLabel.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE));
 | 
			
		||||
 | 
			
		||||
        column.addChild(new Label("Gebäude:"));
 | 
			
		||||
        Selector<String> buildingSelector = createPropertySelector(isLeft);
 | 
			
		||||
        column.addChild(buildingSelector);
 | 
			
		||||
 | 
			
		||||
        column.addChild(new Label("Währung:"));
 | 
			
		||||
        TextField currencyInput = createCurrencyInput();
 | 
			
		||||
        column.addChild(currencyInput);
 | 
			
		||||
 | 
			
		||||
        column.addChild(new Label("Sonderkarten:"));
 | 
			
		||||
        Selector<String> specialCardSelector = createSpecialCardSelector(isLeft);
 | 
			
		||||
        styleSelector(specialCardSelector);
 | 
			
		||||
        column.addChild(specialCardSelector);
 | 
			
		||||
 | 
			
		||||
        assignSelectors(buildingSelector, specialCardSelector, currencyInput, isLeft);
 | 
			
		||||
        return column;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a property selector for buildings.
 | 
			
		||||
     *
 | 
			
		||||
     * @param isLeft true if the selector is for the sender; false otherwise
 | 
			
		||||
     * @return the created property selector
 | 
			
		||||
     */
 | 
			
		||||
    private Selector<String> createPropertySelector(boolean isLeft) {
 | 
			
		||||
        VersionedList<String> properties = new VersionedList<>();
 | 
			
		||||
        for (PropertyField field : getPropertyFields(isLeft)) {
 | 
			
		||||
            properties.add(field.getName());
 | 
			
		||||
        }
 | 
			
		||||
        Selector<String> selector = new Selector<>(properties, "glass");
 | 
			
		||||
        styleSelector(selector);
 | 
			
		||||
        return selector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a selector for special cards.
 | 
			
		||||
     *
 | 
			
		||||
     * @param isLeft true if the selector is for the sender; false otherwise
 | 
			
		||||
     * @return the created special card selector
 | 
			
		||||
     */
 | 
			
		||||
    private Selector<String> createSpecialCardSelector(boolean isLeft) {
 | 
			
		||||
        VersionedList<String> numbers = new VersionedList<>();
 | 
			
		||||
        for (int i = 0; i <= app.getGameLogic().getPlayerHandler().getPlayerById(isLeft ? tradeHandler.getReceiver().getId() : tradeHandler.getSender().getId()).getNumJailCard(); i++) {
 | 
			
		||||
            numbers.add(i + "");
 | 
			
		||||
        }
 | 
			
		||||
        Selector<String> selector = new Selector<>(numbers, "glass");
 | 
			
		||||
        styleSelector(selector);
 | 
			
		||||
        return selector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the property fields owned by the respective player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param isLeft true if retrieving fields for the sender; false otherwise
 | 
			
		||||
     * @return an iterable of property fields
 | 
			
		||||
     */
 | 
			
		||||
    private Iterable<PropertyField> getPropertyFields(boolean isLeft) {
 | 
			
		||||
        return app.getGameLogic()
 | 
			
		||||
                .getBoardManager()
 | 
			
		||||
                .getPropertyFields(app.getGameLogic()
 | 
			
		||||
                        .getPlayerHandler()
 | 
			
		||||
                        .getPlayerById(isLeft ? tradeHandler.getSender().getId() : tradeHandler.getReceiver().getId())
 | 
			
		||||
                        .getProperties());
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates a text field for currency input. */
 | 
			
		||||
    private TextField createCurrencyInput() {
 | 
			
		||||
        TextField currencyInput = new TextField("0");
 | 
			
		||||
        styleTextField(currencyInput);
 | 
			
		||||
        return currencyInput;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the middle section containing buttons and summary fields. */
 | 
			
		||||
    private Container createMiddleSection() {
 | 
			
		||||
        Container middleSection = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        middleSection.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        Label middleLabelTop = middleSection.addChild(new Label("Gebäude:        Währung:        Sonderkarten:"));
 | 
			
		||||
        middleLabelTop.setFontSize(24);
 | 
			
		||||
        middleLabelTop.setInsets(new Insets3f(5, 5, 5, 5));
 | 
			
		||||
 | 
			
		||||
        leftSelectionsField = middleSection.addChild(new TextField(""));
 | 
			
		||||
        leftSelectionsField.setPreferredSize(new Vector3f(600, 50, 0));
 | 
			
		||||
 | 
			
		||||
        Container buttons = middleSection.addChild(new Container(new SpringGridLayout()));
 | 
			
		||||
        Button cancel = new Button("Abbrechen");
 | 
			
		||||
        cancel.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            close();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        Button trade = new Button("Handeln");
 | 
			
		||||
        trade.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            setTrades();
 | 
			
		||||
            app.getGameLogic().send(new TradeOffer(tradeHandler));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        buttons.addChild(cancel);
 | 
			
		||||
        buttons.addChild(trade);
 | 
			
		||||
 | 
			
		||||
        Label middleLabelBottom = middleSection.addChild(new Label("Gebäude:        Währung:        Sonderkarten:"));
 | 
			
		||||
        middleLabelBottom.setFontSize(24);
 | 
			
		||||
        middleLabelBottom.setInsets(new Insets3f(5, 5, 5, 5));
 | 
			
		||||
 | 
			
		||||
        rightSelectionsField = middleSection.addChild(new TextField(""));
 | 
			
		||||
        rightSelectionsField.setPreferredSize(new Vector3f(600, 50, 0));
 | 
			
		||||
        return middleSection;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Styles the given selector with insets and background color. */
 | 
			
		||||
    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. */
 | 
			
		||||
    private void styleTextField(TextField textField) {
 | 
			
		||||
        textField.setInsets(new Insets3f(5, 10, 5, 10));
 | 
			
		||||
        textField.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
 | 
			
		||||
        textField.setPreferredSize(new Vector3f(300, 30, 0));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Assigns selectors and input fields to either the left or right column.
 | 
			
		||||
     *
 | 
			
		||||
     * @param buildingSelector    the building selector
 | 
			
		||||
     * @param specialCardSelector the special card selector
 | 
			
		||||
     * @param currencyInput       the currency input field
 | 
			
		||||
     * @param isLeft              true if assigning to the left column; false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    private void assignSelectors(Selector<String> buildingSelector, Selector<String> specialCardSelector, TextField currencyInput, boolean isLeft) {
 | 
			
		||||
        if (isLeft) {
 | 
			
		||||
            leftBuildingSelector = buildingSelector;
 | 
			
		||||
            leftSpecialCardSelector = specialCardSelector;
 | 
			
		||||
            leftCurrencyInput = currencyInput;
 | 
			
		||||
        } else {
 | 
			
		||||
            rightBuildingSelector = buildingSelector;
 | 
			
		||||
            rightSpecialCardSelector = specialCardSelector;
 | 
			
		||||
            rightCurrencyInput = currencyInput;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    /** Positions the main container at the center of the screen. */
 | 
			
		||||
    private void positionMainContainer() {
 | 
			
		||||
        mainContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + mainContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    /** 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());
 | 
			
		||||
        background = new Geometry("Background", quad);
 | 
			
		||||
        Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        backgroundMaterial.setTexture("ColorMap", backgroundImage);
 | 
			
		||||
        background.setMaterial(backgroundMaterial);
 | 
			
		||||
        background.setLocalTranslation(0, 0, 6);
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
    /** Initializes references for tracking UI changes. */
 | 
			
		||||
    private void initializeReferences() {
 | 
			
		||||
        leftBuildingRef = leftBuildingSelector.getSelectionModel().createReference();
 | 
			
		||||
        leftCardRef = leftSpecialCardSelector.getSelectionModel().createReference();
 | 
			
		||||
        leftCurrencyRef = leftCurrencyInput.getDocumentModel().createReference();
 | 
			
		||||
 | 
			
		||||
        rightBuildingRef = rightBuildingSelector.getSelectionModel().createReference();
 | 
			
		||||
        rightCardRef = rightSpecialCardSelector.getSelectionModel().createReference();
 | 
			
		||||
        rightCurrencyRef = rightCurrencyInput.getDocumentModel().createReference();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the trade menu state, including selected properties and values.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta the time elapsed since the last update
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        if (leftBuildingRef.update() || leftCardRef.update() || leftCurrencyRef.update()) {
 | 
			
		||||
            updateSelections(leftSelectionsField, leftBuildingSelector, leftCurrencyInput, leftSpecialCardSelector, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (rightBuildingRef.update() || rightCardRef.update() || rightCurrencyRef.update()) {
 | 
			
		||||
            updateSelections(rightSelectionsField, rightBuildingSelector, rightCurrencyInput, rightSpecialCardSelector, false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the displayed selections for properties, currency, and cards.
 | 
			
		||||
     *
 | 
			
		||||
     * @param target   the target text field to update
 | 
			
		||||
     * @param building the building selector
 | 
			
		||||
     * @param currency the currency input field
 | 
			
		||||
     * @param card     the special card selector
 | 
			
		||||
     * @param isLeft   true if updating the left column; false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    private void updateSelections(TextField target, Selector<String> building, TextField currency, Selector<String> card, boolean isLeft) {
 | 
			
		||||
        StringBuilder buildingText = new StringBuilder();
 | 
			
		||||
        if (isLeft) {
 | 
			
		||||
            if (leftselBuildings.contains(building.getSelectedItem())) {
 | 
			
		||||
                leftselBuildings.remove(building.getSelectedItem()); // Remove if already selected
 | 
			
		||||
            } else {
 | 
			
		||||
                leftselBuildings.add(building.getSelectedItem()); // Add if not already selected
 | 
			
		||||
            }
 | 
			
		||||
            for (String  property : leftselBuildings) {
 | 
			
		||||
                buildingText.append(property);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (rightselBuildings.contains(building.getSelectedItem())) {
 | 
			
		||||
                rightselBuildings.remove(building.getSelectedItem()); // Remove if already selected
 | 
			
		||||
            } else {
 | 
			
		||||
                rightselBuildings.add(building.getSelectedItem()); // Add if not already selected
 | 
			
		||||
            }
 | 
			
		||||
            for (String  property : rightselBuildings) {
 | 
			
		||||
                buildingText.append(property);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String currencyText = currency.getText() != null ? currency.getText().trim() : "";
 | 
			
		||||
        String cardText = card.getSelectedItem() != null ? card.getSelectedItem() : "";
 | 
			
		||||
        target.setText(String.join(" | ", buildingText, currencyText, cardText));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Opens the settings menu when the escape key is pressed. */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Closes the trade menu and detaches UI elements. */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(mainContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(background);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -25,7 +25,7 @@ public class VolumeSlider extends Slider {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * when triggered it updates the volume to the value set with the slider
 | 
			
		||||
     * When triggered it updates the volume to the value set with the slider
 | 
			
		||||
     */
 | 
			
		||||
    public void update() {
 | 
			
		||||
        if (vol != getModel().getPercent()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,504 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2014, Simsilica, LLC
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * 
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions 
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright 
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright 
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in 
 | 
			
		||||
 *    the documentation and/or other materials provided with the 
 | 
			
		||||
 *    distribution.
 | 
			
		||||
 * 
 | 
			
		||||
 * 3. Neither the name of the copyright holder nor the names of its 
 | 
			
		||||
 *    contributors may be used to endorse or promote products derived 
 | 
			
		||||
 *    from this software without specific prior written permission.
 | 
			
		||||
 * 
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 | 
			
		||||
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 | 
			
		||||
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 | 
			
		||||
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 | 
			
		||||
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 | 
			
		||||
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 | 
			
		||||
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 | 
			
		||||
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 | 
			
		||||
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 package pp.monopoly.client.gui.hslider;
 | 
			
		||||
 | 
			
		||||
 import com.jme3.scene.Node;
 | 
			
		||||
 import com.jme3.scene.Spatial;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.FillMode;
 | 
			
		||||
import com.simsilica.lemur.GuiGlobals;
 | 
			
		||||
import com.simsilica.lemur.HAlignment;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Panel;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
 import com.simsilica.lemur.core.GuiControl;
 | 
			
		||||
 import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
 import com.simsilica.lemur.grid.GridModel;
 | 
			
		||||
 import com.simsilica.lemur.style.Attributes;
 | 
			
		||||
 import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 import com.simsilica.lemur.style.StyleDefaults;
 | 
			
		||||
 import com.simsilica.lemur.style.Styles;
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
  *
 | 
			
		||||
  *  @author    Paul Speed
 | 
			
		||||
  */
 | 
			
		||||
 public class GridPanel extends Panel {
 | 
			
		||||
 
 | 
			
		||||
     public static final String ELEMENT_ID = "grid";
 | 
			
		||||
 
 | 
			
		||||
     private GridModel<Panel> model;
 | 
			
		||||
     private VersionedReference<GridModel<Panel>> modelRef;
 | 
			
		||||
     private SpringGridLayout layout;
 | 
			
		||||
     private int visibleRows = 5;
 | 
			
		||||
     private int visibleColumns = 5;
 | 
			
		||||
     private int row = 0;
 | 
			
		||||
     private int column = 0;
 | 
			
		||||
     private Float alpha; // for setting to new children
 | 
			
		||||
     private Float[] columnwidths = null;
 | 
			
		||||
     private Float[] rowheight = null;
 | 
			
		||||
     private boolean widthsupdate = false;
 | 
			
		||||
     private HAlignment [] columnHalignement = null;
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     public GridPanel(GridModel<Panel> model ) {
 | 
			
		||||
         this(true, model, new ElementId(ELEMENT_ID), null);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public GridPanel(GridModel<Panel> model, String style ) {
 | 
			
		||||
         this(true, model, new ElementId(ELEMENT_ID), style);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public GridPanel(GridModel<Panel> model, ElementId elementId, String style ) {
 | 
			
		||||
         this(true, model, elementId, style);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     protected GridPanel(boolean applyStyles, GridModel<Panel> model,
 | 
			
		||||
                         ElementId elementId, String style ) {
 | 
			
		||||
         super(false, elementId, style);
 | 
			
		||||
 
 | 
			
		||||
         this.layout = new SpringGridLayout(Axis.Y, Axis.X,
 | 
			
		||||
                                            FillMode.ForcedEven,
 | 
			
		||||
                                            FillMode.ForcedEven);
 | 
			
		||||
         getControl(GuiControl.class).setLayout(layout);
 | 
			
		||||
 
 | 
			
		||||
         if( applyStyles ) {
 | 
			
		||||
             Styles styles = GuiGlobals.getInstance().getStyles();
 | 
			
		||||
             styles.applyStyles(this, elementId, style);
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         setModel(model);
 | 
			
		||||
     }
 | 
			
		||||
     // change the layout if necessary
 | 
			
		||||
     public void setLayout(SpringGridLayout lay) {
 | 
			
		||||
         this.layout = lay;
 | 
			
		||||
         getControl(GuiControl.class).getLayout().clearChildren();
 | 
			
		||||
         getControl(GuiControl.class).setLayout(layout);
 | 
			
		||||
 
 | 
			
		||||
         this.modelRef = null;
 | 
			
		||||
         if( this.model != null ) {
 | 
			
		||||
             this.modelRef = model.createReference();
 | 
			
		||||
             refreshGrid();
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     @StyleDefaults(ELEMENT_ID)
 | 
			
		||||
     public static void initializeDefaultStyles( Attributes attrs ) {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setModel( GridModel<Panel> model ) {
 | 
			
		||||
 
 | 
			
		||||
         if( this.model == model ) {
 | 
			
		||||
             return;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         if( this.model != null ) {
 | 
			
		||||
             // Clear the old panel
 | 
			
		||||
             getControl(GuiControl.class).getLayout().clearChildren();
 | 
			
		||||
             this.modelRef = null;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         this.model = model;
 | 
			
		||||
 
 | 
			
		||||
         if( this.model != null ) {
 | 
			
		||||
             this.modelRef = model.createReference();
 | 
			
		||||
             refreshGrid();
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public GridModel<Panel> getModel() {
 | 
			
		||||
         return model;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setRow( int row ) {
 | 
			
		||||
         setLocation(row, column);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public int getRow() {
 | 
			
		||||
         return row;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setColumn( int column ) {
 | 
			
		||||
         setLocation(row, column);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public int getColumn() {
 | 
			
		||||
         return column;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public Panel getCell( int r, int c ) {
 | 
			
		||||
         r = r - row;
 | 
			
		||||
         c = c - column;
 | 
			
		||||
         if( r < 0 || c < 0 || r >= visibleRows || c >= visibleColumns ) {
 | 
			
		||||
             return null;
 | 
			
		||||
         }
 | 
			
		||||
         return (Panel)layout.getChild(r, c);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setLocation( int row, int column ) {
 | 
			
		||||
         if( this.row == row && this.column == column ) {
 | 
			
		||||
             return;
 | 
			
		||||
         }
 | 
			
		||||
         this.row = row;
 | 
			
		||||
         this.column = column;
 | 
			
		||||
         refreshGrid();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setVisibleSize( int rows, int columns ) {
 | 
			
		||||
         this.visibleRows = rows;
 | 
			
		||||
         this.visibleColumns = columns;
 | 
			
		||||
         getControl(GuiControl.class).getLayout().clearChildren();
 | 
			
		||||
         refreshGrid();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setVisibleRows( int rows ) {
 | 
			
		||||
         setVisibleSize(rows, visibleColumns);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public int getVisibleRows() {
 | 
			
		||||
         return visibleRows;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setVisibleColumns( int columns ) {
 | 
			
		||||
         setVisibleSize(visibleRows, columns);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public int getVisibleColumns() {
 | 
			
		||||
         return visibleColumns;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setAlpha( float alpha, boolean recursive ) {
 | 
			
		||||
         this.alpha = alpha;
 | 
			
		||||
         super.setAlpha(alpha, recursive);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     protected void refreshGrid() {
 | 
			
		||||
         widthsupdate = false;
 | 
			
		||||
 
 | 
			
		||||
         if( model == null ) {
 | 
			
		||||
             getControl(GuiControl.class).getLayout().clearChildren();
 | 
			
		||||
             return;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         for( int r = row; r < row + visibleRows; r++ ) {
 | 
			
		||||
             for( int c = column; c < column + visibleColumns; c++ ) {
 | 
			
		||||
                 Node existing = layout.getChild(r-row, c-column);
 | 
			
		||||
                 if( r < 0 || r >= model.getRowCount() || c < 0 || c >= model.getColumnCount() ) {
 | 
			
		||||
                     // Out of bounds
 | 
			
		||||
                     layout.addChild(null, r-row, c-column);
 | 
			
		||||
                 } else {
 | 
			
		||||
                     Panel child = model.getCell(r, c, (Panel)existing);
 | 
			
		||||
 
 | 
			
		||||
                     // we check if there is a size for either rowheight or columnwidth stored
 | 
			
		||||
                     Float ytemp = null;
 | 
			
		||||
                     Float xtemp = null;
 | 
			
		||||
 
 | 
			
		||||
                     if (columnwidths !=null) {
 | 
			
		||||
                         if (columnwidths.length > c) {
 | 
			
		||||
                             if (columnwidths[c] != null) xtemp = columnwidths[c];
 | 
			
		||||
                         }
 | 
			
		||||
                     }
 | 
			
		||||
 
 | 
			
		||||
                     if (rowheight != null) {
 | 
			
		||||
                         if (rowheight.length > r) {
 | 
			
		||||
                             if (rowheight[r] !=null) ytemp = rowheight[r];
 | 
			
		||||
                         }
 | 
			
		||||
                     }
 | 
			
		||||
                     // and only if, we set the preferred size
 | 
			
		||||
                     if (ytemp !=null || xtemp != null) {
 | 
			
		||||
                         child.setPreferredSize(null);
 | 
			
		||||
                         if (xtemp != null) child.setPreferredSize(child.getPreferredSize().clone().setX(xtemp));
 | 
			
		||||
                         if (ytemp !=null) child.setPreferredSize(child.getPreferredSize().clone().setY(ytemp));
 | 
			
		||||
                     }
 | 
			
		||||
 
 | 
			
		||||
                     if (columnHalignement != null) {
 | 
			
		||||
                         if (columnHalignement.length > c) {
 | 
			
		||||
                             if (columnHalignement[c] != null) {
 | 
			
		||||
                                 // we only set the alignement for "text" elements attached to the listbox
 | 
			
		||||
                                 // for others e.g. progressbar etc. we should call the element and do the changes there
 | 
			
		||||
                                 if (child instanceof Button) ((Button) child).setTextHAlignment(columnHalignement[c]);
 | 
			
		||||
                                 if (child instanceof Label) ((Label) child).setTextHAlignment(columnHalignement[c]);
 | 
			
		||||
                                 if (child instanceof TextField)
 | 
			
		||||
                                     ((TextField) child).setTextHAlignment(columnHalignement[c]);
 | 
			
		||||
                             } else if (child instanceof Button) ((Button) child).setTextHAlignment(HAlignment.Left);
 | 
			
		||||
                         } else if (child instanceof Button) ((Button) child).setTextHAlignment(HAlignment.Left);
 | 
			
		||||
                     } else if (child instanceof Button) ((Button) child).setTextHAlignment(HAlignment.Left);
 | 
			
		||||
 
 | 
			
		||||
                     if( child != existing ) {
 | 
			
		||||
                         // Make sure new children pick up the alpha of the container
 | 
			
		||||
                         if( alpha != null && alpha != 1 ) {
 | 
			
		||||
                             child.setAlpha(alpha);
 | 
			
		||||
                         }
 | 
			
		||||
 
 | 
			
		||||
                         layout.addChild(child, r-row, c-column);
 | 
			
		||||
                     }
 | 
			
		||||
                 }
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public void updateLogicalState( float tpf ) {
 | 
			
		||||
         super.updateLogicalState(tpf);
 | 
			
		||||
 
 | 
			
		||||
         if( modelRef.update() ) {
 | 
			
		||||
             refreshGrid();
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         if (widthsupdate)  refreshGrid();
 | 
			
		||||
 
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public String toString() {
 | 
			
		||||
         return getClass().getName() + "[elementId=" + getElementId() + "]";
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     public Float[] getColumnwidths() {
 | 
			
		||||
         return columnwidths;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public Float[] getRowheights() {
 | 
			
		||||
         return rowheight;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     public void setRowheight(Float rowheight, int rownumber_starting_with_0){
 | 
			
		||||
         // adds or replaces a columnwidth
 | 
			
		||||
         if (rownumber_starting_with_0 < 0) return;
 | 
			
		||||
         int size = rownumber_starting_with_0+1;
 | 
			
		||||
         if (this.rowheight != null) {
 | 
			
		||||
             size = Math.max(size, this.rowheight.length);
 | 
			
		||||
         }
 | 
			
		||||
         preparegridsizes(size,false);
 | 
			
		||||
         setcheckedsize(rowheight,rownumber_starting_with_0,true,true);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setColumnwidths(Float columnwidth, int columnnumber_starting_with_0) {
 | 
			
		||||
         // adds or replaces a columnwidth
 | 
			
		||||
         if (columnnumber_starting_with_0 <0) return;
 | 
			
		||||
         int size = columnnumber_starting_with_0+1;
 | 
			
		||||
         if (this.columnwidths != null) {
 | 
			
		||||
             size = Math.max(size, this.columnwidths.length);
 | 
			
		||||
         }
 | 
			
		||||
         preparegridsizes(size,true);
 | 
			
		||||
         setcheckedsize(columnwidth,columnnumber_starting_with_0,true,false);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     public void setRowheight (Float[] rowheights_or_null) {
 | 
			
		||||
         // replaces the given rowheights and only keep the number of rows given
 | 
			
		||||
         setRowheight(rowheights_or_null,true);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setColumnwidths (Float[] columnwidths_or_null) {
 | 
			
		||||
         // replaces the given columnwidths and only keep the number of columns given
 | 
			
		||||
         setColumnwidths(columnwidths_or_null,true);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     public void setRowheight(Float[] rowheights_or_null, boolean write_null_values) {
 | 
			
		||||
         // replaces the given rowheights and only keep the number of rows given
 | 
			
		||||
         // null values either overwrite or will be ignored
 | 
			
		||||
         Integer tmp = null;
 | 
			
		||||
         if (rowheights_or_null != null) tmp = rowheights_or_null.length;
 | 
			
		||||
         if (preparegridsizes(tmp,false)) {
 | 
			
		||||
             for (int i = 0; i <tmp;i++) {
 | 
			
		||||
                 setcheckedsize(rowheights_or_null[i],i,write_null_values,true);
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setColumnwidths(Float[] columnwidths_or_null, boolean write_null_values) {
 | 
			
		||||
         // replaces the given columnwidths_or_null and only keep the number of columns given
 | 
			
		||||
         // null values either overwrite or will be ignored
 | 
			
		||||
         Integer tmp = null;
 | 
			
		||||
         if (columnwidths_or_null != null) tmp = columnwidths_or_null.length;
 | 
			
		||||
         if (preparegridsizes(tmp,true)) {
 | 
			
		||||
             for (int i = 0; i <tmp;i++) {
 | 
			
		||||
                 setcheckedsize(columnwidths_or_null[i],i,write_null_values,false);
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     private boolean preparegridsizes(Integer givenfieldsize, boolean width) {
 | 
			
		||||
         // prepares and adjust the size of the field(s) that hold columnwidth or rowheights
 | 
			
		||||
         if (givenfieldsize == null) {
 | 
			
		||||
             if (width) { //either columns or rows will be set null
 | 
			
		||||
                 columnwidths =null;
 | 
			
		||||
             } else {
 | 
			
		||||
                 rowheight = null;
 | 
			
		||||
             }
 | 
			
		||||
             for (Spatial p: this.getChildren()) {
 | 
			
		||||
                 Panel x = (Panel) p;
 | 
			
		||||
                 x.setPreferredSize(null); //we set all sizes to 0 as we will recalculate them with next update
 | 
			
		||||
             }
 | 
			
		||||
             widthsupdate = true;
 | 
			
		||||
             return false; // no more activity needed
 | 
			
		||||
         } else {
 | 
			
		||||
             Float[] tmp;
 | 
			
		||||
             tmp = new Float[givenfieldsize];
 | 
			
		||||
             if (width) {
 | 
			
		||||
                 if (columnwidths == null) {
 | 
			
		||||
                     columnwidths = tmp;
 | 
			
		||||
                     return true;
 | 
			
		||||
                 }
 | 
			
		||||
                 int i = 0;
 | 
			
		||||
                 for (Float z:columnwidths) {
 | 
			
		||||
                     tmp[i] =z;
 | 
			
		||||
                     i++;
 | 
			
		||||
                     if (i>= givenfieldsize) break;
 | 
			
		||||
                 }
 | 
			
		||||
                 columnwidths = tmp; // we get what we have
 | 
			
		||||
             } else {
 | 
			
		||||
                 if (rowheight == null) {
 | 
			
		||||
                     rowheight = tmp;
 | 
			
		||||
                     return true;
 | 
			
		||||
                 }
 | 
			
		||||
                 int i = 0;
 | 
			
		||||
                 for (Float z:rowheight) {
 | 
			
		||||
                     tmp[i] =z;
 | 
			
		||||
                     i++;
 | 
			
		||||
                     if (i>= givenfieldsize) break;
 | 
			
		||||
                 }
 | 
			
		||||
                 rowheight = tmp; // we get what we have
 | 
			
		||||
             }
 | 
			
		||||
             return true;
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void setcheckedsize(Float size, int row_or_column, boolean override, boolean i_am_a_row) {
 | 
			
		||||
         if (override || (size !=null))  {
 | 
			
		||||
             if (i_am_a_row) {
 | 
			
		||||
                 rowheight[row_or_column] = size;
 | 
			
		||||
             } else {
 | 
			
		||||
                 columnwidths[row_or_column] = size;
 | 
			
		||||
             }
 | 
			
		||||
             widthsupdate = true;
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
  //   public void setRowheight(Float rowheight_or_null){
 | 
			
		||||
  //       if (rowheight_or_null<=0) return;
 | 
			
		||||
  //       this.rowheight = rowheight_or_null;
 | 
			
		||||
  //       widthsupdate = true;
 | 
			
		||||
  //   }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
     public void setHalignements(HAlignment[] hals) {
 | 
			
		||||
         setHalignements(hals,false);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setHalignements(HAlignment[] hals, boolean overridestandard) {
 | 
			
		||||
         if (checkexistinghal(hals)) {
 | 
			
		||||
             int i =0;
 | 
			
		||||
             for (HAlignment z:hals) {
 | 
			
		||||
                 setHalignementchecked(z,i,overridestandard);
 | 
			
		||||
                 i++;
 | 
			
		||||
                 if (i>=columnHalignement.length)   return; // we ignore given HAlignement that is out of column bound
 | 
			
		||||
             }
 | 
			
		||||
             if (!overridestandard ) return;
 | 
			
		||||
             for (int u = i; u<columnHalignement.length;u++) {
 | 
			
		||||
                 setHalignementchecked(null,u,overridestandard); // override existing HAlignements
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void setHalignements(HAlignment hal, int column) {
 | 
			
		||||
         checkexistinghal(new HAlignment[]{HAlignment.Center});
 | 
			
		||||
         if (column < columnHalignement.length)  setHalignementchecked(hal,column,true);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private void setHalignementchecked(HAlignment hal, int column,boolean override) {
 | 
			
		||||
         if (override || (hal !=null))  {
 | 
			
		||||
             columnHalignement[column] = hal;
 | 
			
		||||
             widthsupdate = true;
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     private boolean checkexistinghal(HAlignment[] givenfield) {
 | 
			
		||||
         // delete the given Halignements
 | 
			
		||||
         if (givenfield == null) {
 | 
			
		||||
             columnHalignement =null;
 | 
			
		||||
             for (Spatial p: this.getChildren()) {
 | 
			
		||||
                 Button x = (Button)((Panel) p);
 | 
			
		||||
                 x.setTextHAlignment(HAlignment.Left); //standard HAlignement
 | 
			
		||||
             }
 | 
			
		||||
             widthsupdate = true;
 | 
			
		||||
             return false;
 | 
			
		||||
         }
 | 
			
		||||
         // or prepare if we have no columnHalignement yet
 | 
			
		||||
         HAlignment[] tmp;
 | 
			
		||||
         if (columnHalignement == null) {
 | 
			
		||||
             tmp = new HAlignment[model.getColumnCount()];
 | 
			
		||||
             columnHalignement = tmp;
 | 
			
		||||
         } else {
 | 
			
		||||
             if (!(columnHalignement.length ==model.getColumnCount() )) {
 | 
			
		||||
                 tmp = new HAlignment[model.getColumnCount()];
 | 
			
		||||
                 int i = 0;
 | 
			
		||||
                 for (HAlignment z:columnHalignement) {
 | 
			
		||||
                     tmp[i] =z;
 | 
			
		||||
                     i++;
 | 
			
		||||
                     if (i>=model.getColumnCount()) break;
 | 
			
		||||
                 }
 | 
			
		||||
                 columnHalignement = tmp;
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
         return true;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public HAlignment[] getColumnHalignement() {
 | 
			
		||||
         return columnHalignement;
 | 
			
		||||
     }
 | 
			
		||||
 }
 | 
			
		||||
@@ -0,0 +1,135 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2014, Simsilica, LLC
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * 
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions 
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright 
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright 
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in 
 | 
			
		||||
 *    the documentation and/or other materials provided with the 
 | 
			
		||||
 *    distribution.
 | 
			
		||||
 * 
 | 
			
		||||
 * 3. Neither the name of the copyright holder nor the names of its 
 | 
			
		||||
 *    contributors may be used to endorse or promote products derived 
 | 
			
		||||
 *    from this software without specific prior written permission.
 | 
			
		||||
 * 
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 | 
			
		||||
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 | 
			
		||||
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 | 
			
		||||
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 | 
			
		||||
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 | 
			
		||||
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 | 
			
		||||
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 | 
			
		||||
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 | 
			
		||||
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 package pp.monopoly.client.gui.hslider;
 | 
			
		||||
 | 
			
		||||
 import java.util.AbstractList;
 | 
			
		||||
 import java.util.ArrayList;
 | 
			
		||||
 import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.core.VersionedObject;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
  *
 | 
			
		||||
  *  @author    Paul Speed
 | 
			
		||||
  */
 | 
			
		||||
 public class VersionedList<T> extends AbstractList<T>
 | 
			
		||||
                               implements VersionedObject<List<T>> {
 | 
			
		||||
     private long version = 0;
 | 
			
		||||
     private List<T> list;
 | 
			
		||||
 
 | 
			
		||||
     protected VersionedList(List<T> items, boolean copy ) {
 | 
			
		||||
         if( copy ) {
 | 
			
		||||
             list = new ArrayList<T>();
 | 
			
		||||
             list.addAll(items);
 | 
			
		||||
         } else {
 | 
			
		||||
             this.list = items;
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public VersionedList() {
 | 
			
		||||
         this(new ArrayList<T>(), false);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public VersionedList(List<T> items ) {
 | 
			
		||||
         this(items, true);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     /**
 | 
			
		||||
      *  Wraps a list in a VersionedList instead of copying it.
 | 
			
		||||
      *  This is useful for cases where a VersionedList is required
 | 
			
		||||
      *  but strict versioning is not, for example, passing a static list
 | 
			
		||||
      *  to a ListBox.  Changes to the wrapped list obviously don't
 | 
			
		||||
      *  trigger version changes in the wrapper.  Only changes through
 | 
			
		||||
      *  the wrapper will increment the version.
 | 
			
		||||
      */
 | 
			
		||||
     public static <T> VersionedList<T> wrap( List<T> list ) {
 | 
			
		||||
         return new VersionedList<T>(list, false);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public void incrementVersion() { // changed this to public
 | 
			
		||||
         version++;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public long getVersion() {
 | 
			
		||||
         return version;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public List<T> getObject() {
 | 
			
		||||
         return this;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public VersionedReference<List<T>> createReference() {
 | 
			
		||||
         return new VersionedReference<List<T>>(this);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public T get( int i ) {
 | 
			
		||||
         return list.get(i);
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public int size() {
 | 
			
		||||
         return list.size();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public T set( int i, T val ) {
 | 
			
		||||
         T result = list.set(i, val);
 | 
			
		||||
         incrementVersion();
 | 
			
		||||
         return result;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public void add( int i, T val ) {
 | 
			
		||||
         list.add(i, val);
 | 
			
		||||
         incrementVersion();
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public T remove( int i ) {
 | 
			
		||||
         T result = list.remove(i);
 | 
			
		||||
         incrementVersion();
 | 
			
		||||
         return result;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,144 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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>
 | 
			
		||||
 */
 | 
			
		||||
public class AcceptTrade extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the dialog. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Container for the warning message content. */
 | 
			
		||||
    private final Container noMoneyWarningContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the accept trade dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     * @param msg the trade reply message containing details about the trade
 | 
			
		||||
     */
 | 
			
		||||
    public AcceptTrade(MonopolyApp app, TradeReply msg) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        noMoneyWarningContainer = new Container();
 | 
			
		||||
        noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Handel angenommen!", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast Spieler"+ msg.getTradeHandler().getReceiver().getName() + "einen Handel vorgeschlagen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Der Handel wurde angenommen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @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 dialog and removes the associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape key action by closing the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,132 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn
 | 
			
		||||
 */
 | 
			
		||||
public class Bankrupt extends Dialog {
 | 
			
		||||
    /** 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 bankruptcy warning content. */
 | 
			
		||||
    private final Container bankruptContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the bankruptcy warning popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public Bankrupt(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        bankruptContainer = new Container();
 | 
			
		||||
        bankruptContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        bankruptContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = bankruptContainer.addChild(new Label("Vorsicht !", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = bankruptContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast noch einen negativen Kontostand. Wenn du jetzt deinen Zug beendest, gehst du Bankrott und verlierst das Spiel!", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = bankruptContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(this::close));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        bankruptContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(bankruptContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 menu and removes the GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(bankruptContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape key action by closing the popup.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,7 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
@@ -13,41 +10,52 @@ import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO Kommentare fixen
 | 
			
		||||
 * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
 | 
			
		||||
 * BuildingPropertyCard creates the popup for field information
 | 
			
		||||
 */
 | 
			
		||||
public class BuildingPropertyCard extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private final Container buildingPropertyContainer;
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private int index = 37;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the building property information. */
 | 
			
		||||
    private final Container buildingPropertyContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the property card. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a property card popup displaying details about the building property.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public BuildingPropertyCard(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        BuildingProperty field = (BuildingProperty) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        //Generate the corresponding field
 | 
			
		||||
        int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
 | 
			
		||||
        BuildingProperty field = (BuildingProperty) new BoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
        buildingPropertyContainer = new Container();
 | 
			
		||||
        buildingPropertyContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des buildingPropertyContainer an
 | 
			
		||||
        backgroundContainer.setPreferredSize(buildingPropertyContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        Label settingsTitle = buildingPropertyContainer.addChild(new Label( field.getName(), new ElementId("settings-title")));
 | 
			
		||||
        //Titel
 | 
			
		||||
        Label settingsTitle = buildingPropertyContainer.addChild(new Label( field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        settingsTitle.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
 | 
			
		||||
        settingsTitle.setFontSize(48);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
@@ -66,28 +74,31 @@ public class BuildingPropertyCard extends Dialog {
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        //TODO eventuell diese Stelle löschen, da nur die BuyCard Kaufen und beenden hat
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        Button quitButton = buildingPropertyContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            System.err.println("Button does something?");
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
        Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        Button buyButton = buildingPropertyContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
         */
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
            app.getGameLogic().send(new BuyPropertyResponse());
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Padding around the settingsContainer for the background
 | 
			
		||||
        backgroundContainer.setPreferredSize(buildingPropertyContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        buildingPropertyContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
@@ -98,38 +109,20 @@ public class BuildingPropertyCard extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt einen halbtransparenten Hintergrund für das Menü.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Geometrie des Overlays
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Schließt das Menü und entfernt die GUI-Elemente.
 | 
			
		||||
     * 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(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void setIndex(int index) {
 | 
			
		||||
        this.index = index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,128 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
 | 
			
		||||
 */
 | 
			
		||||
public class BuyCard extends Dialog {
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private final Container buyCardContainer;
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    private int index = 37;
 | 
			
		||||
 | 
			
		||||
    public BuyCard(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        BuildingProperty field = (BuildingProperty) new BoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
        buyCardContainer = new Container();
 | 
			
		||||
        buyCardContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Label settingsTitle = buyCardContainer.addChild(new Label( field.getName(), new ElementId("settings-title")));
 | 
			
		||||
        settingsTitle.setFontSize(48);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Preise werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        Container propertyValuesContainer = buyCardContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 1 Haus: " + field.getAllRent().get(1) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 2 Häuser: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 3 Häuser: " + field.getAllRent().get(3) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 4 Häuser: " + field.getAllRent().get(4) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 1 Hotel: " + field.getAllRent().get(5) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = buyCardContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
        Button buyButton = buyCardContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Padding around the settingsContainer for the background
 | 
			
		||||
        backgroundContainer.setPreferredSize(buyCardContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        buyCardContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(buyCardContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt einen halbtransparenten Hintergrund für das Menü.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Geometrie des Overlays
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Schließt das Menü und entfernt die GUI-Elemente.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(buyCardContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,247 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.message.client.AlterProperty;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * BuyHouse is a popup which appears when a player clicks on the "Buy House"-button in the BuildingAdminMenu
 | 
			
		||||
 */
 | 
			
		||||
public class BuyHouse extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the "Buy House" popup UI. */
 | 
			
		||||
    private final Container buyHouseContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** TextField to display selected properties. */
 | 
			
		||||
    private TextField selectionDisplay;
 | 
			
		||||
 | 
			
		||||
    /** Reference for tracking dropdown selection changes. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
 | 
			
		||||
    /** Dropdown selector for choosing properties to build houses on. */
 | 
			
		||||
    private Selector<String> propertySelector;
 | 
			
		||||
 | 
			
		||||
    /** Set of selected properties for house purchase. */
 | 
			
		||||
    private Set<String> selectedProperties = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    /** Label displaying the total cost of building houses on the selected properties. */
 | 
			
		||||
    private Label cost = new Label("0", new ElementId("label-Text"));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the "Buy House" popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public BuyHouse(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Main container for the menu
 | 
			
		||||
        buyHouseContainer = new Container();
 | 
			
		||||
        buyHouseContainer.setPreferredSize(new Vector3f(800, 600, 0));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Adjust backgroundContainer size to match buyHouseContainer
 | 
			
		||||
        backgroundContainer.setPreferredSize(buyHouseContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = buyHouseContainer.addChild(new Label("Gebäude Kaufen", new ElementId("warning-Bold")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Divide buyHouseContainer into three sub-containers
 | 
			
		||||
        Container upContainer = buyHouseContainer.addChild(new Container());
 | 
			
		||||
        Container middleContainer = buyHouseContainer.addChild(new Container());
 | 
			
		||||
        Container downContainer = buyHouseContainer.addChild(new Container());
 | 
			
		||||
 | 
			
		||||
        // Upper section text
 | 
			
		||||
        upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
 | 
			
		||||
        upContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
 | 
			
		||||
        upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
 | 
			
		||||
        middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
 | 
			
		||||
        // Add the property selector dropdown
 | 
			
		||||
        middleContainer.addChild(createPropertyDropdown());
 | 
			
		||||
 | 
			
		||||
        downContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
 | 
			
		||||
        downContainer.addChild(new Label("Kosten:", new ElementId("label-Text"))); // Label for cost
 | 
			
		||||
        downContainer.addChild(cost); // Cost details
 | 
			
		||||
        downContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Cancel button
 | 
			
		||||
        Button cancelButton = buyHouseContainer.addChild(new Button("Abbrechen", new ElementId("button")));
 | 
			
		||||
        cancelButton.setFontSize(32);
 | 
			
		||||
        cancelButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Confirm button
 | 
			
		||||
        Button confirmButton = buyHouseContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            AlterProperty msg = new AlterProperty("BuyHouse");
 | 
			
		||||
            msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
 | 
			
		||||
            app.getGameLogic().send(msg);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Center the popup
 | 
			
		||||
        buyHouseContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - buyHouseContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + buyHouseContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                9
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - buyHouseContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + buyHouseContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(buyHouseContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a dropdown menu for selecting properties eligible for house construction.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The container holding the dropdown menu.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createPropertyDropdown() {
 | 
			
		||||
        Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> propertyOptions = new VersionedList<>();
 | 
			
		||||
        List<BuildingProperty> playerProperties = getPlayerProperties();
 | 
			
		||||
 | 
			
		||||
        // Populate the dropdown with property names
 | 
			
		||||
        for (BuildingProperty property : playerProperties) {
 | 
			
		||||
            propertyOptions.add(property.getName());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        propertySelector = new Selector<>(propertyOptions, "glass");
 | 
			
		||||
        dropdownContainer.addChild(propertySelector);
 | 
			
		||||
 | 
			
		||||
        // Track selection changes
 | 
			
		||||
        selectionRef = propertySelector.getSelectionModel().createReference();
 | 
			
		||||
 | 
			
		||||
        // Initialize the selection display here
 | 
			
		||||
        selectionDisplay = new TextField(""); // Create TextField for displaying selections
 | 
			
		||||
        selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
 | 
			
		||||
        dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
 | 
			
		||||
 | 
			
		||||
        // Set initial selection
 | 
			
		||||
        if (!propertyOptions.isEmpty()) {
 | 
			
		||||
            onDropdownSelectionChanged(propertySelector);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return dropdownContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the list of properties owned by the current player that are eligible for house construction.
 | 
			
		||||
     *
 | 
			
		||||
     * @return A list of {@link BuildingProperty} objects owned by the player.
 | 
			
		||||
     */
 | 
			
		||||
    private List<BuildingProperty> getPlayerProperties() {
 | 
			
		||||
        Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
 | 
			
		||||
        BoardManager boardManager = app.getGameLogic().getBoardManager();
 | 
			
		||||
 | 
			
		||||
        return boardManager.getPropertyFields(self.getProperties()).stream()
 | 
			
		||||
                           .filter(property -> property instanceof BuildingProperty)
 | 
			
		||||
                           .map(property -> (BuildingProperty) property)
 | 
			
		||||
                           .filter(property -> app.getGameLogic().getBoardManager().canBuild(property))
 | 
			
		||||
                           .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Periodically updates the popup, tracking selection changes in the dropdown menu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta Time since the last update in seconds.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        if(selectionRef.update()) {
 | 
			
		||||
            onDropdownSelectionChanged(propertySelector);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles property selection changes in the dropdown menu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerProperties the dropdown selector for the player's properties
 | 
			
		||||
     */
 | 
			
		||||
    private void onDropdownSelectionChanged(Selector<String> playerProperties) {
 | 
			
		||||
        String selected = playerProperties.getSelectedItem();
 | 
			
		||||
        app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        if (selectedProperties.contains(selected)) {
 | 
			
		||||
            selectedProperties.remove(selected);
 | 
			
		||||
        } else {
 | 
			
		||||
            selectedProperties.add(selected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int cost = 0;
 | 
			
		||||
        for (String s : selectedProperties) {
 | 
			
		||||
            cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String display = String.join(" | ", selectedProperties);
 | 
			
		||||
        selectionDisplay.setText(display);
 | 
			
		||||
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(buyHouseContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,151 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.client.gui.TradeMenu;
 | 
			
		||||
import pp.monopoly.message.client.TradeResponse;
 | 
			
		||||
import pp.monopoly.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ConfirmTrade is a popup which appears when a trade is proposed to this certain player.
 | 
			
		||||
 */
 | 
			
		||||
public class ConfirmTrade extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the "Confirm Trade" popup UI. */
 | 
			
		||||
    private final Container confirmTradeContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** The trade handler managing the details of the trade proposal. */
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the "Confirm Trade" popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public ConfirmTrade(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        tradeHandler = app.getGameLogic().getTradeHandler();
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        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.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        StringBuilder offeredProperties = new StringBuilder();
 | 
			
		||||
        for (PropertyField field : tradeHandler.getOfferedProperties()) {
 | 
			
		||||
            offeredProperties.append(field.getName());
 | 
			
		||||
            offeredProperties.append(", ");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        StringBuilder requestedProperties = new StringBuilder();
 | 
			
		||||
        for (PropertyField field : tradeHandler.getRequestedProperties()) {
 | 
			
		||||
            requestedProperties.append(field.getName());
 | 
			
		||||
            requestedProperties.append(", ");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Werte werden dem Handel entnommen (Iwas auch immer da dann ist)
 | 
			
		||||
        Container propertyValuesContainer = confirmTradeContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Spieler " + tradeHandler.getSender().getName() + " möchte:", new ElementId("label-Text"))); 
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + offeredProperties, new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedAmount() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedJailCards() +" Sonderkaten", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("gegen:", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- "+ requestedProperties, new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedAmount() +" EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedJailCards() +" Sonderkaten", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("tauschen, willst du das Angebot annehmen?", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Ablehnen-Button
 | 
			
		||||
        Button declineButton = confirmTradeContainer.addChild(new Button("Ablehnen", new ElementId("button")));
 | 
			
		||||
        declineButton.setFontSize(32);
 | 
			
		||||
        declineButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new TradeResponse(false, tradeHandler));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Verhandeln-Button
 | 
			
		||||
        Button negotiateButton = confirmTradeContainer.addChild(new Button("Verhandeln", new ElementId("button")));
 | 
			
		||||
        negotiateButton.setFontSize(32);
 | 
			
		||||
        negotiateButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
            TradeHandler t = new TradeHandler(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getSender().getId()));
 | 
			
		||||
            t.setReceiver(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getReceiver().getId()));
 | 
			
		||||
            new TradeMenu(app, t).open();
 | 
			
		||||
        }));
 | 
			
		||||
        // Confirm-Button
 | 
			
		||||
        Button confirmButton = confirmTradeContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new TradeResponse(true, tradeHandler));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        confirmTradeContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(confirmTradeContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(confirmTradeContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -13,25 +13,37 @@ import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.model.card.Card; // TODO für den Import der Queue notwendig
 | 
			
		||||
import pp.monopoly.model.card.DeckHelper;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
 | 
			
		||||
 * EventCardPopup is a popup which appears when a certain EventCard is triggered by entering a EventCardField
 | 
			
		||||
 */
 | 
			
		||||
public class EventCard extends Dialog {
 | 
			
		||||
public class EventCardPopup extends Dialog {
 | 
			
		||||
    /** 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 event card information. */
 | 
			
		||||
    private final Container eventCardContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** The description of the event card. */
 | 
			
		||||
    private final String description;
 | 
			
		||||
 | 
			
		||||
    public EventCard(MonopolyApp app) {
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the EventCardPopup to display the details of a triggered event card.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app         the Monopoly application instance
 | 
			
		||||
     * @param description the description of the triggered event card
 | 
			
		||||
     */
 | 
			
		||||
    public EventCardPopup(MonopolyApp app, String description) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        Card card = new DeckHelper().drawCard(); // TODO nimmt die Karten gerade unabhängig aus dem DeckHelper
 | 
			
		||||
        this.description = description;
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
@@ -42,64 +54,61 @@ public class EventCard extends Dialog {
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
 | 
			
		||||
        eventCardContainer = new Container();
 | 
			
		||||
        eventCardContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        eventCardContainer.setPreferredSize(new Vector3f(550,400,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        // Die Namen werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        Label gateFieldTitle = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Preise werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        // Die Erklärungsfelder werden automatisch den descriptions der Message entnommen
 | 
			
		||||
        Container propertyValuesContainer = eventCardContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label(card.getDescription(), new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label(description, new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        propertyValuesContainer.setPreferredSize(new Vector3f(300,200,10));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> close());
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // TODO Kaufen-Button wird nicht mehr benötigt, prüfen ob weg kann
 | 
			
		||||
        //Button buyButton = buyCardContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        //buyButton.setFontSize(32);
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Padding around the settingsContainer for the background
 | 
			
		||||
        backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        eventCardContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
            10
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
                9
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(eventCardContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt einen halbtransparenten Hintergrund für das Menü.
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Geometrie des Overlays
 | 
			
		||||
     * @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.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f));
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
@@ -107,18 +116,21 @@ public class EventCard extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Schließt das Menü und entfernt die GUI-Elemente.
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(eventCardContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        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() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
@@ -13,45 +14,55 @@ import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
import pp.monopoly.model.fields.FoodField;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * FoodFieldCard erstellt die Geböudekarte vom Brandl und der Truppenküche
 | 
			
		||||
 * FoodFieldCard creates the popup for field information
 | 
			
		||||
 */
 | 
			
		||||
public class FoodFieldCard extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private final Container foodFieldContainer;
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private int index = 12;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the food field information. */
 | 
			
		||||
    private final Container foodFieldContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a FoodFieldCard popup displaying details about a food field.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public FoodFieldCard(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
 | 
			
		||||
        FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
        foodFieldContainer = new Container();
 | 
			
		||||
        foodFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
 | 
			
		||||
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe
 | 
			
		||||
        Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title")));
 | 
			
		||||
        Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        settingsTitle.setFontSize(48);
 | 
			
		||||
        settingsTitle.setColor(ColorRGBA.White);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        Container propertyValuesContainer = foodFieldContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile
 | 
			
		||||
@@ -68,29 +79,30 @@ public class FoodFieldCard extends Dialog {
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        //TODO eventuell diese Stelle löschen, da nur die BuyCard Kaufen und beenden hat
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
        Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
         */
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new BuyPropertyResponse());
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Padding around the settingsContainer for the background
 | 
			
		||||
        backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        foodFieldContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
@@ -101,9 +113,9 @@ public class FoodFieldCard extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt einen halbtransparenten Hintergrund für das Menü.
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Geometrie des Overlays
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
@@ -117,7 +129,7 @@ public class FoodFieldCard extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Schließt das Menü und entfernt die GUI-Elemente.
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
@@ -127,10 +139,9 @@ public class FoodFieldCard extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setIndex(int index) {
 | 
			
		||||
        this.index = index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
@@ -12,41 +13,50 @@ import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
import pp.monopoly.model.fields.GateField;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
 | 
			
		||||
 * GateFieldCard creates the popup for field information
 | 
			
		||||
 */
 | 
			
		||||
public class GateFieldCard extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private final Container gateFieldContainer;
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private int index = 5;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the gate field information. */
 | 
			
		||||
    private final Container gateFieldContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a GateFieldCard popup displaying details about a gate field.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public GateFieldCard(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
 | 
			
		||||
        GateField field = (GateField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
        gateFieldContainer = new Container();
 | 
			
		||||
        gateFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        // Die Namen werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title")));
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des gateFieldContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe
 | 
			
		||||
        Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
@@ -55,36 +65,41 @@ public class GateFieldCard extends Dialog {
 | 
			
		||||
        Container propertyValuesContainer = gateFieldContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 1 Bahnhof besitzt: 250 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 2 Bahnhöfe besitzt: 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 3 Bahnhöfe besitzt: 1000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 4 Bahnhöfe besitzt: 2000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete: 250 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("2 Bahnhof besitzt: 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("3 Bahnhof besitzt: 1000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("4 Bahnhof besitzt: 2000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        //TODO eventuell diese Stelle löschen, da nur die BuyCard Kaufen und beenden hat
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        Button quitButton = gateFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
        Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        Button buyButton = gateFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
         */
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new BuyPropertyResponse());
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Padding around the settingsContainer for the background
 | 
			
		||||
        backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        gateFieldContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
                (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
@@ -95,9 +110,9 @@ public class GateFieldCard extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt einen halbtransparenten Hintergrund für das Menü.
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Geometrie des Overlays
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
@@ -111,20 +126,18 @@ public class GateFieldCard extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Schließt das Menü und entfernt die GUI-Elemente.
 | 
			
		||||
     * 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(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setIndex(int index) {
 | 
			
		||||
        this.index = index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,132 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 {
 | 
			
		||||
    /** 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 Gulag warning message. */
 | 
			
		||||
    private final Container gulagContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Gulag popup, displaying a warning when a player lands on the "Wache" field.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public Gulag(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        gulagContainer = new Container();
 | 
			
		||||
        gulagContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        gulagContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(gulagContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = gulagContainer.addChild(new Label("Du kommst ins Gulag!", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        gulagContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - gulagContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - gulagContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gulagContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(gulagContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the popup.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,136 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.NotificationAnswer;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the Gulag information dialog. */
 | 
			
		||||
    private final Container gulagInfoContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a styled border around the dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a GulagInfo popup that provides the player with options for getting out of the "Gulag" field.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     * @param trys the number of failed attempts to roll doubles for release
 | 
			
		||||
     */
 | 
			
		||||
    public GulagInfo(MonopolyApp app, int trys) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für das Bestätigungspopup
 | 
			
		||||
        gulagInfoContainer = new Container();
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des confirmTradeContainer an
 | 
			
		||||
        backgroundContainer.setPreferredSize(gulagInfoContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label title = gulagInfoContainer.addChild(new Label( "Gulag", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Werte werden dem Handel entnommen (Iwas auch immer da dann ist)
 | 
			
		||||
        Container propertyValuesContainer = gulagInfoContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Du sitzt im Gefänginis und kommst nicht raus ...", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Es sei denn, du ...", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- bestichst die Wache mit 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- löst eine Gulag-Frei-Karte ein", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- wartest 3 Runden und bezahlst dann", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- oder du würfelst einen Pasch", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Bezahlen-Button
 | 
			
		||||
        Button payButton = gulagInfoContainer.addChild(new Button("Bestechungsgeld bezahlen", new ElementId("button")));
 | 
			
		||||
        payButton.setFontSize(32);
 | 
			
		||||
        payButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new NotificationAnswer("PayJail"));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Ereigniskarte-Button
 | 
			
		||||
        Button eventCardButton = gulagInfoContainer.addChild(new Button("Ereigniskarte nutzen", new ElementId("button")));
 | 
			
		||||
        eventCardButton.setFontSize(32);
 | 
			
		||||
        eventCardButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new NotificationAnswer("UseJailCard"));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Schließen-Button
 | 
			
		||||
        Button closeButton = gulagInfoContainer.addChild(new Button("Schließen", new ElementId("button")));
 | 
			
		||||
        closeButton.setFontSize(32);
 | 
			
		||||
        closeButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        gulagInfoContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if(app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getNumJailCard() == 0) {
 | 
			
		||||
            eventCardButton.setEnabled(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(trys == 3) {
 | 
			
		||||
            closeButton.setEnabled(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(gulagInfoContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the GulagInfo dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,52 +1,145 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.IconComponent;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the dialog. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the "Looser" dialog UI. */
 | 
			
		||||
    private final Container LooserContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a styled border around the main dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new NetworkDialog.
 | 
			
		||||
     * Constructs a new WinnerPopUp dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param network The NetworkSupport instance to be used for network operations.
 | 
			
		||||
     * @param app The MonopolyApp instance.
 | 
			
		||||
     */
 | 
			
		||||
    public LooserPopUp(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        initializeDialog();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        LooserContainer = new Container();
 | 
			
		||||
        LooserContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        LooserContainer.setPreferredSize(new Vector3f(355,600,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(LooserContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label looserTitle = LooserContainer.addChild(new Label("Schade, du hast leider verloren, die nächste Runde wird besser!", new ElementId("header")));
 | 
			
		||||
        looserTitle.setFontSize(25);
 | 
			
		||||
        // looserTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
        // Create the image container
 | 
			
		||||
        Container imageContainer = LooserContainer.addChild(new Container());
 | 
			
		||||
        imageContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Dark gray background
 | 
			
		||||
        imageContainer.setPreferredSize(LooserContainer.getPreferredSize().addLocal(-250, -200, 0)); // Adjust size for layout
 | 
			
		||||
 | 
			
		||||
        // Add the image to the container
 | 
			
		||||
        Label imageLabel = new Label(""); // Create a label for the image
 | 
			
		||||
        IconComponent icon = new IconComponent("Pictures/MonopolyLooser.png"); // Load the image as an icon
 | 
			
		||||
        icon.setIconScale(0.7f); // Scale the image appropriately
 | 
			
		||||
        imageLabel.setIcon(icon);
 | 
			
		||||
        imageContainer.addChild(imageLabel); // Add the image label to the container
 | 
			
		||||
 | 
			
		||||
        //Beenden Button
 | 
			
		||||
        Button quitButton = LooserContainer.addChild(new Button("Spiel Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.closeApp();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        LooserContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - LooserContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + LooserContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - LooserContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + LooserContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(LooserContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the dialog with input fields and connection buttons.
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The overlay geometry.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeDialog() {
 | 
			
		||||
        Container inputContainer = new Container();
 | 
			
		||||
 | 
			
		||||
        // Titel und Eingabefelder für Host und Port
 | 
			
		||||
        inputContainer.addChild(new Label("Schade, du hast leider verloren!"));
 | 
			
		||||
        inputContainer.addChild(new Label("Die nächste Runde wird besser!"));
 | 
			
		||||
 | 
			
		||||
        Label imageLabel = new Label("");
 | 
			
		||||
        IconComponent icon = new IconComponent("Pictures/MonopolyLooser.png"); // Icon mit Textur erstellen
 | 
			
		||||
        icon.setIconScale(1); // Skalierung des Bildes
 | 
			
		||||
        imageLabel.setIcon(icon);
 | 
			
		||||
 | 
			
		||||
        // Setze das Icon im Label
 | 
			
		||||
        inputContainer.addChild(imageLabel);
 | 
			
		||||
 | 
			
		||||
        Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
 | 
			
		||||
        cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
 | 
			
		||||
        
 | 
			
		||||
        inputContainer.setLocalTranslation(300, 800, 0);
 | 
			
		||||
        app.getGuiNode().attachChild(inputContainer);
 | 
			
		||||
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the LooserPopUp dialog and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(LooserContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,137 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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>
 | 
			
		||||
 */
 | 
			
		||||
public class NoMoneyWarning extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the warning popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the NoMoneyWarning dialog UI. */
 | 
			
		||||
    private final Container noMoneyWarningContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a styled border around the main dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new NoMoneyWarning dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The MonopolyApp instance.
 | 
			
		||||
     */
 | 
			
		||||
    public NoMoneyWarning(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        noMoneyWarningContainer = new Container();
 | 
			
		||||
        noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Na, schon wieder Pleite?", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(38);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast nicht genug Geld, um dieses Gebäude zu kaufen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> close());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background for the dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The geometry representing the overlay background.
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the menu and removes the GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,167 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Rent 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 ReceivedRent extends Dialog {
 | 
			
		||||
    /** 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.
 | 
			
		||||
     *
 | 
			
		||||
     * @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
 | 
			
		||||
     */
 | 
			
		||||
    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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the overlay geometry
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container with styling.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the styled background container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createBackgroundContainer() {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main rent container with title, text, and button.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerName the name of the player to whom the rent is owed
 | 
			
		||||
     * @param amount     the rent amount
 | 
			
		||||
     * @return the rent container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createRentContainer(String playerName, int amount) {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = container.addChild(new Label("Miete!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Rent message
 | 
			
		||||
        Container textContainer = container.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du bekommst von Spieler " + playerName + " " + 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));
 | 
			
		||||
 | 
			
		||||
        // 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();
 | 
			
		||||
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Centers the rent and background containers on the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void centerContainers() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Center rent container
 | 
			
		||||
        rentContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - rentContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + rentContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Center background container with padding
 | 
			
		||||
        backgroundContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(rentContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,145 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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>
 | 
			
		||||
 */
 | 
			
		||||
public class RejectTrade extends Dialog {
 | 
			
		||||
    /** 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 rejection message content. */
 | 
			
		||||
    private final Container noMoneyWarningContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the RejectTrade popup displaying the rejection of a trade proposal.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     * @param msg the trade reply message containing details about the rejected trade
 | 
			
		||||
     */
 | 
			
		||||
    public RejectTrade(MonopolyApp app, TradeReply msg) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        noMoneyWarningContainer = new Container();
 | 
			
		||||
        noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Handel abgelehnt!", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast Spieler"+ msg.getTradeHandler().getReceiver().getName() + "einen Handel vorgeschlagen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Der Handel wurde abgelehnt", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 menu and removes the GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape key action by closing the popup.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,167 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Rent 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 {
 | 
			
		||||
    /** 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.
 | 
			
		||||
     *
 | 
			
		||||
     * @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
 | 
			
		||||
     */
 | 
			
		||||
    public Rent(MonopolyApp app, String playerName, int amount) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the overlay
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create and position the background container
 | 
			
		||||
        backgroundContainer = createBackgroundContainer();
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Create and position the rent container
 | 
			
		||||
        rentContainer = createRentContainer(playerName, amount);
 | 
			
		||||
        app.getGuiNode().attachChild(rentContainer);
 | 
			
		||||
 | 
			
		||||
        centerContainers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the overlay geometry
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container with styling.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the styled background container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createBackgroundContainer() {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main rent container with title, text, and button.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerName the name of the player to whom the rent is owed
 | 
			
		||||
     * @param amount     the rent amount
 | 
			
		||||
     * @return the rent container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createRentContainer(String playerName, int amount) {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = container.addChild(new Label("Miete!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Rent message
 | 
			
		||||
        Container textContainer = container.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du musst Spieler " + playerName + " " + amount + " EUR Miete zahlen",
 | 
			
		||||
                new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
 | 
			
		||||
        // Payment button
 | 
			
		||||
        Button payButton = container.addChild(new Button("Überweisen", new ElementId("button")));
 | 
			
		||||
        payButton.setFontSize(32);
 | 
			
		||||
        payButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
                app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
                close();
 | 
			
		||||
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Centers the rent and background containers on the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void centerContainers() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Center rent container
 | 
			
		||||
        rentContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - rentContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + rentContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Center background container with padding
 | 
			
		||||
        backgroundContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(rentContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,251 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.message.client.AlterProperty;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * RepayMortage is a popup 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. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the mortgage repayment menu. */
 | 
			
		||||
    private final Container repayMortageContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** Text field to display selected properties. */
 | 
			
		||||
    private TextField selectionDisplay;
 | 
			
		||||
 | 
			
		||||
    /** Reference to track property selections in the dropdown menu. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
 | 
			
		||||
    /** Dropdown menu for selecting mortgaged properties. */
 | 
			
		||||
    private Selector<String> propertySelector;
 | 
			
		||||
 | 
			
		||||
    /** Set of selected properties for mortgage repayment. */
 | 
			
		||||
    private Set<String> selectedProperties = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    /** Label displaying the total repayment cost. */
 | 
			
		||||
    private Label cost = new Label("0", new ElementId("label-Text"));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the RepayMortage popup for handling mortgage repayment.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    public RepayMortage(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für das Menü
 | 
			
		||||
        repayMortageContainer = new Container();
 | 
			
		||||
        repayMortageContainer.setPreferredSize(new Vector3f(800, 600, 0));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des sellhouseContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(repayMortageContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label title = repayMortageContainer.addChild(new Label( "Hypothek Abbezahlen", new ElementId("warining-Bold")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        //Unterteilund des sellHouseContainer in drei "Untercontainer"
 | 
			
		||||
        Container upContainer = repayMortageContainer.addChild(new Container());
 | 
			
		||||
        Container middleContainer = repayMortageContainer.addChild(new Container());
 | 
			
		||||
        Container downContainer = repayMortageContainer.addChild(new Container());
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
 | 
			
		||||
        upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
 | 
			
		||||
        middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
 | 
			
		||||
        middleContainer.addChild(createPropertyDropdown());
 | 
			
		||||
 | 
			
		||||
        downContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        downContainer.addChild(new Label("Kosten:", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        downContainer.addChild(cost);
 | 
			
		||||
        downContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button cancelButton = repayMortageContainer.addChild(new Button("Abbrechen", new ElementId("button")));
 | 
			
		||||
        cancelButton.setFontSize(32);
 | 
			
		||||
        cancelButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
        Button confirmButton = repayMortageContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            AlterProperty msg = new AlterProperty("RepayMortage");
 | 
			
		||||
            msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
 | 
			
		||||
            app.getGameLogic().send(msg);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        repayMortageContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - repayMortageContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + repayMortageContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            9
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - repayMortageContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + repayMortageContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(repayMortageContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a dropdown menu for selecting a property.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The dropdown container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createPropertyDropdown() {
 | 
			
		||||
        Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> propertyOptions = new VersionedList<>();
 | 
			
		||||
        List<PropertyField> playerProperties = getPlayerProperties();
 | 
			
		||||
 | 
			
		||||
        // Populate the dropdown with property names
 | 
			
		||||
        for (PropertyField property : playerProperties) {
 | 
			
		||||
            propertyOptions.add(property.getName());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        propertySelector = new Selector<>(propertyOptions, "glass");
 | 
			
		||||
        dropdownContainer.addChild(propertySelector);
 | 
			
		||||
 | 
			
		||||
        // Track selection changes
 | 
			
		||||
        selectionRef = propertySelector.getSelectionModel().createReference();
 | 
			
		||||
 | 
			
		||||
        // Initialize the selection display here
 | 
			
		||||
        selectionDisplay = new TextField(""); // Create TextField for displaying selections
 | 
			
		||||
        selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
 | 
			
		||||
        dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
 | 
			
		||||
 | 
			
		||||
        // Set initial selection
 | 
			
		||||
        if (!propertyOptions.isEmpty()) {
 | 
			
		||||
            onDropdownSelectionChanged(propertySelector);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return dropdownContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the list of properties owned by the current player.
 | 
			
		||||
     *
 | 
			
		||||
     * @return List of PropertyField objects owned by the player.
 | 
			
		||||
     */
 | 
			
		||||
    private List<PropertyField> getPlayerProperties() {
 | 
			
		||||
        Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
 | 
			
		||||
        BoardManager boardManager = app.getGameLogic().getBoardManager();
 | 
			
		||||
 | 
			
		||||
        return boardManager.getPropertyFields(self.getProperties()).stream()
 | 
			
		||||
                           .filter(property -> property instanceof PropertyField)
 | 
			
		||||
                           .map(property -> (PropertyField) property)
 | 
			
		||||
                           .filter(p -> p.isMortgaged())
 | 
			
		||||
                           .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the UI based on selection changes in the dropdown menu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta the time elapsed since the last update
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        if(selectionRef.update()) {
 | 
			
		||||
            onDropdownSelectionChanged(propertySelector);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles changes in the property selection and updates the total repayment cost.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerProperties the dropdown menu for selecting properties
 | 
			
		||||
     */
 | 
			
		||||
    private void onDropdownSelectionChanged(Selector<String> playerProperties) {
 | 
			
		||||
        String selected = playerProperties.getSelectedItem();
 | 
			
		||||
        app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        if (selectedProperties.contains(selected)) {
 | 
			
		||||
            selectedProperties.remove(selected);
 | 
			
		||||
        } else {
 | 
			
		||||
            selectedProperties.add(selected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int cost = 0;
 | 
			
		||||
        for (String s : selectedProperties) {
 | 
			
		||||
            cost += ((PropertyField) app.getGameLogic().getBoardManager().getFieldByName(s)).getHypo();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String display = String.join(" | ", selectedProperties);
 | 
			
		||||
        selectionDisplay.setText(display);
 | 
			
		||||
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(repayMortageContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,260 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector2f;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Checkbox;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.ListBox;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.IconComponent;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.message.client.AlterProperty;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SellHouse is a popup 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. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the SellHouse dialog UI. */
 | 
			
		||||
    private final Container sellhouseContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a styled border around the main dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** Text field to display selected properties. */
 | 
			
		||||
    private TextField selectionDisplay;
 | 
			
		||||
 | 
			
		||||
    /** Reference to track selection changes in the property selector. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
 | 
			
		||||
    /** Dropdown selector for displaying available properties. */
 | 
			
		||||
    private Selector<String> propertySelector;
 | 
			
		||||
 | 
			
		||||
    /** Set of properties selected for selling. */
 | 
			
		||||
    private Set<String> selectedProperties = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    /** Label to display the total refund amount for the selected properties. */
 | 
			
		||||
    private Label cost = new Label("0", new ElementId("label-Text"));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new SellHouse dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The MonopolyApp instance.
 | 
			
		||||
     */
 | 
			
		||||
    public SellHouse(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für das Menü
 | 
			
		||||
        sellhouseContainer = new Container();
 | 
			
		||||
        sellhouseContainer.setPreferredSize(new Vector3f(800, 600, 0));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des sellhouseContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(sellhouseContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label title = sellhouseContainer.addChild(new Label( "Gebäude Abreißen", new ElementId("warining-Bold")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        //Unterteilund des sellHouseContainer in drei "Untercontainer"
 | 
			
		||||
        Container upContainer = sellhouseContainer.addChild(new Container());
 | 
			
		||||
        Container middleContainer = sellhouseContainer.addChild(new Container());
 | 
			
		||||
        Container downContainer = sellhouseContainer.addChild(new Container());
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
 | 
			
		||||
        upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
 | 
			
		||||
        middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
 | 
			
		||||
        middleContainer.addChild(createPropertyDropdown());
 | 
			
		||||
 | 
			
		||||
        downContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        downContainer.addChild(new Label("Erstattung:", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        downContainer.addChild(cost); // Cost details
 | 
			
		||||
        downContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button cancelButton = sellhouseContainer.addChild(new Button("Abbrechen", new ElementId("button")));
 | 
			
		||||
        cancelButton.setFontSize(32);
 | 
			
		||||
        cancelButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
        Button confirmButton = sellhouseContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            AlterProperty msg = new AlterProperty("SellHouse");
 | 
			
		||||
            for (String string : selectedProperties) {
 | 
			
		||||
                System.out.println(string);
 | 
			
		||||
            }
 | 
			
		||||
            msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
 | 
			
		||||
            for (Integer integer : msg.getProperties()) {
 | 
			
		||||
                System.out.println("ID des verkaufs: "+integer);
 | 
			
		||||
            }
 | 
			
		||||
            app.getGameLogic().send(msg);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        sellhouseContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - sellhouseContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + sellhouseContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            9
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - sellhouseContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + sellhouseContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(sellhouseContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a dropdown menu for selecting a property.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The dropdown container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createPropertyDropdown() {
 | 
			
		||||
        Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> propertyOptions = new VersionedList<>();
 | 
			
		||||
        List<BuildingProperty> playerProperties = getPlayerProperties();
 | 
			
		||||
 | 
			
		||||
        // Populate the dropdown with property names
 | 
			
		||||
        for (BuildingProperty property : playerProperties) {
 | 
			
		||||
            propertyOptions.add(property.getName());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        propertySelector = new Selector<>(propertyOptions, "glass");
 | 
			
		||||
        dropdownContainer.addChild(propertySelector);
 | 
			
		||||
 | 
			
		||||
        // Track selection changes
 | 
			
		||||
        selectionRef = propertySelector.getSelectionModel().createReference();
 | 
			
		||||
 | 
			
		||||
        // Initialize the selection display here
 | 
			
		||||
        selectionDisplay = new TextField(""); // Create TextField for displaying selections
 | 
			
		||||
        selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
 | 
			
		||||
        dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
 | 
			
		||||
        
 | 
			
		||||
        // Set initial selection
 | 
			
		||||
        if (!propertyOptions.isEmpty()) {
 | 
			
		||||
            onDropdownSelectionChanged(propertySelector);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return dropdownContainer;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the list of properties owned by the current player.
 | 
			
		||||
     *
 | 
			
		||||
     * @return List of BuildingProperty objects owned by the player.
 | 
			
		||||
     */
 | 
			
		||||
    private List<BuildingProperty> getPlayerProperties() {
 | 
			
		||||
        Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
 | 
			
		||||
        BoardManager boardManager = app.getGameLogic().getBoardManager();
 | 
			
		||||
 | 
			
		||||
        return boardManager.getPropertyFields(self.getProperties()).stream()
 | 
			
		||||
                           .filter(property -> property instanceof BuildingProperty)
 | 
			
		||||
                           .map(property -> (BuildingProperty) property)
 | 
			
		||||
                           .filter(p -> app.getGameLogic().getBoardManager().canSell(p))
 | 
			
		||||
                           .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the dialog UI, tracking changes in the property selection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta Time since the last update.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        if(selectionRef.update()) {
 | 
			
		||||
            onDropdownSelectionChanged(propertySelector);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles changes to the property selection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerProperties The dropdown menu's selection state.
 | 
			
		||||
     */
 | 
			
		||||
    private void onDropdownSelectionChanged(Selector<String> playerProperties) {
 | 
			
		||||
        String selected = playerProperties.getSelectedItem();
 | 
			
		||||
        app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        if (selectedProperties.contains(selected)) {
 | 
			
		||||
            selectedProperties.remove(selected);
 | 
			
		||||
        } else {
 | 
			
		||||
            selectedProperties.add(selected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int cost = 0;
 | 
			
		||||
        for (String s : selectedProperties) {
 | 
			
		||||
            cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice() / 2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String display = String.join(" | ", selectedProperties);
 | 
			
		||||
        selectionDisplay.setText(display);
 | 
			
		||||
 | 
			
		||||
        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ü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,255 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.message.client.AlterProperty;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TakeMortage is a popup that appears when a player clicks on the "Take Mortage" button
 | 
			
		||||
 * in the BuildingAdminMenu.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * This popup allows the player to select properties and take a mortgage on them
 | 
			
		||||
 * to gain financial benefit during gameplay.
 | 
			
		||||
 * </p>
 | 
			
		||||
 */
 | 
			
		||||
public class TakeMortage extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the TakeMortage dialog UI. */
 | 
			
		||||
    private final Container takeMortageContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a styled border around the main dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** Text field to display selected properties. */
 | 
			
		||||
    private TextField selectionDisplay;
 | 
			
		||||
 | 
			
		||||
    /** Reference to track selection changes in the property selector. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
 | 
			
		||||
    /** Dropdown selector for displaying available properties. */
 | 
			
		||||
    private Selector<String> propertySelector;
 | 
			
		||||
 | 
			
		||||
    /** Set of properties selected for mortgaging. */
 | 
			
		||||
    private Set<String> selectedProperties = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    /** Label to display the total mortgage amount. */
 | 
			
		||||
    private Label cost = new Label("0", new ElementId("label-Text"));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new TakeMortage dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The MonopolyApp instance.
 | 
			
		||||
     */
 | 
			
		||||
    public TakeMortage(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für das Menü
 | 
			
		||||
        takeMortageContainer = new Container();
 | 
			
		||||
        takeMortageContainer.setPreferredSize(new Vector3f(800, 600, 0));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des sellhouseContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(takeMortageContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label title = takeMortageContainer.addChild(new Label( "Hypothek aufnehmen", new ElementId("warining-Bold")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        //Unterteilund des sellHouseContainer in drei "Untercontainer"
 | 
			
		||||
        Container upContainer = takeMortageContainer.addChild(new Container());
 | 
			
		||||
        Container middleContainer = takeMortageContainer.addChild(new Container());
 | 
			
		||||
        Container downContainer = takeMortageContainer.addChild(new Container());
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
 | 
			
		||||
        upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        middleContainer.setPreferredSize(new Vector3f(100, 150, 0));
 | 
			
		||||
        middleContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
 | 
			
		||||
        middleContainer.addChild(createPropertyDropdown());
 | 
			
		||||
 | 
			
		||||
        downContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        downContainer.addChild(new Label("Erstattung:", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        downContainer.addChild(cost);
 | 
			
		||||
        downContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button cancelButton = takeMortageContainer.addChild(new Button("Abbrechen", new ElementId("button")));
 | 
			
		||||
        cancelButton.setFontSize(32);
 | 
			
		||||
        cancelButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
        Button confirmButton = takeMortageContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            AlterProperty msg = new AlterProperty("TakeMortage");
 | 
			
		||||
            msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
 | 
			
		||||
            app.getGameLogic().send(msg);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        takeMortageContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - takeMortageContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + takeMortageContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            9
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - takeMortageContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + takeMortageContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(takeMortageContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a dropdown menu for selecting a property.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The dropdown container with property options.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createPropertyDropdown() {
 | 
			
		||||
        Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        dropdownContainer.setPreferredSize(new Vector3f(300, 200, 0));
 | 
			
		||||
        dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> propertyOptions = new VersionedList<>();
 | 
			
		||||
        List<PropertyField> playerProperties = getPlayerProperties();
 | 
			
		||||
 | 
			
		||||
        // Populate the dropdown with property names
 | 
			
		||||
        for (PropertyField property : playerProperties) {
 | 
			
		||||
            propertyOptions.add(property.getName());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        propertySelector = new Selector<>(propertyOptions, "glass");
 | 
			
		||||
        dropdownContainer.addChild(propertySelector);
 | 
			
		||||
 | 
			
		||||
        // Track selection changes
 | 
			
		||||
        selectionRef = propertySelector.getSelectionModel().createReference();
 | 
			
		||||
 | 
			
		||||
        // Initialize the selection display here
 | 
			
		||||
        selectionDisplay = new TextField(""); // Create TextField for displaying selections
 | 
			
		||||
        selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
 | 
			
		||||
        dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
 | 
			
		||||
 | 
			
		||||
        // Set initial selection
 | 
			
		||||
        if (!propertyOptions.isEmpty()) {
 | 
			
		||||
            onDropdownSelectionChanged(propertySelector);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return dropdownContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the list of properties owned by the current player.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * Only properties that are not currently mortgaged are included.
 | 
			
		||||
     * </p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return List of eligible PropertyField objects owned by the player.
 | 
			
		||||
     */
 | 
			
		||||
    private List<PropertyField> getPlayerProperties() {
 | 
			
		||||
        Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
 | 
			
		||||
        BoardManager boardManager = app.getGameLogic().getBoardManager();
 | 
			
		||||
 | 
			
		||||
        return boardManager.getPropertyFields(self.getProperties()).stream()
 | 
			
		||||
                           .filter(property -> property instanceof PropertyField)
 | 
			
		||||
                           .map(property -> (PropertyField) property)
 | 
			
		||||
                           .filter(p -> !p.isMortgaged())
 | 
			
		||||
                           .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the dialog UI, tracking changes in the property selection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta Time since the last update.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        if(selectionRef.update()) {
 | 
			
		||||
            onDropdownSelectionChanged(propertySelector);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles changes to the property selection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerProperties The dropdown menu's selection state.
 | 
			
		||||
     */
 | 
			
		||||
    private void onDropdownSelectionChanged(Selector<String> playerProperties) {
 | 
			
		||||
        String selected = playerProperties.getSelectedItem();
 | 
			
		||||
        app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        if (selectedProperties.contains(selected)) {
 | 
			
		||||
            selectedProperties.remove(selected);
 | 
			
		||||
        } else {
 | 
			
		||||
            selectedProperties.add(selected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int cost = 0;
 | 
			
		||||
        for (String s : selectedProperties) {
 | 
			
		||||
            cost += ((PropertyField) app.getGameLogic().getBoardManager().getFieldByName(s)).getHypo();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String display = String.join(" | ", selectedProperties);
 | 
			
		||||
        selectionDisplay.setText(display);
 | 
			
		||||
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the dialog and removes GUI elements from the screen.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(takeMortageContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,137 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
import static pp.monopoly.Resources.lookup;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TimeOut is a warning popup triggered when the connection to the server is interrupted.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * This popup informs the user about the loss of connection and provides an option to acknowledge it.
 | 
			
		||||
 * </p>
 | 
			
		||||
 */
 | 
			
		||||
public class TimeOut extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the dialog. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the TimeOut dialog UI. */
 | 
			
		||||
    private final Container timeOutContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a styled border around the main dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new TimeOut dialog to notify the user about a connection loss.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The MonopolyApp instance.
 | 
			
		||||
     */
 | 
			
		||||
    public TimeOut(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        timeOutContainer = new Container();
 | 
			
		||||
        timeOutContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        timeOutContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(timeOutContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = timeOutContainer.addChild(new Label("Vorsicht !", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        Container textContainer = timeOutContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast die Verbindung verloren und kannst nichts dagegen machen. Akzeptiere einfach, dass du verloren hast!", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        textContainer.setPreferredSize(timeOutContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = timeOutContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> close());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        timeOutContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - timeOutContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + timeOutContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - timeOutContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + timeOutContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(timeOutContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The overlay geometry.
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the TimeOut dialog and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(timeOutContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,51 +1,143 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.IconComponent;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the dialog. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the "Winner" dialog UI. */
 | 
			
		||||
    private final Container WinnerContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a styled border around the main dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new NetworkDialog.
 | 
			
		||||
     * Constructs a new WinnerPopUp dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The NetworkSupport instance to be used for network operations.
 | 
			
		||||
     * @param app The MonopolyApp instance.
 | 
			
		||||
     */
 | 
			
		||||
    public WinnerPopUp(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        initializeDialog();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        WinnerContainer = new Container();
 | 
			
		||||
        WinnerContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        WinnerContainer.setPreferredSize(new Vector3f(440,600,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(WinnerContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label winnerTitle = WinnerContainer.addChild(new Label("Herzlichen Glückwunsch, du bist der neue Monopoly Champion!", new ElementId("header")));
 | 
			
		||||
        winnerTitle.setFontSize(25);
 | 
			
		||||
       // winnerTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
        // Create the image container
 | 
			
		||||
        Container imageContainer = WinnerContainer.addChild(new Container());
 | 
			
		||||
        imageContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Dark gray background
 | 
			
		||||
        imageContainer.setPreferredSize(WinnerContainer.getPreferredSize().addLocal(-250, -200, 0)); // Adjust size for layout
 | 
			
		||||
 | 
			
		||||
        // Add the image to the container
 | 
			
		||||
        Label imageLabel = new Label(""); // Create a label for the image
 | 
			
		||||
        IconComponent icon = new IconComponent("Pictures/MonopolyWinner.png"); // Load the image as an icon
 | 
			
		||||
        icon.setIconScale(1); // Scale the image appropriately
 | 
			
		||||
        imageLabel.setIcon(icon);
 | 
			
		||||
        imageContainer.addChild(imageLabel); // Add the image label to the container
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Button quitButton = WinnerContainer.addChild(new Button("Spiel Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.closeApp();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        WinnerContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - WinnerContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + WinnerContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - WinnerContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + WinnerContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(WinnerContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the dialog with input fields and connection buttons.
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The overlay geometry.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeDialog() {
 | 
			
		||||
        Container inputContainer = new Container();
 | 
			
		||||
 | 
			
		||||
        // Titel und Eingabefelder für Host und Port
 | 
			
		||||
        inputContainer.addChild(new Label("Herlichen Glückwunsch!"));
 | 
			
		||||
        inputContainer.addChild(new Label("Du,bist der Monopoly Champion!!!"));
 | 
			
		||||
 | 
			
		||||
        Label imageLabel = new Label("");
 | 
			
		||||
        IconComponent icon = new IconComponent("Pictures/MonopolyWinner.png"); // Icon mit Textur erstellen
 | 
			
		||||
        icon.setIconScale(1); // Skalierung des Bildes
 | 
			
		||||
        imageLabel.setIcon(icon);
 | 
			
		||||
 | 
			
		||||
        // Setze das Icon im Label
 | 
			
		||||
        inputContainer.addChild(imageLabel);
 | 
			
		||||
 | 
			
		||||
        Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
 | 
			
		||||
        cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
 | 
			
		||||
        
 | 
			
		||||
        inputContainer.setLocalTranslation(300, 800, 0);
 | 
			
		||||
        app.getGuiNode().attachChild(inputContainer);
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the WinnerPopUp dialog and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(WinnerContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Pictures/dice/1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 169 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Pictures/dice/2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 171 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Pictures/dice/3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 183 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Pictures/dice/4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 207 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Pictures/dice/5.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 105 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Pictures/dice/6.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 228 KiB  | 
| 
		 After Width: | Height: | Size: 24 MiB  | 
| 
		 After Width: | Height: | Size: 66 KiB  | 
| 
		 After Width: | Height: | Size: 200 KiB  | 
| 
		 After Width: | Height: | Size: 6.7 MiB  | 
| 
		 After Width: | Height: | Size: 31 MiB  | 
| 
		 After Width: | Height: | Size: 18 MiB  | 
| 
		 After Width: | Height: | Size: 5.7 MiB  | 
| 
		 After Width: | Height: | Size: 589 B  | 
| 
		 After Width: | Height: | Size: 1.3 MiB  | 
| 
		 After Width: | Height: | Size: 35 KiB  | 
| 
		 After Width: | Height: | Size: 6.3 KiB  | 
| 
		 After Width: | Height: | Size: 9.6 KiB  | 
| 
		 After Width: | Height: | Size: 41 KiB  | 
@@ -34,13 +34,13 @@ public class MonopolyConfig extends Config {
 | 
			
		||||
     * The width of the game map in terms of grid units.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("map.width")
 | 
			
		||||
    private int mapWidth = 12;
 | 
			
		||||
    private int mapWidth = 10;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The height of the game map in terms of grid units.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("map.height")
 | 
			
		||||
    private int mapHeight = 12;
 | 
			
		||||
    private int mapHeight = 10;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates an instance of {@code MonopolyConfig} with default settings.
 | 
			
		||||
 
 | 
			
		||||
@@ -5,15 +5,16 @@ import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.game.server.PlayerHandler;
 | 
			
		||||
import pp.monopoly.message.client.ClientMessage;
 | 
			
		||||
import pp.monopoly.message.server.BuyPropertyResponse;
 | 
			
		||||
import pp.monopoly.message.server.BuyPropertyRequest;
 | 
			
		||||
import pp.monopoly.message.server.DiceResult;
 | 
			
		||||
import pp.monopoly.message.server.EventDrawCard;
 | 
			
		||||
import pp.monopoly.message.server.GameOver;
 | 
			
		||||
import pp.monopoly.message.server.GameStart;
 | 
			
		||||
import pp.monopoly.message.server.JailEvent;
 | 
			
		||||
import pp.monopoly.message.server.NextPlayerTurn;
 | 
			
		||||
import pp.monopoly.message.server.NotificationMessage;
 | 
			
		||||
import pp.monopoly.message.server.PlayerStatusUpdate;
 | 
			
		||||
import pp.monopoly.message.server.ServerInterpreter;
 | 
			
		||||
import pp.monopoly.message.server.TimeOutWarning;
 | 
			
		||||
@@ -22,14 +23,20 @@ import pp.monopoly.message.server.TradeRequest;
 | 
			
		||||
import pp.monopoly.message.server.ViewAssetsResponse;
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.model.IntPoint;
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.notification.ClientStateEvent;
 | 
			
		||||
import pp.monopoly.notification.DiceRollEvent;
 | 
			
		||||
import pp.monopoly.notification.ButtonStatusEvent;
 | 
			
		||||
import pp.monopoly.notification.EventCardEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEventBroker;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.InfoTextEvent;
 | 
			
		||||
import pp.monopoly.notification.PopUpEvent;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
import pp.monopoly.notification.SoundEvent;
 | 
			
		||||
import pp.monopoly.notification.UpdatePlayerView;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Controls the client-side game logic for Monopoly.
 | 
			
		||||
@@ -52,10 +59,13 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
    /** The current state of the client game logic. */
 | 
			
		||||
    private ClientState state = new LobbyState(this);
 | 
			
		||||
 | 
			
		||||
    private List<Player> players;
 | 
			
		||||
    private PlayerHandler playerHandler;
 | 
			
		||||
 | 
			
		||||
    private BoardManager boardManager = new BoardManager();
 | 
			
		||||
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a ClientGameLogic with the specified sender object.
 | 
			
		||||
     *
 | 
			
		||||
@@ -94,8 +104,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
        state.entry();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<Player> getPlayers() {
 | 
			
		||||
        return players;
 | 
			
		||||
    public PlayerHandler getPlayerHandler() {
 | 
			
		||||
        return playerHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -107,6 +117,10 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
        return board;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public TradeHandler getTradeHandler() {
 | 
			
		||||
        return tradeHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves the preview figure to the specified position.
 | 
			
		||||
     *
 | 
			
		||||
@@ -144,7 +158,6 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
            LOGGER.log(Level.ERROR, "trying to send {0} with sender==null", msg); //NON-NLS
 | 
			
		||||
        } else {
 | 
			
		||||
            clientSender.send(msg);
 | 
			
		||||
            System.out.println("Message gesendet");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -191,21 +204,6 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
        state.update(delta);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the response for buying a property.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the message containing the buy property response
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(BuyPropertyResponse msg) {
 | 
			
		||||
        if (msg.isSuccessful()) {
 | 
			
		||||
            setInfoText("You successfully bought " + msg.getPropertyName() + "!");
 | 
			
		||||
            playSound(Sound.MONEY_LOST);
 | 
			
		||||
        } else {
 | 
			
		||||
            setInfoText("Unable to buy " + msg.getPropertyName() + ". Reason: " + msg.getReason());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the result of a dice roll.
 | 
			
		||||
     *
 | 
			
		||||
@@ -213,9 +211,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(DiceResult msg) {
 | 
			
		||||
        setInfoText("You rolled a " + msg.calcTotal() + "!");
 | 
			
		||||
        //Set the dice images
 | 
			
		||||
        playSound(Sound.DICE_ROLL);
 | 
			
		||||
        notifyListeners(new DiceRollEvent(msg.getRollResult().get(0), msg.getRollResult().get(1)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -225,9 +222,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(EventDrawCard msg) {
 | 
			
		||||
        setInfoText("Event card drawn: " + msg.getCardDescription());
 | 
			
		||||
        // Kartenlogik
 | 
			
		||||
        playSound(Sound.EVENT_CARD);
 | 
			
		||||
        notifyListeners(new EventCardEvent(msg.getCardDescription()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -238,12 +233,10 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(GameOver msg) {
 | 
			
		||||
        if (msg.isWinner()) {
 | 
			
		||||
            setInfoText("Congratulations! You have won the game!");
 | 
			
		||||
            //Winner popup
 | 
			
		||||
            notifyListeners(new PopUpEvent("Winner", msg));
 | 
			
		||||
            playSound(Sound.WINNER);
 | 
			
		||||
        } else {
 | 
			
		||||
            setInfoText("Game over. Better luck next time!");
 | 
			
		||||
            // Looser popup
 | 
			
		||||
            notifyListeners(new PopUpEvent("Looser", msg));
 | 
			
		||||
            playSound(Sound.LOSER);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -255,9 +248,9 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(GameStart msg) {
 | 
			
		||||
        players = msg.getPlayers();
 | 
			
		||||
        setInfoText("The game has started! Good luck!");
 | 
			
		||||
        playerHandler = msg.getPlayerHandler();
 | 
			
		||||
        setState(new WaitForTurnState(this));
 | 
			
		||||
        notifyListeners(new ButtonStatusEvent(false));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -268,10 +261,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(JailEvent msg) {
 | 
			
		||||
        if (msg.isGoingToJail()) {
 | 
			
		||||
            setInfoText("You are sent to jail!");
 | 
			
		||||
            playSound(Sound.GULAG);
 | 
			
		||||
        } else {
 | 
			
		||||
            setInfoText("You are out of jail!");
 | 
			
		||||
            notifyListeners(new PopUpEvent("goingToJail", msg));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -282,8 +273,9 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(PlayerStatusUpdate msg) {
 | 
			
		||||
        
 | 
			
		||||
        setInfoText("Player " + msg.getPlayerName() + " status updated: " + msg.getStatus());
 | 
			
		||||
        playerHandler = msg.getPlayerHandler();
 | 
			
		||||
        System.out.println("Update Player");
 | 
			
		||||
        notifyListeners(new UpdatePlayerView());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -293,7 +285,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TimeOutWarning msg) {
 | 
			
		||||
        setInfoText("Warning! Time is running out. You have " + msg.getRemainingTime() + " seconds left.");
 | 
			
		||||
        notifyListeners(new PopUpEvent("timeout", msg));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -303,7 +295,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(ViewAssetsResponse msg) {
 | 
			
		||||
        setInfoText("Your current assets are being displayed.");
 | 
			
		||||
        boardManager = msg.getboard();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -313,12 +305,12 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TradeReply msg) {
 | 
			
		||||
        if (msg.getTradeHandler().getStatus()) {
 | 
			
		||||
            setInfoText("Trade accepted by " + msg.getTradeHandler().getReceiver().getName() + ".");
 | 
			
		||||
        if (msg.isAccepted()) {
 | 
			
		||||
            playSound(Sound.TRADE_ACCEPTED);
 | 
			
		||||
            notifyListeners(new PopUpEvent("tradepos", msg));
 | 
			
		||||
        } else {
 | 
			
		||||
            setInfoText("Trade rejected by " + msg.getTradeHandler().getReceiver().getName() + ".");
 | 
			
		||||
            playSound(Sound.TRADE_REJECTED);
 | 
			
		||||
            notifyListeners(new PopUpEvent("tradeneg", msg));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -329,9 +321,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TradeRequest msg) {
 | 
			
		||||
        setInfoText("Trade offer received from " + msg.getTradeHandler().getSender().getName());
 | 
			
		||||
        // playSound(Sound.TRADE_REQUEST); no sound effect
 | 
			
		||||
        // notifyListeners();
 | 
			
		||||
        tradeHandler = msg.getTradeHandler();
 | 
			
		||||
        notifyListeners(new PopUpEvent("tradeRequest", msg));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -341,7 +332,28 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(NextPlayerTurn msg) {
 | 
			
		||||
        setInfoText("It's your turn!");
 | 
			
		||||
        setState(new ActiveState(this));
 | 
			
		||||
        notifyListeners(new ButtonStatusEvent(true));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(BuyPropertyRequest msg) {
 | 
			
		||||
        notifyListeners(new PopUpEvent("Buy", msg));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(NotificationMessage msg) {
 | 
			
		||||
        if (msg.getKeyWord().equals("rent")) {
 | 
			
		||||
            notifyListeners(new PopUpEvent("rent", msg));
 | 
			
		||||
        } else if (msg.getKeyWord().equals("jailpay")) {
 | 
			
		||||
            notifyListeners(new PopUpEvent(msg.getKeyWord(), msg));
 | 
			
		||||
        } else if(msg.getKeyWord().equals("NoMoneyWarning")) {
 | 
			
		||||
            notifyListeners(new PopUpEvent("NoMoneyWarning", msg));
 | 
			
		||||
        } else if (msg.getKeyWord().equals("jailpay")) {
 | 
			
		||||
            notifyListeners(new PopUpEvent("jailpay", msg));
 | 
			
		||||
        } else if (msg.getKeyWord().equals("jailtryagain")) {
 | 
			
		||||
            notifyListeners(new PopUpEvent("jailtryagain", msg));
 | 
			
		||||
        } else if(msg.getKeyWord().equals("ReceivedRent")) {
 | 
			
		||||
            notifyListeners(new PopUpEvent("ReceivedRent", msg));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,12 +7,21 @@
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.message.server.BuyPropertyRequest;
 | 
			
		||||
import pp.monopoly.message.server.DiceResult;
 | 
			
		||||
import pp.monopoly.message.server.EventDrawCard;
 | 
			
		||||
import pp.monopoly.message.server.JailEvent;
 | 
			
		||||
import pp.monopoly.message.server.NextPlayerTurn;
 | 
			
		||||
import pp.monopoly.message.server.NotificationMessage;
 | 
			
		||||
import pp.monopoly.message.server.PlayerStatusUpdate;
 | 
			
		||||
import pp.monopoly.model.FieldVisitor;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.model.card.Card;
 | 
			
		||||
@@ -36,12 +45,12 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    private String name;
 | 
			
		||||
    private int accountBalance = 15000;
 | 
			
		||||
    private Figure figure;
 | 
			
		||||
    private List<PropertyField> properties;
 | 
			
		||||
    private Set<Integer> properties = new HashSet<>();
 | 
			
		||||
    private int getOutOfJailCard;
 | 
			
		||||
    private int fieldID;
 | 
			
		||||
    private DiceResult rollResult;
 | 
			
		||||
    private final PlayerHandler handler;
 | 
			
		||||
    private PlayerState state = new LobbyState();
 | 
			
		||||
    private transient final PlayerHandler handler;
 | 
			
		||||
    private transient PlayerState state = new WaitForTurnState();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
@@ -76,15 +85,19 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    public void setFigure(Figure figure) {
 | 
			
		||||
        this.figure = figure;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public Figure getFigure(){
 | 
			
		||||
        return figure;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public PlayerColor getColor() {
 | 
			
		||||
        switch ((id%6)+1) {
 | 
			
		||||
            case 1: return PlayerColor.BLUE;
 | 
			
		||||
            case 2: return PlayerColor.GREEN_DARK;
 | 
			
		||||
            case 3: return PlayerColor.GREEN_LIGHT;
 | 
			
		||||
            case 1: return PlayerColor.CYAN;
 | 
			
		||||
            case 2: return PlayerColor.YELLOW;
 | 
			
		||||
            case 3: return PlayerColor.RED;
 | 
			
		||||
            case 4: return PlayerColor.PINK;
 | 
			
		||||
            case 5: return PlayerColor.RED;
 | 
			
		||||
            case 6: return PlayerColor.YELLOW;
 | 
			
		||||
            case 5: return PlayerColor.GREEN;
 | 
			
		||||
            case 6: return PlayerColor.PURPLE;
 | 
			
		||||
        
 | 
			
		||||
            default:
 | 
			
		||||
                return null;
 | 
			
		||||
@@ -122,53 +135,96 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    public int getFieldID() {
 | 
			
		||||
        return fieldID;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void setActive() {
 | 
			
		||||
        state = new ActiveState();
 | 
			
		||||
        System.out.println("State:   "+state.getClass().getName());
 | 
			
		||||
        if(!(state instanceof JailState)) {
 | 
			
		||||
            state = new ActiveState();
 | 
			
		||||
        } else {
 | 
			
		||||
            String message = (((JailState)state).remainingAttempts <= 0) ? "jailpay" : "jailtryagain";
 | 
			
		||||
            handler.getLogic().send(this, new NotificationMessage(message));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean finishTurn() {
 | 
			
		||||
        if(canFinishTurn()) {
 | 
			
		||||
            state = new WaitForTurnState();
 | 
			
		||||
            if (state instanceof ActiveState) state = new WaitForTurnState();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else return false;
 | 
			
		||||
        else {
 | 
			
		||||
            bankrupt();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean canFinishTurn() {
 | 
			
		||||
        return accountBalance >= 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves by the specified amount of steps
 | 
			
		||||
     * @param steps the number of steps to move
 | 
			
		||||
     * @return the new position
 | 
			
		||||
     */
 | 
			
		||||
    public int move(int steps){
 | 
			
		||||
        return movePos(fieldID+steps);
 | 
			
		||||
    public PlayerState getState() {
 | 
			
		||||
        return state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setState(PlayerState state) {
 | 
			
		||||
        this.state = state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves the player to the specified Position on the board
 | 
			
		||||
     * @param position the position to move to
 | 
			
		||||
     * Moves the player by a given number of steps, handling board wrapping.
 | 
			
		||||
     *
 | 
			
		||||
     * @param steps number of steps to move
 | 
			
		||||
     * @return the new position
 | 
			
		||||
     */
 | 
			
		||||
    public int movePos(int position){
 | 
			
		||||
        fieldID = fieldID+position;
 | 
			
		||||
        if(fieldID >= 40) {
 | 
			
		||||
            fieldID = fieldID%40;
 | 
			
		||||
            earnMoney(2000);
 | 
			
		||||
    public int move(int steps) {
 | 
			
		||||
        if (fieldID + steps >= 40) {
 | 
			
		||||
            earnMoney(2000); // Passing GO gives money
 | 
			
		||||
        }
 | 
			
		||||
        fieldID = (fieldID + steps) % 40;
 | 
			
		||||
        figure.moveTo(fieldID);
 | 
			
		||||
        handler.getLogic().send(this, new PlayerStatusUpdate(handler));
 | 
			
		||||
        handler.getLogic().getBoardManager().getFieldAtIndex(fieldID).accept(this);
 | 
			
		||||
        return fieldID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the player to the specified Position on the board
 | 
			
		||||
     * @param position the position to move to
 | 
			
		||||
     * @return the new position
 | 
			
		||||
     */
 | 
			
		||||
    public int setPosition(int position){
 | 
			
		||||
        if(position < 40 && position >= 0) {
 | 
			
		||||
            fieldID = position;
 | 
			
		||||
            figure.moveTo(fieldID);
 | 
			
		||||
            handler.getLogic().send(this, new PlayerStatusUpdate(handler));
 | 
			
		||||
            handler.getLogic().getBoardManager().getFieldAtIndex(fieldID).accept(this);
 | 
			
		||||
        }
 | 
			
		||||
        return fieldID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
     * Sets the player to the specified Position on the board
 | 
			
		||||
     * @param position the position to move to
 | 
			
		||||
     * @return the new position
 | 
			
		||||
     */
 | 
			
		||||
    public int setPositionWithMoney(int position){
 | 
			
		||||
        if(position < 40 && position >= 0) {
 | 
			
		||||
            if(position < fieldID) {
 | 
			
		||||
                earnMoney(2000);
 | 
			
		||||
            }
 | 
			
		||||
            fieldID = position;
 | 
			
		||||
            figure.moveTo(fieldID);
 | 
			
		||||
            handler.getLogic().send(this, new PlayerStatusUpdate(handler));
 | 
			
		||||
            handler.getLogic().getBoardManager().getFieldAtIndex(fieldID).accept(this);
 | 
			
		||||
        }
 | 
			
		||||
        return fieldID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all the properties owned by this player
 | 
			
		||||
     * @return List of all properties owned by this player
 | 
			
		||||
     */
 | 
			
		||||
    public List<PropertyField> getProperties() {
 | 
			
		||||
        return properties;
 | 
			
		||||
    public List<Integer> getProperties() {
 | 
			
		||||
        return new ArrayList<>(properties);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -178,7 +234,7 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
     */
 | 
			
		||||
    public void buyProperty(PropertyField property) {
 | 
			
		||||
        if (property.getOwner() == null && accountBalance >= property.getPrice()) {
 | 
			
		||||
            properties.add(property);
 | 
			
		||||
            properties.add(property.getId());
 | 
			
		||||
            property.setOwner(this);
 | 
			
		||||
            pay(property.getPrice());
 | 
			
		||||
        }
 | 
			
		||||
@@ -275,38 +331,63 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        state.useJailCard();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void sendRentNotification(String keyword, Player player, int amount) {
 | 
			
		||||
        NotificationMessage msg = new NotificationMessage(keyword);
 | 
			
		||||
        msg.setRentAmount(amount);
 | 
			
		||||
        msg.setRentOwnerId(player.getName());
 | 
			
		||||
        getHandler().getLogic().send(player, msg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(BuildingProperty field) {
 | 
			
		||||
        int rent = field.calcRent();
 | 
			
		||||
 | 
			
		||||
        field.getOwner().earnMoney(rent);
 | 
			
		||||
        pay(rent);
 | 
			
		||||
        if(field.getOwner() == null) {
 | 
			
		||||
            if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest());
 | 
			
		||||
            else getHandler().getLogic().send(this, new NotificationMessage("NoMoneyWarning"));
 | 
			
		||||
        } else if (field.getOwner() != this){
 | 
			
		||||
            int rent = field.calcRent();
 | 
			
		||||
            field.getOwner().earnMoney(rent);
 | 
			
		||||
            pay(rent);
 | 
			
		||||
            sendRentNotification("rent", field.getOwner(), rent);
 | 
			
		||||
            sendRentNotification("ReceivedRent", this, rent);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(FoodField field) {
 | 
			
		||||
        int factor = 4;
 | 
			
		||||
        if (field.getOwner().getNumProp(field) == 2) {
 | 
			
		||||
            factor = 10;
 | 
			
		||||
        if(field.getOwner() == null) {
 | 
			
		||||
            if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest());
 | 
			
		||||
        } else if (field.getOwner() != this){
 | 
			
		||||
            int factor = 40;
 | 
			
		||||
            if (field.getOwner().getNumProp(field) == 2) {
 | 
			
		||||
                factor = 100;
 | 
			
		||||
            }
 | 
			
		||||
            int rent = rollResult.calcTotal()*factor;
 | 
			
		||||
            field.getOwner().earnMoney(rent);
 | 
			
		||||
            pay(rent);
 | 
			
		||||
            sendRentNotification("rent", field.getOwner(), rent);
 | 
			
		||||
            sendRentNotification("ReceivedRent", this, rent);
 | 
			
		||||
        }
 | 
			
		||||
        field.getOwner().earnMoney(rollResult.calcTotal()*factor);
 | 
			
		||||
        pay(rollResult.calcTotal()*factor);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(GateField field) {
 | 
			
		||||
        int rent = field.calcRent() * field.getOwner().getNumProp(field);
 | 
			
		||||
        if(field.getOwner() == null) {
 | 
			
		||||
            if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest());
 | 
			
		||||
        } else if (field.getOwner() != this){
 | 
			
		||||
            int rent = field.calcRent() * field.getOwner().getNumProp(field);
 | 
			
		||||
 | 
			
		||||
        field.getOwner().earnMoney(rent);
 | 
			
		||||
        pay(rent);
 | 
			
		||||
            field.getOwner().earnMoney(rent);
 | 
			
		||||
            pay(rent);
 | 
			
		||||
            sendRentNotification("rent", field.getOwner(), rent);
 | 
			
		||||
            sendRentNotification("ReceivedRent", this, rent);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(GulagField field) {
 | 
			
		||||
        state = new JailState();
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -319,21 +400,21 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(EventField field) {
 | 
			
		||||
        Card c = getHandler().getLogic().getDeckHelper().drawCard();
 | 
			
		||||
        getHandler().getLogic().getDeckHelper().visit(c, this);
 | 
			
		||||
        getHandler().getLogic().getDeckHelper().visit(c, this); //Logic
 | 
			
		||||
        getHandler().getLogic().send(this, new EventDrawCard(c.getDescription())); // Card notification
 | 
			
		||||
        getHandler().getLogic().send(this, new PlayerStatusUpdate(getHandler())); //update view
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(WacheField field) {
 | 
			
		||||
        movePos(10);
 | 
			
		||||
        moveToJail();
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(GoField field) {
 | 
			
		||||
        earnMoney(2000);
 | 
			
		||||
        GulagField res = (GulagField) handler.getLogic().getBoardManager().getFieldAtIndex(10);
 | 
			
		||||
        res.accept(this);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -346,6 +427,30 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<PropertyField> getPropertyFields() {
 | 
			
		||||
        List<PropertyField> properties = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        for (Integer i : this.properties) {
 | 
			
		||||
            properties.add((PropertyField)getHandler().getLogic().getBoardManager().getFieldAtIndex(i));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return properties;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends the player to jail by setting position and state.
 | 
			
		||||
     */
 | 
			
		||||
    public void moveToJail() {
 | 
			
		||||
        setPosition(10); // Jail position on the board
 | 
			
		||||
        state = new JailState();
 | 
			
		||||
        handler.getLogic().send(this, new JailEvent(true));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void jail() {
 | 
			
		||||
        state = new JailState();
 | 
			
		||||
        fieldID = 10;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of Properties of the speciefied fild type
 | 
			
		||||
     * @param field the type of field to search for
 | 
			
		||||
@@ -353,7 +458,9 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
     */
 | 
			
		||||
    public int getNumProp(PropertyField field) {
 | 
			
		||||
        int count = 0;
 | 
			
		||||
        for (PropertyField propertyField : properties) {
 | 
			
		||||
        if (properties.isEmpty()) return 0;
 | 
			
		||||
        
 | 
			
		||||
        for (PropertyField propertyField : getPropertyFields()) {
 | 
			
		||||
            if (propertyField.getClass() == field.getClass()) {
 | 
			
		||||
                count++;
 | 
			
		||||
            }
 | 
			
		||||
@@ -364,7 +471,7 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
 | 
			
		||||
    public int getNumHouses() {
 | 
			
		||||
        int total = 0;
 | 
			
		||||
        for (PropertyField field : properties) {
 | 
			
		||||
        for (PropertyField field : getPropertyFields()) {
 | 
			
		||||
            if (field.getClass() == BuildingProperty.class) {
 | 
			
		||||
                total += ((BuildingProperty) field).getHouses();
 | 
			
		||||
            }
 | 
			
		||||
@@ -374,15 +481,16 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
 | 
			
		||||
    public int getNumHotels() {
 | 
			
		||||
        int total = 0;
 | 
			
		||||
        for (PropertyField field : properties) {
 | 
			
		||||
        for (PropertyField field : getPropertyFields()) {
 | 
			
		||||
            if (field.getClass() == BuildingProperty.class) {
 | 
			
		||||
                total += ((BuildingProperty) field).getHotel();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return total;
 | 
			
		||||
    }
 | 
			
		||||
    // private static int c = 0;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
    /**
 | 
			
		||||
     * Inner class for dice functionality in the game.
 | 
			
		||||
     * Rolls random dice values.
 | 
			
		||||
     */
 | 
			
		||||
@@ -396,22 +504,36 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
         */
 | 
			
		||||
        private static int rollDice() {
 | 
			
		||||
            return random.nextInt(6) + 1;
 | 
			
		||||
            // c++;
 | 
			
		||||
            // return (c%2 == 0)? 3: 2;           
 | 
			
		||||
            // if(c < 7) {
 | 
			
		||||
            //     return 3;
 | 
			
		||||
            // } else {
 | 
			
		||||
            //     return (c%4)+1;
 | 
			
		||||
            // }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rolls two dice and returns a list with the results.
 | 
			
		||||
     * Rolls two dice, handles movement logic, and checks for doublets.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a List of two integers representing the dice roll results
 | 
			
		||||
     * @return the DiceResult of the roll
 | 
			
		||||
     */
 | 
			
		||||
    DiceResult rollDice() {
 | 
			
		||||
        return state.rollDice();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void bankrupt() {
 | 
			
		||||
        for (PropertyField field : getPropertyFields()) {
 | 
			
		||||
            field.setOwner(null);
 | 
			
		||||
        }
 | 
			
		||||
        properties.clear();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * A interface representing the PlayerStates
 | 
			
		||||
     */
 | 
			
		||||
    private interface PlayerState {
 | 
			
		||||
    interface PlayerState {
 | 
			
		||||
        /**
 | 
			
		||||
         * Handles the logic for rolling Dice
 | 
			
		||||
         * @return the {@link DiceResult} of this the DiceRoll
 | 
			
		||||
@@ -436,10 +558,39 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
     */
 | 
			
		||||
    private class ActiveState implements PlayerState {
 | 
			
		||||
 | 
			
		||||
        private int doubletscounter = 3;
 | 
			
		||||
        private boolean mayRollDice = true;
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public DiceResult rollDice() {
 | 
			
		||||
 | 
			
		||||
            if (!mayRollDice) {
 | 
			
		||||
                throw new IllegalStateException("Player is not allowed to roll dice at this moment.");
 | 
			
		||||
            }
 | 
			
		||||
    
 | 
			
		||||
            List<Integer> roll = List.of(Dice.rollDice(), Dice.rollDice());
 | 
			
		||||
            rollResult = new DiceResult(roll);
 | 
			
		||||
            rollResult = new DiceResult(roll.get(0), roll.get(1));
 | 
			
		||||
            mayRollDice = false;
 | 
			
		||||
    
 | 
			
		||||
            // Check for doublets
 | 
			
		||||
            if (rollResult.isDoublets()) {
 | 
			
		||||
                doubletscounter--; // Decrement doublets counter
 | 
			
		||||
 | 
			
		||||
                if (doubletscounter <= 0) {
 | 
			
		||||
                    // Player rolls third doublet -> move to jail
 | 
			
		||||
                    moveToJail();
 | 
			
		||||
                    doubletscounter = 3; // Reset doublets counter
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Player rolls doublets but can roll again
 | 
			
		||||
                    mayRollDice = true;
 | 
			
		||||
                    move(rollResult.calcTotal()); // Move player for this roll
 | 
			
		||||
                    getHandler().getLogic().send(Player.this, new NextPlayerTurn());
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // No doublets -> move normally and reset doublets counter
 | 
			
		||||
                move(rollResult.calcTotal());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return rollResult;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -455,71 +606,53 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A class to represent the Lobby PlayerState
 | 
			
		||||
     * Set when in Lobby
 | 
			
		||||
     */
 | 
			
		||||
    private class LobbyState implements PlayerState{
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public DiceResult rollDice() {
 | 
			
		||||
            //do nothing
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void payBail() {
 | 
			
		||||
            //do nothing
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void useJailCard() {
 | 
			
		||||
            // do nothing
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A class to represent the Jailed PlayerState
 | 
			
		||||
     * Set when in Gulag
 | 
			
		||||
     */
 | 
			
		||||
    private class JailState implements PlayerState {
 | 
			
		||||
 | 
			
		||||
        private int DoubletsCounter = 3;
 | 
			
		||||
        private int remainingAttempts = 3;
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public DiceResult rollDice() {
 | 
			
		||||
            List<Integer> roll = List.of(Dice.rollDice(), Dice.rollDice());
 | 
			
		||||
            rollResult = new DiceResult(roll);
 | 
			
		||||
            if (rollResult.isDoublets()) {
 | 
			
		||||
                state = new ActiveState();
 | 
			
		||||
            } else if (DoubletsCounter == 0) {
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
                DoubletsCounter--;
 | 
			
		||||
            if (remainingAttempts <= 0) {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            List<Integer> roll = List.of(Dice.rollDice(), Dice.rollDice());
 | 
			
		||||
            rollResult = new DiceResult(roll.get(0), roll.get(1));
 | 
			
		||||
            handler.getLogic().send(Player.this, new DiceResult (rollResult.getRollResult().get(0), rollResult.getRollResult().get(1)));
 | 
			
		||||
 | 
			
		||||
            if (rollResult.isDoublets()) {
 | 
			
		||||
                handler.getLogic().send(Player.this, new JailEvent(false));
 | 
			
		||||
                state = new ActiveState();
 | 
			
		||||
            } else {
 | 
			
		||||
                remainingAttempts--;
 | 
			
		||||
            }
 | 
			
		||||
            System.out.println("Feld:"+fieldID);
 | 
			
		||||
            return rollResult;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void payBail() {
 | 
			
		||||
            pay(500);
 | 
			
		||||
            state = new ActiveState();
 | 
			
		||||
                pay(500);
 | 
			
		||||
                state = new ActiveState();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void useJailCard() {
 | 
			
		||||
            getOutOfJailCard--;
 | 
			
		||||
            state = new ActiveState();
 | 
			
		||||
            if (getOutOfJailCard > 0) {
 | 
			
		||||
                removeJailCard();
 | 
			
		||||
                state = new ActiveState();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private class WaitForTurnState implements PlayerState {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public DiceResult rollDice() {
 | 
			
		||||
            throw new UnsupportedOperationException("not allowed");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
@@ -531,4 +664,17 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return "Player{name=" + name + ", figure=" + figure + "}";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addProperty(Integer id) {
 | 
			
		||||
        properties.add(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void removeProperty(Integer id) {
 | 
			
		||||
        properties.remove(id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,12 @@ import com.jme3.math.ColorRGBA;
 | 
			
		||||
 * Enum representing six distinct colors for players in the game.
 | 
			
		||||
 */
 | 
			
		||||
public enum PlayerColor {
 | 
			
		||||
    GREEN_LIGHT(new ColorRGBA(0 / 255f, 204 / 255f, 0 / 255f, 1)),   // Hex: 00cc00
 | 
			
		||||
    RED(new ColorRGBA(255 / 255f, 0 / 255f, 0 / 255f, 1)),           // Hex: ff0000
 | 
			
		||||
    BLUE(new ColorRGBA(0 / 255f, 0 / 255f, 204 / 255f, 1)),          // Hex: 0000cc
 | 
			
		||||
    PINK(new ColorRGBA(255 / 255f, 77 / 255f, 166 / 255f, 1)),       // Hex: ff4da6
 | 
			
		||||
    GREEN_DARK(new ColorRGBA(0 / 255f, 102 / 255f, 0 / 255f, 1)),    // Hex: 006600
 | 
			
		||||
    YELLOW(new ColorRGBA(255 / 255f, 255 / 255f, 0 / 255f, 1));      // Hex: ffff00
 | 
			
		||||
    CYAN(new ColorRGBA(1 / 255f, 190 / 255f, 254 / 255f, 1)),
 | 
			
		||||
    YELLOW(new ColorRGBA(255 / 255f, 255 / 255f, 0 / 255f, 1)),
 | 
			
		||||
    RED(new ColorRGBA(255 / 255f, 0 / 255f, 0 / 255f, 1)),
 | 
			
		||||
    PINK(new ColorRGBA(255 / 255f, 77 / 255f, 166 / 255f, 1)),
 | 
			
		||||
    GREEN(new ColorRGBA(0 / 255f, 204 / 255f, 0 / 255f, 1)),
 | 
			
		||||
    PURPLE(new ColorRGBA(143 / 255f, 0 / 255f, 255 / 255f, 1));
 | 
			
		||||
 | 
			
		||||
    private final ColorRGBA color;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.NoSuchElementException;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
@@ -16,10 +16,9 @@ import pp.monopoly.model.LimitedLinkedList;
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class PlayerHandler {
 | 
			
		||||
    private List<Player> players = new LimitedLinkedList<>(6);
 | 
			
		||||
    private List<Player> players = new LinkedList<>();
 | 
			
		||||
    private Set<Player> readyPlayers = new HashSet<>();
 | 
			
		||||
    private ServerGameLogic logic;
 | 
			
		||||
    private Player hostPlayer;
 | 
			
		||||
    private transient ServerGameLogic logic;
 | 
			
		||||
    private Player extra = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -55,14 +54,6 @@ public class PlayerHandler {
 | 
			
		||||
        players.addAll(players);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the host player
 | 
			
		||||
     * @return the host player
 | 
			
		||||
     */
 | 
			
		||||
    public Player getHostPlayer() {
 | 
			
		||||
        return hostPlayer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of players
 | 
			
		||||
     * @return number of players in the game
 | 
			
		||||
@@ -114,9 +105,6 @@ public class PlayerHandler {
 | 
			
		||||
            throw new IllegalArgumentException("Player already registered");
 | 
			
		||||
        }
 | 
			
		||||
        players.add(player);
 | 
			
		||||
        if(hostPlayer == null) {
 | 
			
		||||
            hostPlayer = player;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -2,16 +2,25 @@ package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Properties;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collector;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.MonopolyConfig;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyRequest;
 | 
			
		||||
import pp.monopoly.message.client.AlterProperty;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
import pp.monopoly.message.client.ClientInterpreter;
 | 
			
		||||
import pp.monopoly.message.client.EndTurn;
 | 
			
		||||
import pp.monopoly.message.client.NotificationAnswer;
 | 
			
		||||
import pp.monopoly.message.client.PlayerReady;
 | 
			
		||||
import pp.monopoly.message.client.RollDice;
 | 
			
		||||
import pp.monopoly.message.client.TradeOffer;
 | 
			
		||||
import pp.monopoly.message.client.TradeResponse;
 | 
			
		||||
import pp.monopoly.message.client.ViewAssetsRequest;
 | 
			
		||||
import pp.monopoly.message.server.GameOver;
 | 
			
		||||
import pp.monopoly.message.server.GameStart;
 | 
			
		||||
import pp.monopoly.message.server.NextPlayerTurn;
 | 
			
		||||
import pp.monopoly.message.server.PlayerStatusUpdate;
 | 
			
		||||
@@ -19,11 +28,12 @@ import pp.monopoly.message.server.ServerMessage;
 | 
			
		||||
import pp.monopoly.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.message.server.TradeRequest;
 | 
			
		||||
import pp.monopoly.message.server.ViewAssetsResponse;
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.model.Rotation;
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
import pp.monopoly.model.card.DeckHelper;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -132,7 +142,6 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
 | 
			
		||||
        playerHandler.addPlayer(player);
 | 
			
		||||
        LOGGER.log(Level.DEBUG, "Player added: {0}", player.getId());
 | 
			
		||||
        System.out.println("Anzahl Spieler verbunden:"+ playerHandler.getPlayerCount());
 | 
			
		||||
 | 
			
		||||
        return player;
 | 
			
		||||
    }
 | 
			
		||||
@@ -145,20 +154,16 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
     * @param from the connection ID of the player who sent the request
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(BuyPropertyRequest msg, int from) {
 | 
			
		||||
    public void received(BuyPropertyResponse msg, int from) {
 | 
			
		||||
        Player player = playerHandler.getPlayerById(from);
 | 
			
		||||
        if (player != null && state == ServerState.INGAME) {
 | 
			
		||||
            PropertyField property = (PropertyField) boardManager.getFieldAtIndex(player.move(0)); // Assuming player position for property
 | 
			
		||||
        if (player != null) {
 | 
			
		||||
            PropertyField property = (PropertyField) boardManager.getFieldAtIndex(player.getFieldID()); // Assuming player position for property
 | 
			
		||||
            
 | 
			
		||||
            if (property.getOwner() == null && player.getAccountBalance() >= property.getPrice()) {
 | 
			
		||||
                player.buyProperty(property);
 | 
			
		||||
                property.setOwner(player);
 | 
			
		||||
                player.earnMoney(-property.getPrice());
 | 
			
		||||
                LOGGER.log(Level.INFO, "Player {0} bought property {1}", player.getName(), property.getName());
 | 
			
		||||
            } else {
 | 
			
		||||
                LOGGER.log(Level.WARNING, "Player {0} cannot buy property {1}", player.getName(), property.getName());
 | 
			
		||||
            }
 | 
			
		||||
            player.buyProperty(property);
 | 
			
		||||
            System.out.println("Properties:" +player.getProperties().toString());
 | 
			
		||||
            LOGGER.log(Level.INFO, "Player {0} bought property {1}", player.getName(), property.getName());
 | 
			
		||||
        }
 | 
			
		||||
        updateAllPlayers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -170,14 +175,23 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(EndTurn msg, int from) {
 | 
			
		||||
        Player player = playerHandler.getPlayerById(from);
 | 
			
		||||
        if (player != null && state == ServerState.INGAME) {
 | 
			
		||||
        if (player != null && player == playerHandler.getPlayerAtIndex(0)) {
 | 
			
		||||
            if (player.finishTurn()) {
 | 
			
		||||
                LOGGER.log(Level.DEBUG, "Ending turn for player {0}", player.getName());
 | 
			
		||||
                Player next = playerHandler.nextPlayer();
 | 
			
		||||
                next.setActive();
 | 
			
		||||
                send(next, new NextPlayerTurn(next));
 | 
			
		||||
                send(next, new NextPlayerTurn());
 | 
			
		||||
                send(next, new PlayerStatusUpdate(playerHandler));
 | 
			
		||||
                send(player, new PlayerStatusUpdate(playerHandler));
 | 
			
		||||
            } else {
 | 
			
		||||
                send(player, new GameOver(false));
 | 
			
		||||
                playerHandler.removePlayer(player);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if(playerHandler.getPlayers().size() == 1) {
 | 
			
		||||
            send(playerHandler.getPlayerAtIndex(0), new GameOver(true));
 | 
			
		||||
        }
 | 
			
		||||
        updateAllPlayers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -189,12 +203,14 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(PlayerReady msg, int from) {
 | 
			
		||||
        Player player = playerHandler.getPlayerById(from);
 | 
			
		||||
        if(player == playerHandler.getHostPlayer()) {
 | 
			
		||||
        if(player.getId() == 0) {
 | 
			
		||||
            startMoney = msg.getStartMoney();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (player != null) {
 | 
			
		||||
            player.setName(msg.getName());
 | 
			
		||||
            String name = msg.getName();
 | 
			
		||||
            String truc = name.length() > 10 ? name.substring(0, 15) : name;
 | 
			
		||||
            player.setName(truc);
 | 
			
		||||
            player.setFigure(new Figure(1, -10, -10, Rotation.LEFT, msg.getFigure()));
 | 
			
		||||
            //TODO add figure to the map
 | 
			
		||||
            playerHandler.setPlayerReady(player, true);    
 | 
			
		||||
@@ -204,10 +220,10 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
        if(playerHandler.allPlayersReady()) {
 | 
			
		||||
            playerHandler.setStartBalance(startMoney);
 | 
			
		||||
            for (Player p : playerHandler.getPlayers()) {
 | 
			
		||||
               send(p, new GameStart(playerHandler.getPlayers())); 
 | 
			
		||||
               send(p, new GameStart(playerHandler)); 
 | 
			
		||||
            }
 | 
			
		||||
            playerHandler.randomOrder();
 | 
			
		||||
            send(playerHandler.getPlayerAtIndex(0), new NextPlayerTurn(playerHandler.getPlayerAtIndex(0)));
 | 
			
		||||
            send(playerHandler.getPlayerAtIndex(0), new NextPlayerTurn());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -220,8 +236,9 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(RollDice msg, int from) {
 | 
			
		||||
        Player player = playerHandler.getPlayerById(from);
 | 
			
		||||
        if (player != null && state == ServerState.INGAME) {
 | 
			
		||||
        if (player != null && player == playerHandler.getPlayerAtIndex(0)) {
 | 
			
		||||
            send(player, player.rollDice());
 | 
			
		||||
            updateAllPlayers();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -234,11 +251,11 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TradeOffer msg, int from) {
 | 
			
		||||
        Player sender = playerHandler.getPlayerById(from);
 | 
			
		||||
        Player receiver = playerHandler.getPlayerById(msg.getReceiverId());
 | 
			
		||||
        Player receiver = msg.getTradeHandler().getReceiver();
 | 
			
		||||
        
 | 
			
		||||
        if (sender != null && receiver != null) {
 | 
			
		||||
            LOGGER.log(Level.INFO, "Player {0} offers a trade to player {1}", sender.getName(), receiver.getName());
 | 
			
		||||
            send(playerHandler.getPlayerById(msg.getReceiverId()), new TradeRequest(msg.getReceiverId(), msg.getTradeHandler()));
 | 
			
		||||
            send(receiver, new TradeRequest(msg.getTradeHandler()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -250,15 +267,79 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TradeResponse msg, int from) {
 | 
			
		||||
        Player responder = playerHandler.getPlayerById(from);
 | 
			
		||||
        Player initiator = playerHandler.getPlayerById(msg.getInitiatorId());
 | 
			
		||||
 | 
			
		||||
        TradeHandler tradeHandler = msg.getTradeHandler();
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        if (responder != null && initiator != null) {
 | 
			
		||||
            LOGGER.log(Level.INFO, "Player {0} responded to trade with player {1}", responder.getName(), initiator.getName());
 | 
			
		||||
            send(initiator, new TradeReply(msg.getInitiatorId(), msg.getTradeHandler()));
 | 
			
		||||
        
 | 
			
		||||
        Player receiver = playerHandler.getPlayerById(tradeHandler.getReceiver().getId());
 | 
			
		||||
        Player sender = playerHandler.getPlayerById(tradeHandler.getSender().getId());
 | 
			
		||||
        
 | 
			
		||||
        if(msg.isAccepted()) {
 | 
			
		||||
            Set<PropertyField> offered = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
            for (PropertyField propertyField : tradeHandler.getOfferedProperties()) {
 | 
			
		||||
                offered.add( (PropertyField) boardManager.getFieldAtIndex(propertyField.getId()));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Set<PropertyField> requested = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
            for (PropertyField propertyField : tradeHandler.getRequestedProperties()) {
 | 
			
		||||
                requested.add( (PropertyField) boardManager.getFieldAtIndex(propertyField.getId()));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            executeTrade(sender, receiver, offered, requested);
 | 
			
		||||
 | 
			
		||||
            sender.earnMoney(tradeHandler.getRequestedAmount());
 | 
			
		||||
            sender.pay(tradeHandler.getOfferedAmount());
 | 
			
		||||
            receiver.earnMoney(tradeHandler.getOfferedAmount());
 | 
			
		||||
            receiver.pay(tradeHandler.getRequestedAmount());
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < tradeHandler.getOfferedJailCards(); i++) {
 | 
			
		||||
                sender.removeJailCard();
 | 
			
		||||
                receiver.addJailCard();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < tradeHandler.getRequestedJailCards(); i++) {
 | 
			
		||||
                sender.addJailCard();
 | 
			
		||||
                receiver.removeJailCard();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        updateAllPlayers();
 | 
			
		||||
        
 | 
			
		||||
        if (receiver != null && sender != null) {
 | 
			
		||||
            LOGGER.log(Level.INFO, "Player {0} responded to trade with player {1}", receiver.getName(), sender.getName());
 | 
			
		||||
            send(sender, new TradeReply(msg.isAccepted(), msg.getTradeHandler()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Executes the trade by transferring requested properties from the receiver
 | 
			
		||||
     * to the sender and offered properties from the sender to the receiver.
 | 
			
		||||
     */
 | 
			
		||||
    public void executeTrade(Player sender, Player receiver, Set<PropertyField> requestedProperties, Set<PropertyField> offeredProperties) {
 | 
			
		||||
        // Transfer requested properties from receiver to sender
 | 
			
		||||
        for (PropertyField field : requestedProperties) {
 | 
			
		||||
                receiver.removeProperty(field.getId());
 | 
			
		||||
                sender.addProperty(field.getId());
 | 
			
		||||
                field.setOwner(sender); // Update ownership
 | 
			
		||||
                System.out.printf("Property %s transferred from %s to %s.\n", 
 | 
			
		||||
                                field.getName(), receiver.getName(), sender.getName());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Transfer offered properties from sender to receiver
 | 
			
		||||
        for (PropertyField field : offeredProperties) {
 | 
			
		||||
                sender.removeProperty(field.getId());
 | 
			
		||||
                receiver.addProperty(field.getId());
 | 
			
		||||
                field.setOwner(receiver); // Update ownership
 | 
			
		||||
                System.out.printf("Property %s transferred from %s to %s.\n", 
 | 
			
		||||
                                field.getName(), sender.getName(), receiver.getName());
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a ViewAssetsRequest message, sending the player a response containing their assets.
 | 
			
		||||
     *
 | 
			
		||||
@@ -268,11 +349,17 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(ViewAssetsRequest msg, int from) {
 | 
			
		||||
        Player sender = playerHandler.getPlayerById(from);
 | 
			
		||||
        Player player = msg.getPlayer();
 | 
			
		||||
        if (sender != null && player != null) {
 | 
			
		||||
            LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", sender.getName());
 | 
			
		||||
            
 | 
			
		||||
            send(sender, new ViewAssetsResponse(boardManager, player.getProperties(), player.getAccountBalance(), player.getNumJailCard()));
 | 
			
		||||
        if (sender != null) {
 | 
			
		||||
            LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", sender.getName()); 
 | 
			
		||||
            send(sender, new ViewAssetsResponse(boardManager));
 | 
			
		||||
            updateAllPlayers();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateAllPlayers() {
 | 
			
		||||
        for (Player player : playerHandler.getPlayers()) {
 | 
			
		||||
            send(player, new PlayerStatusUpdate(playerHandler));
 | 
			
		||||
            send(player, new ViewAssetsResponse(boardManager));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -292,4 +379,61 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    public DeckHelper getDeckHelper() {
 | 
			
		||||
        return deckHelper;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(AlterProperty msg, int from) {
 | 
			
		||||
        Player sender = playerHandler.getPlayerById(from);
 | 
			
		||||
 | 
			
		||||
        Set<PropertyField> properties = new HashSet<>();
 | 
			
		||||
        for (Integer integer : msg.getProperties()) {
 | 
			
		||||
            properties.add( (PropertyField)boardManager.getFieldAtIndex(integer));
 | 
			
		||||
        } 
 | 
			
		||||
 | 
			
		||||
        if (msg.getKeyword().equals("TakeMortage")) {
 | 
			
		||||
            for (PropertyField field : properties) {
 | 
			
		||||
                field.setMortgaged(true);
 | 
			
		||||
                sender.earnMoney(field.getHypo());
 | 
			
		||||
            }
 | 
			
		||||
        } else if (msg.getKeyword().equals("RepayMortage")) {
 | 
			
		||||
            for (PropertyField field : properties) {
 | 
			
		||||
                if(sender.getAccountBalance() >= field.getHypo()) {
 | 
			
		||||
                    field.setMortgaged(false);
 | 
			
		||||
                    sender.pay(field.getHypo());
 | 
			
		||||
                }
 | 
			
		||||
            }            
 | 
			
		||||
        } else if(msg.getKeyword().equals("BuyHouse")) {
 | 
			
		||||
            for (BuildingProperty field : properties.stream().map(p -> (BuildingProperty) p).collect(Collectors.toList())) {
 | 
			
		||||
                if (boardManager.canBuild(field) && sender.getAccountBalance() >= field.getHousePrice()) {
 | 
			
		||||
                    field.build();
 | 
			
		||||
                    sender.pay(field.getHousePrice());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else if(msg.getKeyword().equals("SellHouse")) {
 | 
			
		||||
            for (BuildingProperty field : properties.stream().map(p -> (BuildingProperty) p).collect(Collectors.toList())) {
 | 
			
		||||
                if (boardManager.canSell(field)) {
 | 
			
		||||
                    field.sell();
 | 
			
		||||
                    sender.earnMoney(field.getHousePrice() / 2);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        updateAllPlayers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(NotificationAnswer msg, int from) {
 | 
			
		||||
        if(msg.getA().equals("UseJailCard")) {
 | 
			
		||||
            playerHandler.getPlayerById(from).useJailCard();
 | 
			
		||||
        } else if (msg.getA().equals("PayJail")) {
 | 
			
		||||
            playerHandler.getPlayerById(from).payBail();
 | 
			
		||||
        } else if(msg.getA().equals("hack")) {
 | 
			
		||||
            for (BuildingProperty bp : boardManager.getPropertyFields( List.of(1,3)).stream().filter(p -> p instanceof BuildingProperty).map(p -> (BuildingProperty) p).collect(Collectors.toList())) {
 | 
			
		||||
                bp.setOwner(playerHandler.getPlayerById(0));
 | 
			
		||||
                playerHandler.getPlayerById(0).addProperty(bp.getId());
 | 
			
		||||
            }
 | 
			
		||||
            playerHandler.getPlayerAtIndex(0).earnMoney(20000);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        updateAllPlayers();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class AlterProperty extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    private String keyword;
 | 
			
		||||
    private Set<Integer> properties;
 | 
			
		||||
 | 
			
		||||
    private AlterProperty() {}
 | 
			
		||||
 | 
			
		||||
    public AlterProperty(String keyword) {
 | 
			
		||||
        this.keyword = keyword;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getKeyword() {
 | 
			
		||||
        return keyword;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setProperties(Set<Integer> properties) {
 | 
			
		||||
        this.properties = properties;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Set<Integer> getProperties() {
 | 
			
		||||
        return properties;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a request from a player to buy a property.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class BuyPropertyRequest extends ClientMessage{
 | 
			
		||||
    private int propertyId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private BuyPropertyRequest() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a BuyPropertyRequest with the specified property ID.
 | 
			
		||||
     *
 | 
			
		||||
     * @param propertyId the ID of the property to buy
 | 
			
		||||
     */
 | 
			
		||||
    public BuyPropertyRequest(int propertyId) {
 | 
			
		||||
        this.propertyId = propertyId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the ID of the property to buy.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the property ID
 | 
			
		||||
     */
 | 
			
		||||
    public int getPropertyId() {
 | 
			
		||||
        return propertyId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a request from a player to buy a property.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class BuyPropertyResponse extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a BuyPropertyRequest
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    public BuyPropertyResponse() {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,7 +17,7 @@ public interface ClientInterpreter {
 | 
			
		||||
     * @param msg  the BuyPropertyRequest to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(BuyPropertyRequest msg, int from);
 | 
			
		||||
    void received(BuyPropertyResponse msg, int from);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received EndTurn.
 | 
			
		||||
@@ -66,4 +66,20 @@ public interface ClientInterpreter {
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(ViewAssetsRequest msg, int from);
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received AlterProperty.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the AlterProperty to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(AlterProperty msg, int from);
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received NotificationAnswer.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the NotificationAnswer to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(NotificationAnswer msg, int from);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,25 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class NotificationAnswer extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    private String A;
 | 
			
		||||
 | 
			
		||||
    private NotificationAnswer() {}
 | 
			
		||||
 | 
			
		||||
    public NotificationAnswer(String A) {
 | 
			
		||||
        this.A = A;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getA() {
 | 
			
		||||
        return A;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -18,11 +18,11 @@ public class PlayerReady extends ClientMessage {
 | 
			
		||||
    private PlayerReady() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a PlayerReady message.
 | 
			
		||||
     *
 | 
			
		||||
     * @param isReady true if the player is ready, false otherwise
 | 
			
		||||
     * @param name    the name of the player
 | 
			
		||||
     * @param color   the color of the player (can be null)
 | 
			
		||||
     * Constructs a PlayerReady message
 | 
			
		||||
     * @param isReady is the player ready
 | 
			
		||||
     * @param name the name of the Player
 | 
			
		||||
     * @param figure the figure corresponding to the Player
 | 
			
		||||
     * @param startMoney the initial capital of the game
 | 
			
		||||
     */
 | 
			
		||||
    public PlayerReady(boolean isReady, String name, String figure, int startMoney) {
 | 
			
		||||
        this.isReady = isReady;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ public class RollDice extends ClientMessage{
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private RollDice() { /* empty */ }
 | 
			
		||||
    public RollDice() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@ import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class TradeOffer extends ClientMessage{
 | 
			
		||||
    private int receiverId;
 | 
			
		||||
    private TradeHandler tradehandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -20,15 +19,12 @@ public class TradeOffer extends ClientMessage{
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeOffer with the specified details.
 | 
			
		||||
     *
 | 
			
		||||
     * @param receiverId the ID of the player receiving the Request
 | 
			
		||||
     * @param tradehandler the tradehandler
 | 
			
		||||
     */
 | 
			
		||||
    public TradeOffer(int receiverId, TradeHandler tradehandler) {
 | 
			
		||||
        this.receiverId = receiverId;
 | 
			
		||||
    public TradeOffer(TradeHandler tradehandler) {
 | 
			
		||||
        this.tradehandler = tradehandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getReceiverId() { return receiverId; }
 | 
			
		||||
    public TradeHandler getTradeHandler() { return tradehandler; }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class TradeResponse extends ClientMessage{
 | 
			
		||||
    private int initiatorId;
 | 
			
		||||
    private boolean status;
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -20,15 +20,15 @@ public class TradeResponse extends ClientMessage{
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeResponse with the specified response details.
 | 
			
		||||
     *
 | 
			
		||||
     * @param initiatorId the ID of the player who initiated the trade
 | 
			
		||||
     * @param accepted true if the offer is accepted, false if declined
 | 
			
		||||
     * @param status the ID of the player who initiated the trade
 | 
			
		||||
     * @param tradeHandler the TradeHandler corresponding to the Trade
 | 
			
		||||
     */
 | 
			
		||||
    public TradeResponse(int initiatorId, TradeHandler tradeHandler) {
 | 
			
		||||
        this.initiatorId = initiatorId;
 | 
			
		||||
    public TradeResponse(boolean status, TradeHandler tradeHandler) {
 | 
			
		||||
        this.status = status;
 | 
			
		||||
        this.tradeHandler = tradeHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getInitiatorId() { return initiatorId; }
 | 
			
		||||
    public boolean isAccepted() { return status; }
 | 
			
		||||
    public TradeHandler getTradeHandler() {
 | 
			
		||||
        return tradeHandler;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||