Compare commits
	
		
			56 Commits
		
	
	
		
			249110f83c
			...
			be568fd8f2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					be568fd8f2 | ||
| 
						 | 
					83aaae9fa6 | ||
| 
						 | 
					10e30d9bd9 | ||
| 
						 | 
					5de76f3226 | ||
| 
						 | 
					e2db058fc7 | ||
| 
						 | 
					7c79bb77e7 | ||
| 
						 | 
					444cf9db4e | ||
| 
						 | 
					9e199d677e | ||
| 
						 | 
					df4a81cbf2 | ||
| 
						 | 
					c635df9369 | ||
| 
						 | 
					c6ad605021 | ||
| 
						 | 
					1e20a2ac6e | ||
| 
						 | 
					36a9a7addf | ||
| 
						 | 
					e1190cd4a2 | ||
| 
						 | 
					34ecd2277b | ||
| 
						 | 
					5959f36a21 | ||
| 
						 | 
					1db2d9ebac | ||
| 
						 | 
					54bac50a7e | ||
| 
						 | 
					274ed2b25d | ||
| 
						 | 
					371fa83319 | ||
| 
						 | 
					c1faf91188 | ||
| 
						 | 
					617d707df8 | ||
| 
						 | 
					d18cea435c | ||
| 
						 | 
					1543f0dcea | ||
| 
						 | 
					ae181e4eff | ||
| 
						 | 
					fa96324c15 | ||
| 
						 | 
					9f559fe0d7 | ||
| 
						 | 
					cf6ee535b8 | ||
| 
						 | 
					be89bf1a27 | ||
| 
						 | 
					6f2027c2fb | ||
| 
						 | 
					6e99f17787 | ||
| 
						 | 
					b7e2e3213a | ||
| 
						 | 
					3ea6452d6d | ||
| 
						 | 
					fd3c141967 | ||
| 
						 | 
					b3d2dfed08 | ||
| 
						 | 
					5306208107 | ||
| 
						 | 
					2a7cbeed89 | ||
| 
						 | 
					0a34751825 | ||
| 
						 | 
					996bc0118a | ||
| 
						 | 
					bbcb12c131 | ||
| 
						 | 
					1969afc58f | ||
| 
						 | 
					ad0c432102 | ||
| 
						 | 
					315739646c | ||
| 
						 | 
					330e788498 | ||
| 
						 | 
					fc5a2809c8 | ||
| 
						 | 
					0acb63adb6 | ||
| 
						 | 
					b4c664927b | ||
| 
						 | 
					ed27e0aaf1 | ||
| 
						 | 
					98f453d7f8 | ||
| 
						 | 
					8de7499c21 | ||
| 
						 | 
					b680d7bc58 | ||
| 
						 | 
					30559bf443 | ||
| 
						 | 
					8774c4246d | ||
| 
						 | 
					7b82b20736 | ||
| 
						 | 
					698937e77c | ||
| 
						 | 
					7cbf000c44 | 
@@ -19,6 +19,8 @@ import java.util.Deque;
 | 
			
		||||
 | 
			
		||||
import static java.lang.Math.max;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Manages dialog boxes within the application, handling their display, positioning, and focus.
 | 
			
		||||
 */
 | 
			
		||||
@@ -28,11 +30,15 @@ public class DialogManager {
 | 
			
		||||
     */
 | 
			
		||||
    private final SimpleApplication app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private final static Logger LOGGER = System.getLogger(DialogManager.class.getName());
 | 
			
		||||
    /**
 | 
			
		||||
     * A stack to keep track of the dialogs.
 | 
			
		||||
     */
 | 
			
		||||
    private final Deque<Dialog> dialogStack = new ArrayDeque<>();
 | 
			
		||||
 | 
			
		||||
    private final Deque<PopupDialog> popUpStack = new ArrayDeque<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a DialogManager for the specified application.
 | 
			
		||||
     *
 | 
			
		||||
@@ -112,11 +118,45 @@ public class DialogManager {
 | 
			
		||||
     * @param dialog the dialog to open
 | 
			
		||||
     */
 | 
			
		||||
    public void open(Dialog dialog) {
 | 
			
		||||
 | 
			
		||||
        if(dialog instanceof PopupDialog) {
 | 
			
		||||
            popUpStack.push((PopupDialog) dialog);
 | 
			
		||||
            processPopUps();
 | 
			
		||||
        } else {
 | 
			
		||||
            showDialog(dialog);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void showDialog(Dialog dialog) {
 | 
			
		||||
        dialogStack.push(dialog);
 | 
			
		||||
        if(dialog instanceof PopupDialog) {
 | 
			
		||||
            ((PopupDialog)dialog).show();
 | 
			
		||||
        }
 | 
			
		||||
        dialog.update();
 | 
			
		||||
        app.getGuiNode().attachChild(dialog);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void processPopUps() {
 | 
			
		||||
        if (popUpStack.isEmpty()) {
 | 
			
		||||
            return; // Nothing to process
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        // Check if a popup dialog is already on top
 | 
			
		||||
        if (dialogStack.peek() instanceof PopupDialog) {
 | 
			
		||||
            LOGGER.log(Logger.Level.DEBUG, "Popup dialog already on top");
 | 
			
		||||
            return; // Already a popup dialog on top
 | 
			
		||||
        } else {
 | 
			
		||||
            
 | 
			
		||||
            // Pop the next popup from the stack and validate before showing
 | 
			
		||||
            PopupDialog popUp = popUpStack.pop();
 | 
			
		||||
                
 | 
			
		||||
            showDialog( (Dialog) popUp);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the specified dialog is the topmost dialog in the dialog stack.
 | 
			
		||||
     *
 | 
			
		||||
@@ -140,6 +180,8 @@ public class DialogManager {
 | 
			
		||||
        if (!dialogStack.isEmpty())
 | 
			
		||||
            dialogStack.peek().update();
 | 
			
		||||
        app.getGuiNode().detachChild(dialog);
 | 
			
		||||
 | 
			
		||||
        processPopUps();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -150,6 +192,11 @@ public class DialogManager {
 | 
			
		||||
        dialogStack.peek().escape();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates all dialogs in the dialog stack.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta the time since the last update
 | 
			
		||||
     */
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        for (Dialog dialog : dialogStack)
 | 
			
		||||
            dialog.update(delta);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Projekte/jme-common/src/main/java/pp/dialog/PopupDialog.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,10 @@
 | 
			
		||||
package pp.dialog;
 | 
			
		||||
 | 
			
		||||
/** An interface for tagging Dialogs as PopUps for handling in the DialogManager */
 | 
			
		||||
public interface PopupDialog {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shows the popup.
 | 
			
		||||
     */
 | 
			
		||||
    void show();
 | 
			
		||||
}
 | 
			
		||||
@@ -405,3 +405,44 @@ selector("button-clear", "pp") { playerColor ->
 | 
			
		||||
    textHAlignment = HAlignment.Center // Text-Zentrierung
 | 
			
		||||
    textVAlignment = VAlignment.Center // Text-Zentrierung
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def enabledCommandToolbar2= new Command<Button>() {
 | 
			
		||||
    void execute(Button source) {
 | 
			
		||||
        if (source.isEnabled()){
 | 
			
		||||
            source.setColor(ColorRGBA.White)
 | 
			
		||||
            def orangeBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)); // Orange background
 | 
			
		||||
            source.setBackground(orangeBackground);
 | 
			
		||||
        } else{
 | 
			
		||||
            source.setColor(ColorRGBA.White)
 | 
			
		||||
            def grayBackground = new QuadBackgroundComponent(ColorRGBA.Gray); // Gray background
 | 
			
		||||
            source.setBackground(grayBackground);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def stdButtonCommandsToolbar2 =[
 | 
			
		||||
        (ButtonAction.Down)    : [pressedCommand],
 | 
			
		||||
        (ButtonAction.Up)      : [pressedCommand],
 | 
			
		||||
        (ButtonAction.Enabled) : [enabledCommandToolbar2],
 | 
			
		||||
        (ButtonAction.Disabled): [enabledCommandToolbar2]
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
selector("button-toolbar2", "pp") {
 | 
			
		||||
    def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Orange border
 | 
			
		||||
    def innerBackground = new QuadBackgroundComponent(buttonBgColor) // Inner button background
 | 
			
		||||
 | 
			
		||||
    // Apply the outer border as the main background
 | 
			
		||||
    background = outerBackground
 | 
			
		||||
 | 
			
		||||
    // Use insets to create a margin/padding effect for the inner background
 | 
			
		||||
    insets = new Insets3f(3, 3, 3, 3) // Adjust the border thickness
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
    buttonCommands = stdButtonCommandsToolbar2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,33 +3,35 @@ package pp.monopoly.client;
 | 
			
		||||
import com.jme3.app.Application;
 | 
			
		||||
import com.jme3.app.state.AppStateManager;
 | 
			
		||||
import com.jme3.asset.AssetManager;
 | 
			
		||||
import com.jme3.effect.ParticleEmitter;
 | 
			
		||||
import com.jme3.effect.ParticleMesh;
 | 
			
		||||
import com.jme3.effect.shapes.EmitterSphereShape;
 | 
			
		||||
import com.jme3.light.AmbientLight;
 | 
			
		||||
import com.jme3.light.DirectionalLight;
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.FaceCullMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.FastMath;
 | 
			
		||||
import com.jme3.math.Quaternion;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.renderer.Camera;
 | 
			
		||||
import com.jme3.renderer.queue.RenderQueue;
 | 
			
		||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.Node;
 | 
			
		||||
import com.jme3.scene.Spatial;
 | 
			
		||||
import com.jme3.scene.shape.Box;
 | 
			
		||||
import com.jme3.scene.shape.Cylinder;
 | 
			
		||||
import com.jme3.shadow.DirectionalLightShadowRenderer;
 | 
			
		||||
import com.jme3.shadow.EdgeFilteringMode;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.jme3.util.SkyFactory;
 | 
			
		||||
import com.jme3.util.TangentBinormalGenerator;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.gui.BobTheBuilder;
 | 
			
		||||
import pp.monopoly.client.gui.CameraController;
 | 
			
		||||
import pp.monopoly.client.gui.CameraInputHandler;
 | 
			
		||||
import pp.monopoly.client.gui.Toolbar;
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.client.gui.FigureControl;
 | 
			
		||||
import static pp.util.FloatMath.TWO_PI;
 | 
			
		||||
import static pp.util.FloatMath.cos;
 | 
			
		||||
import static pp.util.FloatMath.sin;
 | 
			
		||||
import static pp.util.FloatMath.sqrt;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Manages the rendering and visual aspects of the sea and sky in the Battleship game.
 | 
			
		||||
@@ -65,9 +67,18 @@ public class BoardAppState extends MonopolyAppState {
 | 
			
		||||
    /**
 | 
			
		||||
     * The pop-up manager for displaying messages and notifications.
 | 
			
		||||
     */
 | 
			
		||||
    private PopUpManager popUpManager;;
 | 
			
		||||
    private PopUpManager popUpManager;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The camera controller for managing the camera's position and orientation.
 | 
			
		||||
     */
 | 
			
		||||
    private CameraController cameraController;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The input handler for controlling the camera's movement and rotation.
 | 
			
		||||
     */
 | 
			
		||||
    private CameraInputHandler cameraInputHandler;
 | 
			
		||||
 | 
			
		||||
    private Vector3f currentTarget = new Vector3f(0f,0,0f);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the state by setting up the sky, lights, and other visual components.
 | 
			
		||||
@@ -79,10 +90,19 @@ public class BoardAppState extends MonopolyAppState {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void initialize(AppStateManager stateManager, Application application) {
 | 
			
		||||
        super.initialize(stateManager, application);
 | 
			
		||||
 | 
			
		||||
        // Initialisiere den CameraController zuerst
 | 
			
		||||
        cameraController = new CameraController(getApp().getCamera(), getApp());
 | 
			
		||||
 | 
			
		||||
        // Danach den CameraInputHandler mit dem initialisierten CameraController
 | 
			
		||||
        cameraInputHandler = new CameraInputHandler(cameraController, getApp().getInputManager());
 | 
			
		||||
 | 
			
		||||
        popUpManager = new PopUpManager(getApp());
 | 
			
		||||
        viewNode.attachChild(sceneNode);
 | 
			
		||||
 | 
			
		||||
        setupLights();
 | 
			
		||||
        setupSky();
 | 
			
		||||
        // setupSky();
 | 
			
		||||
        getApp().getViewPort().setBackgroundColor(new com.jme3.math.ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
@@ -94,6 +114,8 @@ public class BoardAppState extends MonopolyAppState {
 | 
			
		||||
        getApp().getRootNode().detachAllChildren();
 | 
			
		||||
        getApp().getGuiNode().detachAllChildren();
 | 
			
		||||
 | 
			
		||||
        getApp().getDialogManager().close(getApp().getDialogManager().getDialogStack().peek());
 | 
			
		||||
 | 
			
		||||
        new Toolbar(getApp()).open();
 | 
			
		||||
        sceneNode.detachAllChildren();
 | 
			
		||||
        setupScene();
 | 
			
		||||
@@ -103,30 +125,6 @@ public class BoardAppState extends MonopolyAppState {
 | 
			
		||||
        }
 | 
			
		||||
        getApp().getRootNode().attachChild(viewNode);
 | 
			
		||||
    }
 | 
			
		||||
    //TODO remove this only for camera testing
 | 
			
		||||
    private static final float ABOVE_SEA_LEVEL = 10f;
 | 
			
		||||
    private static final float INCLINATION = 2.5f;
 | 
			
		||||
    private float cameraAngle;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adjusts the camera position and orientation to create a circular motion around
 | 
			
		||||
     * the center of the map. This provides a dynamic view of the sea and surrounding environment.
 | 
			
		||||
     */
 | 
			
		||||
    private void adjustCamera() {
 | 
			
		||||
        final Board board = getGameLogic().getBoard();
 | 
			
		||||
        final float mx = 0.5f * board.getWidth();
 | 
			
		||||
        final float my = 0.5f * board.getHeight();
 | 
			
		||||
        final float radius = 2f * sqrt(mx * mx + my + my);
 | 
			
		||||
        final float cos = radius * cos(cameraAngle);
 | 
			
		||||
        final float sin = radius * sin(cameraAngle);
 | 
			
		||||
        final float x = mx - cos;
 | 
			
		||||
        final float y = my - sin;
 | 
			
		||||
        final Camera camera = getApp().getCamera();
 | 
			
		||||
        camera.setLocation(new Vector3f(30,20,0));
 | 
			
		||||
        camera.lookAt(new Vector3f(getCurrentTarget()),
 | 
			
		||||
                                    Vector3f.UNIT_Y);
 | 
			
		||||
        camera.update();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -143,18 +141,7 @@ public class BoardAppState extends MonopolyAppState {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the state each frame, moving the camera to simulate it circling around the map.
 | 
			
		||||
     *
 | 
			
		||||
     * @param tpf the time per frame (seconds)
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        super.update(tpf);
 | 
			
		||||
        //TODO remove this only for camera testing
 | 
			
		||||
        cameraAngle += TWO_PI * 0.05f * tpf;
 | 
			
		||||
        adjustCamera();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up the lighting for the scene, including directional and ambient lights.
 | 
			
		||||
@@ -183,17 +170,79 @@ public class BoardAppState extends MonopolyAppState {
 | 
			
		||||
     */
 | 
			
		||||
    private void setupSky() {
 | 
			
		||||
        final AssetManager assetManager = getApp().getAssetManager();
 | 
			
		||||
        final Texture west = assetManager.loadTexture("Pictures/Backdrop/west.jpg"); //NON-NLS
 | 
			
		||||
        final Texture east = assetManager.loadTexture("Pictures/Backdrop/ost.jpg"); //NON-NLS
 | 
			
		||||
        final Texture north = assetManager.loadTexture("Pictures/Backdrop/nord.jpg"); //NON-NLS
 | 
			
		||||
        final Texture south = assetManager.loadTexture("Pictures/Backdrop/sued.jpg"); //NON-NLS
 | 
			
		||||
        final Texture up = assetManager.loadTexture("Pictures/Backdrop/sued.jpg"); //NON-NLS
 | 
			
		||||
        final Texture down = assetManager.loadTexture("Pictures/Backdrop/sued.jpg"); //NON-NLS
 | 
			
		||||
        final Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down);
 | 
			
		||||
        // sky.rotate(0, PI, 0);
 | 
			
		||||
        viewNode.attachChild(sky);
 | 
			
		||||
 | 
			
		||||
        // Create a cylinder for the sky
 | 
			
		||||
        float radius = 500f; // Adjust radius as needed
 | 
			
		||||
        float height = 200f; // Height of the cylinder
 | 
			
		||||
        int radialSamples = 64; // Number of radial segments for smoothness
 | 
			
		||||
        int axisSamples = 2; // No vertical divisions (flat vertical surface)
 | 
			
		||||
        
 | 
			
		||||
        Cylinder skyCylinder = new Cylinder(axisSamples, radialSamples, radius, height, true);
 | 
			
		||||
 | 
			
		||||
        // Create a geometry for the cylinder
 | 
			
		||||
        Geometry skyGeometry = new Geometry("CylinderSky", skyCylinder);
 | 
			
		||||
 | 
			
		||||
        // Load the cylindrical texture
 | 
			
		||||
        Texture cylinderTexture = assetManager.loadTexture("Textures/CylinderMap.jpg");
 | 
			
		||||
 | 
			
		||||
        // Create a material and apply the texture
 | 
			
		||||
        Material skyMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        skyMaterial.setTexture("ColorMap", cylinderTexture);
 | 
			
		||||
        skyMaterial.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); // Render inside of the cylinder
 | 
			
		||||
 | 
			
		||||
        // Assign material to the geometry
 | 
			
		||||
        skyGeometry.setMaterial(skyMaterial);
 | 
			
		||||
        skyGeometry.rotate(-FastMath.HALF_PI, 0, 0); // Rotate 90° along the Y-axis
 | 
			
		||||
 | 
			
		||||
        // Position and attach the cylinder to the scene
 | 
			
		||||
        skyGeometry.setQueueBucket(RenderQueue.Bucket.Sky); // Ensure it's rendered in the background
 | 
			
		||||
        skyGeometry.setCullHint(Spatial.CullHint.Never); // Always render the sky
 | 
			
		||||
 | 
			
		||||
        viewNode.attachChild(skyGeometry);
 | 
			
		||||
 | 
			
		||||
        addCylinderCaps();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds top and bottom caps to the cylinder sky.
 | 
			
		||||
     */
 | 
			
		||||
    private void addCylinderCaps() {
 | 
			
		||||
        final AssetManager assetManager = getApp().getAssetManager();
 | 
			
		||||
 | 
			
		||||
        float radius = 500f; // Match the cylinder's radius
 | 
			
		||||
        float height = 225f; // Match the cylinder's height
 | 
			
		||||
        int radialSamples = 64; // Match the cylinder's radial samples
 | 
			
		||||
 | 
			
		||||
        // Bottom Cap
 | 
			
		||||
        Cylinder bottomCap = new Cylinder(2, radialSamples, radius, 0.01f, true, false); // Thin bottom cap
 | 
			
		||||
        Geometry bottomGeometry = new Geometry("BottomCap", bottomCap);
 | 
			
		||||
        bottomGeometry.setLocalTranslation(0, -height / 2, 0); // Position at the bottom
 | 
			
		||||
        bottomGeometry.rotate(FastMath.HALF_PI, 0, 0); // Rotate to make it horizontal
 | 
			
		||||
        Material bottomMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        bottomMaterial.setTexture("ColorMap", assetManager.loadTexture("Textures/grass.jpg")); // Bottom texture
 | 
			
		||||
        bottomMaterial.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); // Render both sides
 | 
			
		||||
        bottomGeometry.setMaterial(bottomMaterial);
 | 
			
		||||
        bottomGeometry.setQueueBucket(RenderQueue.Bucket.Sky);
 | 
			
		||||
        bottomGeometry.setCullHint(Spatial.CullHint.Never);
 | 
			
		||||
 | 
			
		||||
        // Top Cap
 | 
			
		||||
        Cylinder topCap = new Cylinder(2, radialSamples, radius, 0.01f, true, false); // Thin top cap
 | 
			
		||||
        Geometry topGeometry = new Geometry("TopCap", topCap);
 | 
			
		||||
        topGeometry.setLocalTranslation(0, height / 2, 0); // Position at the top
 | 
			
		||||
        topGeometry.rotate(FastMath.HALF_PI, 0, 0); // Rotate to make it horizontal
 | 
			
		||||
        Material topMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        topMaterial.setTexture("ColorMap", assetManager.loadTexture("Textures/Top.png")); // Top texture
 | 
			
		||||
        topMaterial.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); // Render both sides
 | 
			
		||||
        topGeometry.setMaterial(topMaterial);
 | 
			
		||||
        topGeometry.setQueueBucket(RenderQueue.Bucket.Sky);
 | 
			
		||||
        topGeometry.setCullHint(Spatial.CullHint.Never);
 | 
			
		||||
 | 
			
		||||
        // Attach caps to the view node
 | 
			
		||||
        viewNode.attachChild(bottomGeometry);
 | 
			
		||||
        viewNode.attachChild(topGeometry);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up the sea surface in the scene. This includes creating the sea mesh,
 | 
			
		||||
     * applying textures, and enabling shadows.
 | 
			
		||||
@@ -203,39 +252,111 @@ public class BoardAppState extends MonopolyAppState {
 | 
			
		||||
        final float x = board.getWidth();
 | 
			
		||||
        final float y = board.getHeight();
 | 
			
		||||
        final Box seaMesh = new Box(y, 0.1f, x);
 | 
			
		||||
        final Geometry seaGeo = new Geometry("sea", seaMesh); //NONs-NLS
 | 
			
		||||
        final Geometry seaGeo = new Geometry("sea", seaMesh); //NON-NLS
 | 
			
		||||
        seaGeo.setLocalTranslation(new Vector3f(0, -0.1f, 0));
 | 
			
		||||
        Quaternion rotation = new com.jme3.math.Quaternion();
 | 
			
		||||
        rotation.fromAngleAxis(FastMath.HALF_PI, com.jme3.math.Vector3f.UNIT_Y);
 | 
			
		||||
        Quaternion rotation = new Quaternion();
 | 
			
		||||
        rotation.fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y);
 | 
			
		||||
        seaGeo.setLocalRotation(rotation);
 | 
			
		||||
        final Material seaMat = new Material(getApp().getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
 | 
			
		||||
        Texture texture = getApp().getAssetManager().loadTexture("Pictures/board2.png");
 | 
			
		||||
        Texture texture = getApp().getAssetManager().loadTexture(BoardTexture);
 | 
			
		||||
        seaMat.setTexture("DiffuseMap", texture);
 | 
			
		||||
        seaGeo.setMaterial(seaMat);
 | 
			
		||||
        seaGeo.setShadowMode(ShadowMode.CastAndReceive);
 | 
			
		||||
        TangentBinormalGenerator.generate(seaGeo);
 | 
			
		||||
    
 | 
			
		||||
        sceneNode.attachChild(createCardDeck());
 | 
			
		||||
        sceneNode.attachChild(seaGeo);
 | 
			
		||||
    
 | 
			
		||||
        // Schneefall hinzufügen
 | 
			
		||||
        addSnowEffect(sceneNode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card deck with six event and six community cards.
 | 
			
		||||
     * @return the node containing the card deck
 | 
			
		||||
     */
 | 
			
		||||
    private Node createCardDeck() {
 | 
			
		||||
        Node cardDeck = new Node("cardDeck");
 | 
			
		||||
        Spatial card = getApp().getAssetManager().loadModel("models/Kartendecks/Ereigniskarten_Deck.j3o");
 | 
			
		||||
        card.setLocalTranslation(5.5f, 0, 2.7f);
 | 
			
		||||
        card.setLocalScale(4.1f);
 | 
			
		||||
        card.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.QUARTER_PI, Vector3f.UNIT_Y));
 | 
			
		||||
    
 | 
			
		||||
        Spatial card2 = getApp().getAssetManager().loadModel("models/Kartendecks/Gemeinschaftskarten_Deck.j3o");
 | 
			
		||||
        card2.setLocalTranslation(-1.4f, 0, -3.8f);
 | 
			
		||||
        card2.setLocalScale(4.1f);
 | 
			
		||||
        card2.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.QUARTER_PI , Vector3f.UNIT_Y));
 | 
			
		||||
        // Ereigniskarten
 | 
			
		||||
        Vector3f basePosition1 = new Vector3f(3.1f, 0.4f, 3.8f); // Basisposition für Ereigniskarten
 | 
			
		||||
        float baseRotation1 = -60; // Basisrotation in Grad
 | 
			
		||||
        for (int i = 0; i < 6; i++) {
 | 
			
		||||
            Box box = new Box(1.2f, 0.05f, 1.8f); // Sehr flaches Rechteck
 | 
			
		||||
            Geometry flatCard = new Geometry("Ereigniskarten_" + i, box);
 | 
			
		||||
            Material mat = new Material(getApp().getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
            mat.setTexture("ColorMap", getApp().getAssetManager().loadTexture("Textures/Ereigniskarten.png"));
 | 
			
		||||
            flatCard.setMaterial(mat);
 | 
			
		||||
    
 | 
			
		||||
            // Position und Rotation für die Karte
 | 
			
		||||
            flatCard.setLocalTranslation(basePosition1.x, basePosition1.y - (i * 0.08f), basePosition1.z);
 | 
			
		||||
            flatCard.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD * (baseRotation1 - (i * 5)), Vector3f.UNIT_Y));
 | 
			
		||||
    
 | 
			
		||||
            cardDeck.attachChild(flatCard);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        // Gemeinschaftskarten
 | 
			
		||||
        Vector3f basePosition2 = new Vector3f(-3.3f, 0.4f, -3.8f); // Basisposition für Gemeinschaftskarten
 | 
			
		||||
        float baseRotation2 = -220; // Basisrotation in Grad
 | 
			
		||||
        for (int i = 0; i < 6; i++) {
 | 
			
		||||
            Box box = new Box(1.2f, 0.04f, 1.8f); // Sehr flaches Rechteck
 | 
			
		||||
            Geometry flatCard = new Geometry("Gemeinschaftskarten_" + i, box);
 | 
			
		||||
            Material mat = new Material(getApp().getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
            mat.setTexture("ColorMap", getApp().getAssetManager().loadTexture("Textures/Gemeinschaftskarten.png"));
 | 
			
		||||
            flatCard.setMaterial(mat);
 | 
			
		||||
    
 | 
			
		||||
            // Position und Rotation für die Karte
 | 
			
		||||
            flatCard.setLocalTranslation(basePosition2.x, basePosition2.y - (i * 0.08f), basePosition2.z);
 | 
			
		||||
            flatCard.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD * (baseRotation2 - (i * 5)), Vector3f.UNIT_Y));
 | 
			
		||||
    
 | 
			
		||||
            cardDeck.attachChild(flatCard);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        cardDeck.attachChild(card);
 | 
			
		||||
        cardDeck.attachChild(card2);
 | 
			
		||||
        return cardDeck;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector3f getCurrentTarget(){
 | 
			
		||||
        return currentTarget;
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a snow effect to the scene by creating a particle emitter with snowflakes.
 | 
			
		||||
     * @param parentNode the parent node to attach the snow effect to
 | 
			
		||||
     */
 | 
			
		||||
    private void addSnowEffect(Node parentNode) {
 | 
			
		||||
        // ParticleEmitter für Schnee
 | 
			
		||||
        ParticleEmitter snowEmitter = new ParticleEmitter("Snow", ParticleMesh.Type.Triangle, 5000);
 | 
			
		||||
        Material snowMat = new Material(getApp().getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
 | 
			
		||||
        snowMat.setTexture("Texture", getApp().getAssetManager().loadTexture("Textures/snowflake.png")); // Schneeflocken-Textur
 | 
			
		||||
        snowEmitter.setMaterial(snowMat);
 | 
			
		||||
 | 
			
		||||
        // Eigenschaften für Schneepartikel
 | 
			
		||||
        snowEmitter.setImagesX(1);
 | 
			
		||||
        snowEmitter.setImagesY(1);
 | 
			
		||||
        snowEmitter.setEndColor(new ColorRGBA(1f, 1f, 1f, 0.5f)); // Weiß, halbtransparent
 | 
			
		||||
        snowEmitter.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f)); // Vollweiß
 | 
			
		||||
        snowEmitter.setStartSize(0.1f);
 | 
			
		||||
        snowEmitter.setEndSize(0.2f);
 | 
			
		||||
        snowEmitter.setGravity(0, 0.5f, 0); // Langsames Fallen
 | 
			
		||||
        snowEmitter.setLowLife(3f);
 | 
			
		||||
        snowEmitter.setHighLife(15f);
 | 
			
		||||
        snowEmitter.getParticleInfluencer().setInitialVelocity(new Vector3f(0, -1, 0));
 | 
			
		||||
        snowEmitter.getParticleInfluencer().setVelocityVariation(0.3f);
 | 
			
		||||
 | 
			
		||||
        // Spawn-Bereich für Schneeflocken definieren
 | 
			
		||||
        snowEmitter.setParticlesPerSec(200);
 | 
			
		||||
        snowEmitter.setLocalTranslation(0, 10, 0);
 | 
			
		||||
        snowEmitter.setShape(new EmitterSphereShape(new Vector3f(0, 0, 0), 15)); // Bereich von -15 bis 15
 | 
			
		||||
 | 
			
		||||
        // Emitter zur Szene hinzufügen
 | 
			
		||||
        parentNode.attachChild(snowEmitter);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the state by moving the camera and updating the visual elements.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param tpf the time per frame
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        super.update(tpf);
 | 
			
		||||
        cameraController.update(tpf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -48,16 +48,27 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
     */
 | 
			
		||||
    private static final String VOLUME_PREF = "volume"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    /** The sound effect for passing the start field. */
 | 
			
		||||
    private AudioNode passStartSound;
 | 
			
		||||
    /** The sound effect for drawing an event card. */
 | 
			
		||||
    private AudioNode eventCardSound;
 | 
			
		||||
    /** The sound effect for going to the gulag. */
 | 
			
		||||
    private AudioNode gulagSound;
 | 
			
		||||
    /** The sound effect for rolling the dice. */
 | 
			
		||||
    private AudioNode diceRollSound;
 | 
			
		||||
    /** The sound effect for collecting money. */
 | 
			
		||||
    private AudioNode moneyCollectSound;
 | 
			
		||||
    /** The sound effect for losing money. */
 | 
			
		||||
    private AudioNode moneyLostSound;
 | 
			
		||||
    /** The sound effect for accepting a trade. */
 | 
			
		||||
    private AudioNode tradeAcceptedSound;
 | 
			
		||||
    /** The sound effect for rejecting a trade. */
 | 
			
		||||
    private AudioNode tradeRejectedSound;
 | 
			
		||||
    /** The sound effect for winning the game. */
 | 
			
		||||
    private AudioNode winnerSound;
 | 
			
		||||
    /** The sound effect for loosing the game. */
 | 
			
		||||
    private AudioNode looserSound;
 | 
			
		||||
    /** The sound effect for pressing a button. */
 | 
			
		||||
    private AudioNode buttonSound;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -172,12 +172,19 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
    private AppSettings makeSettings() {
 | 
			
		||||
        final AppSettings settings = new AppSettings(true);
 | 
			
		||||
        settings.setTitle(lookup("monopoly.name"));
 | 
			
		||||
        try {
 | 
			
		||||
            settings.setIcons(new Image[]{ImageIO.read(new File("src/main/resources/icons/Uniman.png"))});
 | 
			
		||||
        }
 | 
			
		||||
        catch (IOException e) {
 | 
			
		||||
            LOGGER.log(Level.ERROR, e.getMessage());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set the icon for the application window
 | 
			
		||||
        
 | 
			
		||||
        // try {
 | 
			
		||||
        //     // Prüfen, ob das Betriebssystem ein Mac-System ist
 | 
			
		||||
        //     if (!System.getProperty("os.name").toLowerCase().contains("mac")) {
 | 
			
		||||
        //         settings.setIcons(new Image[]{ImageIO.read(new File("src/main/resources/icons/Uniman.png"))});
 | 
			
		||||
        //     } else {
 | 
			
		||||
        //         LOGGER.log(Level.INFO, "Icon setting skipped on macOS due to system restrictions.");
 | 
			
		||||
        //     }
 | 
			
		||||
        // } catch (IOException e) {
 | 
			
		||||
        //     LOGGER.log(Level.ERROR, e.getMessage());
 | 
			
		||||
        // }
 | 
			
		||||
        settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight());
 | 
			
		||||
        settings.setFullscreen(config.fullScreen());
 | 
			
		||||
        settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer());
 | 
			
		||||
@@ -289,6 +296,8 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
 | 
			
		||||
            stateManager.attach(stats);
 | 
			
		||||
        }
 | 
			
		||||
        flyCam.setEnabled(false);
 | 
			
		||||
        flyCam.setMoveSpeed(4f); // Setzt die Bewegungsgeschwindigkeit der Kamera (Standardwert ist 1f)
 | 
			
		||||
 | 
			
		||||
        stateManager.detach(stateManager.getState(StatsAppState.class));
 | 
			
		||||
        stateManager.detach(stateManager.getState(DebugKeysAppState.class));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -106,6 +106,26 @@ public class MonopolyAppConfig extends MonopolyClientConfig {
 | 
			
		||||
    @Property("overlay.top.color") //NON-NLS
 | 
			
		||||
    private ColorRGBA topColor = ColorRGBA.White;
 | 
			
		||||
 | 
			
		||||
    private ColorRGBA applyGammaCorrection(ColorRGBA color) {
 | 
			
		||||
        return new ColorRGBA(
 | 
			
		||||
            correctGamma(color.r),
 | 
			
		||||
            correctGamma(color.g),
 | 
			
		||||
            correctGamma(color.b),
 | 
			
		||||
            color.a // Alpha bleibt unverändert
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private float correctGamma(float channel) {
 | 
			
		||||
        // Formel: ((RGB / 255)^2.2) * 255
 | 
			
		||||
        float normalized = channel / 255.0f; // RGB normalisieren (0-1)
 | 
			
		||||
        float gammaCorrected = (float) Math.pow(normalized, 2.2); // ^2.2
 | 
			
		||||
        return gammaCorrected * 255.0f; // Zurückskalieren auf 0-255
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private float correctGamma(float channel, float gamma) {
 | 
			
		||||
        return (float) Math.pow(channel, gamma);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a default {@code MonopolyAppConfig} with predefined values.
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -27,15 +27,32 @@ import pp.monopoly.notification.EventCardEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.PopUpEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is responsible for managing the popups that are shown to the user.
 | 
			
		||||
 * It listens for events that require a popup to be shown and then shows the
 | 
			
		||||
 * appropriate popup.
 | 
			
		||||
 */
 | 
			
		||||
public class PopUpManager implements GameEventListener {
 | 
			
		||||
 | 
			
		||||
    /** The MonopolyApp instance */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor for the PopUpManager.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param app The MonopolyApp instance
 | 
			
		||||
     */
 | 
			
		||||
    public PopUpManager(MonopolyApp app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        app.getGameLogic().addListener(this);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This method is called when a PopUpEvent is received.
 | 
			
		||||
     * It checks the message of the event and shows the appropriate popup.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param event The PopUpEvent
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(PopUpEvent event) {
 | 
			
		||||
        if (event.msg().equals("Buy")) {
 | 
			
		||||
@@ -56,7 +73,7 @@ public class PopUpManager implements GameEventListener {
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }, 2500);
 | 
			
		||||
            }, 6000);
 | 
			
		||||
        } else if (event.msg().equals("Winner")) {
 | 
			
		||||
            new WinnerPopUp(app).open();
 | 
			
		||||
        } else if (event.msg().equals("Looser")) {
 | 
			
		||||
@@ -84,6 +101,12 @@ public class PopUpManager implements GameEventListener {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This method is called when an EventCardEvent is received.
 | 
			
		||||
     * It shows the EventCardPopup.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param event The EventCardEvent
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(EventCardEvent event) {
 | 
			
		||||
        Timer timer = new Timer();
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,9 @@ package pp.monopoly.client.gui;
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.FastMath;
 | 
			
		||||
import com.jme3.math.Quaternion;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.Node;
 | 
			
		||||
@@ -14,18 +17,35 @@ import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.model.Hotel;
 | 
			
		||||
import pp.monopoly.model.House;
 | 
			
		||||
import pp.monopoly.model.Item;
 | 
			
		||||
import pp.monopoly.notification.UpdatePlayerView;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The {@code BobTheBuilder} class is responsible for synchronizing the graphical
 | 
			
		||||
 * representation of the figures and buildings on the board with the underlying data model.
 | 
			
		||||
 * It extends the {@link GameBoardSynchronizer} to provide specific synchronization
 | 
			
		||||
 * logic for the board.
 | 
			
		||||
 */
 | 
			
		||||
public class BobTheBuilder extends GameBoardSynchronizer {
 | 
			
		||||
 | 
			
		||||
    /** The String representing the path to the unshaded material*/
 | 
			
		||||
    private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
 | 
			
		||||
    /** The String representing the color parameter in the material*/
 | 
			
		||||
    private static final String COLOR = "Color"; //NON-NLS
 | 
			
		||||
    /** The String representing the figure node*/
 | 
			
		||||
    private static final String FIGURE = "figure"; //NON-NLS
 | 
			
		||||
    /** The String representing the house node*/
 | 
			
		||||
    private static final String HOUSE = "house"; //NON-NLS
 | 
			
		||||
    /** The String representing the hotel node*/
 | 
			
		||||
    private static final String HOTEL = "hotel"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    /** The {@link MonopolyApp} instance*/
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new {@code BobTheBuilder} instance with the specified {@link MonopolyApp} and root node.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the {@link MonopolyApp} instance
 | 
			
		||||
     * @param root the root node of the scene graph
 | 
			
		||||
     */
 | 
			
		||||
    public BobTheBuilder(MonopolyApp app, Node root) {
 | 
			
		||||
        super(app.getGameLogic().getBoard(), root);
 | 
			
		||||
        this.app = app;
 | 
			
		||||
@@ -42,8 +62,10 @@ public class BobTheBuilder extends GameBoardSynchronizer {
 | 
			
		||||
        // Setze die Position basierend auf der Feld-ID
 | 
			
		||||
        node.setLocalTranslation(figure.getPos());
 | 
			
		||||
 | 
			
		||||
        // Setze die Rotation basierend auf der Feld-ID
 | 
			
		||||
        node.setLocalRotation(figure.getRot().toQuaternion());
 | 
			
		||||
        // Setze die Anfangsrotation auf 90 Grad nach links
 | 
			
		||||
        Quaternion initialRotation = new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y);
 | 
			
		||||
        node.setLocalRotation(initialRotation);
 | 
			
		||||
 | 
			
		||||
        node.addControl(new  FigureControl(node, figure, app));
 | 
			
		||||
        return node;
 | 
			
		||||
    }
 | 
			
		||||
@@ -78,16 +100,33 @@ public class BobTheBuilder extends GameBoardSynchronizer {
 | 
			
		||||
        return node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new spatial to represent the specified figure.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param figure the figure to be represented
 | 
			
		||||
     * @return the geometry representing the figure
 | 
			
		||||
     */
 | 
			
		||||
    private Spatial createFigure(Figure figure) {
 | 
			
		||||
        Spatial model;
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            // Lade das Modell
 | 
			
		||||
        Spatial model = app.getAssetManager().loadModel("models/" + "Spielfiguren/" + figure.getType() + "/" + figure.getType() + ".j3o");
 | 
			
		||||
            model = app.getAssetManager().loadModel("models/" + "Spielfiguren/" + figure.getType() + "/" + figure.getType() + ".j3o");
 | 
			
		||||
            
 | 
			
		||||
            // Skaliere und positioniere das Modell
 | 
			
		||||
            model.scale(0.5f);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            model = createBox(figure);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return model;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new spatial to represent the specified hotel.
 | 
			
		||||
     * @param hotel the hotel to be represented
 | 
			
		||||
     * @return  the geometry representing the hotel
 | 
			
		||||
     */
 | 
			
		||||
    private Spatial createHotel(Hotel hotel) {
 | 
			
		||||
        Spatial model = app.getAssetManager().loadModel("models/Hotel/Hotel.j3o");
 | 
			
		||||
        model.scale(0.2f);
 | 
			
		||||
@@ -95,7 +134,11 @@ public class BobTheBuilder extends GameBoardSynchronizer {
 | 
			
		||||
        return model;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new spatial to represent the specified house.
 | 
			
		||||
     * @param house the house to be represented
 | 
			
		||||
     * @return  the geometry representing the house
 | 
			
		||||
     */
 | 
			
		||||
    private Spatial createHouse(House house) {
 | 
			
		||||
        Spatial model = app.getAssetManager().loadModel("models/Haus/"+house.getStage()+"Haus.j3o");
 | 
			
		||||
        model.scale(0.5f);
 | 
			
		||||
 
 | 
			
		||||
@@ -191,9 +191,6 @@ public class BuildingAdminMenu extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the building administration menu and detaches its elements from the GUI.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(mainContainer);
 | 
			
		||||
@@ -201,21 +198,8 @@ public class BuildingAdminMenu extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Periodic updates for the menu, if required.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta Time since the last update in seconds.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        // Periodic updates if necessary
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,64 +3,153 @@ package pp.monopoly.client.gui;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.renderer.Camera;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Controls the movement of the camera within the scene.
 | 
			
		||||
 */
 | 
			
		||||
public class CameraController {
 | 
			
		||||
    private final Camera camera;
 | 
			
		||||
    private final float height = 25;    // Height of the camera above the game board
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.game.server.PlayerHandler;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.UpdatePlayerView;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
     * Constructor for the CameraController.
 | 
			
		||||
     *
 | 
			
		||||
     * @param camera The camera to be controlled
 | 
			
		||||
 * Represents a camera controller for the Monopoly application.
 | 
			
		||||
 */
 | 
			
		||||
    public CameraController(Camera camera) {
 | 
			
		||||
public class CameraController implements GameEventListener{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Enum representing the camera mode for the CameraController.
 | 
			
		||||
     */
 | 
			
		||||
    public enum CameraMode {
 | 
			
		||||
 | 
			
		||||
        /** Mode to focus on the current player */
 | 
			
		||||
        FOCUS_CURRENT_PLAYER,
 | 
			
		||||
        /** Mode to focus on the own player */
 | 
			
		||||
        FOCUS_SELF,
 | 
			
		||||
        /** Mode for free camera movement */
 | 
			
		||||
        FREECAM
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** The camera to control */
 | 
			
		||||
    private final Camera camera;
 | 
			
		||||
    /** The current camera mode */
 | 
			
		||||
    private CameraMode currentMode;
 | 
			
		||||
    /** The player handler instance */
 | 
			
		||||
    private PlayerHandler playerHandler;
 | 
			
		||||
    /** The {@link MonopolyApp} instance*/
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new CameraController instance.
 | 
			
		||||
     * @param camera The camera to control
 | 
			
		||||
     * @param app The MonopolyApp instance
 | 
			
		||||
     */
 | 
			
		||||
    public CameraController(Camera camera, MonopolyApp app) {
 | 
			
		||||
        this.camera = camera;
 | 
			
		||||
        setPosition(0);
 | 
			
		||||
        camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
 | 
			
		||||
        this.playerHandler = app.getGameLogic().getPlayerHandler();
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        app.getGameLogic().addListener(this);
 | 
			
		||||
        setMode(CameraMode.FOCUS_SELF); // Initialize the camera mode
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the camera's position and orientation.
 | 
			
		||||
     * Sets the camera mode to the specified mode.
 | 
			
		||||
     * @param mode The camera mode to set
 | 
			
		||||
     */
 | 
			
		||||
    public void setMode(CameraMode mode) {
 | 
			
		||||
        this.currentMode = mode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the camera behavior based on the current mode and the time-per-frame (tpf).
 | 
			
		||||
     * <p>
 | 
			
		||||
     * This method checks the current mode of the camera and updates its position or behavior accordingly.
 | 
			
		||||
     * Supported modes include:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *   <li>FOCUS_CURRENT_PLAYER: Updates the camera position to focus on the current player.</li>
 | 
			
		||||
     *   <li>FOCUS_SELF: Updates the camera position to focus on the self (the object controlled by the player).</li>
 | 
			
		||||
     *   <li>FREECAM: Leaves the camera position unchanged, allowing free movement.</li>
 | 
			
		||||
     * </ul>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param tpf Time per frame
 | 
			
		||||
     * @param tpf The time-per-frame value, typically provided by the game engine,
 | 
			
		||||
     *            which represents the elapsed time since the last frame.
 | 
			
		||||
     */
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
 | 
			
		||||
 | 
			
		||||
        switch (currentMode) {
 | 
			
		||||
            case FOCUS_CURRENT_PLAYER:
 | 
			
		||||
                updatePosition();
 | 
			
		||||
                break;
 | 
			
		||||
            case FOCUS_SELF:
 | 
			
		||||
                updatePosition();
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case FREECAM:
 | 
			
		||||
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the camera's position based on the field ID.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fieldID The ID of the field to which the camera should move
 | 
			
		||||
     * Updates the camera position depending on the current mode.
 | 
			
		||||
     */
 | 
			
		||||
    public void setPosition(int fieldID) {
 | 
			
		||||
        camera.setLocation(fieldIdToVector(fieldID));
 | 
			
		||||
    public void updatePosition() {
 | 
			
		||||
        Vector3f newPosition = getPos();
 | 
			
		||||
        camera.setLocation(newPosition);
 | 
			
		||||
 | 
			
		||||
        camera.lookAt(app.getGameLogic().getBoard().getFigure(app.getId()).getPos(), Vector3f.UNIT_Y);
 | 
			
		||||
        camera.update();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the camera's position using specific coordinates.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x The X-coordinate of the new camera position
 | 
			
		||||
     * @param y The Y-coordinate of the new camera position
 | 
			
		||||
     * Returns the position for the camera depending on the current mode.
 | 
			
		||||
     * @return The position for the camera
 | 
			
		||||
     */
 | 
			
		||||
    public void setPosition(float x, float y) {
 | 
			
		||||
        camera.setLocation(new Vector3f(x, height, y));
 | 
			
		||||
    private Vector3f getPos() {
 | 
			
		||||
        Vector3f pos = new Vector3f();
 | 
			
		||||
        switch (currentMode) {
 | 
			
		||||
            case FOCUS_CURRENT_PLAYER:
 | 
			
		||||
                pos =  app.getGameLogic().getBoard().getFigure(playerHandler.getPlayerById(0).getId()).getPos();
 | 
			
		||||
        
 | 
			
		||||
            case FOCUS_SELF:
 | 
			
		||||
                pos = app.getGameLogic().getBoard().getFigure(app.getId()).getPos();
 | 
			
		||||
 | 
			
		||||
            case FREECAM:
 | 
			
		||||
                        
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        Vector3f offset = getOffset();
 | 
			
		||||
        pos = new Vector3f(pos.getX() + offset.getX(), pos.getY() + offset.getY(), pos.getZ() + offset.getZ());
 | 
			
		||||
 | 
			
		||||
        return pos;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Maps a field ID to its corresponding position in the game world.
 | 
			
		||||
     *
 | 
			
		||||
     * @param fieldID The ID of the field
 | 
			
		||||
     * @return The position of the field as a {@link Vector3f}
 | 
			
		||||
     * @throws IllegalArgumentException If the field ID is invalid
 | 
			
		||||
     * Calculates the offset for the camera depending on the field the player is on.
 | 
			
		||||
     * @return The offset for the camera
 | 
			
		||||
     */
 | 
			
		||||
    private Vector3f fieldIdToVector(int fieldID) {
 | 
			
		||||
        if (fieldID <= 10) return new Vector3f(30, height, 0);
 | 
			
		||||
        if (fieldID <= 20) return new Vector3f(0, height, 30);
 | 
			
		||||
        if (fieldID <= 30) return new Vector3f(-30, height, 0);
 | 
			
		||||
        if (fieldID <= 40) return new Vector3f(0, height, -30);
 | 
			
		||||
        else throw new IllegalArgumentException();
 | 
			
		||||
    private Vector3f getOffset() {
 | 
			
		||||
        Vector3f offset = new Vector3f();
 | 
			
		||||
 | 
			
		||||
        int fieldId = playerHandler.getPlayerById( (currentMode == CameraMode.FOCUS_SELF ? app.getId() : playerHandler.getPlayerAtIndex(0).getId()) ).getFieldID();
 | 
			
		||||
        // System.out.println();
 | 
			
		||||
        if(fieldId < 10) {
 | 
			
		||||
            offset = new Vector3f(0, 15, -20);
 | 
			
		||||
        } else if(fieldId < 20) {
 | 
			
		||||
            offset = new Vector3f(20 , 15, 0);
 | 
			
		||||
        } else if(fieldId < 30) {
 | 
			
		||||
            offset = new Vector3f(0, 15, 20 );
 | 
			
		||||
        } else {
 | 
			
		||||
            offset = new Vector3f(-20, 15, 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(UpdatePlayerView event) {
 | 
			
		||||
        playerHandler = app.getGameLogic().getPlayerHandler();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,60 +1,44 @@
 | 
			
		||||
//package pp.monopoly.client.gui;
 | 
			
		||||
//
 | 
			
		||||
//import com.jme3.input.InputManager;
 | 
			
		||||
//import com.jme3.input.KeyInput;
 | 
			
		||||
//import com.jme3.input.controls.ActionListener;
 | 
			
		||||
//import com.jme3.input.controls.KeyTrigger;
 | 
			
		||||
//
 | 
			
		||||
///**
 | 
			
		||||
// * Handhabt die Eingaben für die Kamera.
 | 
			
		||||
// */
 | 
			
		||||
//public class CameraInputHandler {
 | 
			
		||||
//
 | 
			
		||||
//    private CameraController cameraController; // Kamera-Controller
 | 
			
		||||
//
 | 
			
		||||
//    /**
 | 
			
		||||
//     * Konstruktor für den CameraInputHandler.
 | 
			
		||||
//     *
 | 
			
		||||
//     * @param cameraController Der Kamera-Controller, der gesteuert werden soll.
 | 
			
		||||
//     * @param inputManager     Der InputManager, um Eingaben zu registrieren.
 | 
			
		||||
//     */
 | 
			
		||||
//    public CameraInputHandler(CameraController cameraController, InputManager inputManager) {
 | 
			
		||||
//        if (cameraController == null || inputManager == null) {
 | 
			
		||||
//            throw new IllegalArgumentException("CameraController und InputManager dürfen nicht null sein");
 | 
			
		||||
//        }
 | 
			
		||||
//        this.cameraController = cameraController;
 | 
			
		||||
//
 | 
			
		||||
//        // Mappings für Kamerasteuerung
 | 
			
		||||
//        inputManager.addMapping("FocusCurrentPlayer", new KeyTrigger(KeyInput.KEY_1)); // Modus 1
 | 
			
		||||
//        inputManager.addMapping("FocusSelf", new KeyTrigger(KeyInput.KEY_2));         // Modus 2
 | 
			
		||||
//        inputManager.addMapping("FreeCam", new KeyTrigger(KeyInput.KEY_3));          // Modus 3
 | 
			
		||||
//
 | 
			
		||||
//        // Listener für die Kameramodi
 | 
			
		||||
//        inputManager.addListener(actionListener, "FocusCurrentPlayer", "FocusSelf", "FreeCam");
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    /**
 | 
			
		||||
//     * ActionListener für die Kamerasteuerung.
 | 
			
		||||
//     */
 | 
			
		||||
//    private final ActionListener actionListener = (name, isPressed, tpf) -> {
 | 
			
		||||
//        if (!isPressed) return;
 | 
			
		||||
//
 | 
			
		||||
//        // Umschalten der Kamera-Modi basierend auf der Eingabe
 | 
			
		||||
//        switch (name) {
 | 
			
		||||
//            case "FocusCurrentPlayer" -> {
 | 
			
		||||
//                cameraController.setMode(CameraController.CameraMode.FOCUS_CURRENT_PLAYER);
 | 
			
		||||
//                System.out.println("Kameramodus: Fokus auf aktuellen Spieler");
 | 
			
		||||
//            }
 | 
			
		||||
//            case "FocusSelf" -> {
 | 
			
		||||
//                cameraController.setMode(CameraController.CameraMode.FOCUS_SELF);
 | 
			
		||||
//                System.out.println("Kameramodus: Fokus auf eigene Figur");
 | 
			
		||||
//            }
 | 
			
		||||
//            case "FreeCam" -> {
 | 
			
		||||
//                cameraController.setMode(CameraController.CameraMode.FREECAM);
 | 
			
		||||
//                System.out.println("Kameramodus: Freie Kamera");
 | 
			
		||||
//            }
 | 
			
		||||
//            default -> System.err.println("Unbekannter Kameramodus: " + name);
 | 
			
		||||
//        }
 | 
			
		||||
//    };
 | 
			
		||||
//}
 | 
			
		||||
//
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.input.InputManager;
 | 
			
		||||
import com.jme3.input.KeyInput;
 | 
			
		||||
import com.jme3.input.controls.ActionListener;
 | 
			
		||||
import com.jme3.input.controls.KeyTrigger;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class to handle the input for the camera.
 | 
			
		||||
 */
 | 
			
		||||
public class CameraInputHandler {
 | 
			
		||||
 | 
			
		||||
    /**The camera controller */
 | 
			
		||||
    private CameraController cameraController;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor for the CameraInputHandler.
 | 
			
		||||
     * @param cameraController The camera controller.
 | 
			
		||||
     * @param inputManager The input manager.
 | 
			
		||||
     */
 | 
			
		||||
    public CameraInputHandler(CameraController cameraController, InputManager inputManager) {
 | 
			
		||||
        this.cameraController = cameraController;
 | 
			
		||||
 | 
			
		||||
        // Tasten für die verschiedenen Kameramodi registrieren
 | 
			
		||||
        inputManager.addMapping("FocusCurrentPlayer", new KeyTrigger(KeyInput.KEY_1));
 | 
			
		||||
        inputManager.addMapping("FocusSelf", new KeyTrigger(KeyInput.KEY_2));
 | 
			
		||||
        inputManager.addMapping("FreeCam", new KeyTrigger(KeyInput.KEY_3));
 | 
			
		||||
 | 
			
		||||
        inputManager.addListener(actionListener, "FocusCurrentPlayer", "FocusSelf", "FreeCam");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * ActionListener for the camera.
 | 
			
		||||
     */
 | 
			
		||||
    private final ActionListener actionListener = (name, isPressed, tpf) -> {
 | 
			
		||||
        if (!isPressed) return;
 | 
			
		||||
 | 
			
		||||
        switch (name) {
 | 
			
		||||
            case "FocusCurrentPlayer" -> cameraController.setMode(CameraController.CameraMode.FOCUS_CURRENT_PLAYER);
 | 
			
		||||
            case "FocusSelf" -> cameraController.setMode(CameraController.CameraMode.FOCUS_SELF);
 | 
			
		||||
            case "FreeCam" -> cameraController.setMode(CameraController.CameraMode.FREECAM);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -22,21 +22,34 @@ import pp.monopoly.message.client.ViewAssetsRequest;
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Dialog for choosing a trade partner.
 | 
			
		||||
 */
 | 
			
		||||
public class ChoosePartner extends Dialog {
 | 
			
		||||
    /** The {@link MonopolyApp} instance*/
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    /** Selector for selecting the player */
 | 
			
		||||
    private Selector<String> playerSelector;
 | 
			
		||||
    /** Button for cancel*/
 | 
			
		||||
    private final Button cancelButton = new Button("Abbrechen");
 | 
			
		||||
    /** Button for confirm*/
 | 
			
		||||
    private final Button confirmButton = new Button("Bestätigen");
 | 
			
		||||
    /** Main container for the UI components */
 | 
			
		||||
    private final Container mainContainer;
 | 
			
		||||
    /** Container for the lower left menu */
 | 
			
		||||
    private Container lowerLeftMenu;
 | 
			
		||||
    /** Container for the lower right menu */
 | 
			
		||||
    private Container lowerRightMenu;
 | 
			
		||||
    /** The background image */
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
    /** The trade handler */
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef; // Reference to track selector changes
 | 
			
		||||
    private String lastSelected = ""; // To keep track of the last selected value
 | 
			
		||||
 | 
			
		||||
    QuadBackgroundComponent translucentWhiteBackground =
 | 
			
		||||
            new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
 | 
			
		||||
    /** Reference to track selector changes */
 | 
			
		||||
    private VersionedReference<Set<Integer>> selectionRef;
 | 
			
		||||
    /** The last selected value */
 | 
			
		||||
    private String lastSelected = "";
 | 
			
		||||
    /** The translucent white background */
 | 
			
		||||
    private QuadBackgroundComponent translucentWhiteBackground = new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the ChoosePartner dialog.
 | 
			
		||||
@@ -169,9 +182,6 @@ public class ChoosePartner extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action for the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -38,18 +38,31 @@ import pp.dialog.DialogBuilder;
 | 
			
		||||
 * Allows users to specify the host and port for connecting to a game server.
 | 
			
		||||
 */
 | 
			
		||||
public class CreateGameMenu extends Dialog {
 | 
			
		||||
    /** The Logger for this class */
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(CreateGameMenu.class.getName());
 | 
			
		||||
    /** A string represing the localhost default */
 | 
			
		||||
    private static final String LOCALHOST = "localhost"; //NON-NLS
 | 
			
		||||
    /** A string representing the default port number */
 | 
			
		||||
    private static final String DEFAULT_PORT = "42069"; //NON-NLS
 | 
			
		||||
    /** The NetworkSupport instance to be used for network operations */
 | 
			
		||||
    private final NetworkSupport network;
 | 
			
		||||
    /** The text field for the host name */
 | 
			
		||||
    private final TextField host = new TextField(LOCALHOST);
 | 
			
		||||
    /** The text field for the port number */
 | 
			
		||||
    private final TextField port = new TextField(DEFAULT_PORT);
 | 
			
		||||
    /** The button for starting the server */
 | 
			
		||||
    private final Button serverButton = new Button("Selber hosten");
 | 
			
		||||
    /** The button for canceling the connection */
 | 
			
		||||
    private final Button cancelButton = new Button("Abbrechen");
 | 
			
		||||
    /** The button for joining a game */
 | 
			
		||||
    private final Button joinButton = new Button("Beitreten");
 | 
			
		||||
    /** The hostname of the server */
 | 
			
		||||
    private String hostname;
 | 
			
		||||
    /** The port number of the server */
 | 
			
		||||
    private int portNumber;
 | 
			
		||||
    /** The future representing the connection to the server */
 | 
			
		||||
    private Future<Object> connectionFuture;
 | 
			
		||||
    /** The dialog for indicating that the connection is in progress */
 | 
			
		||||
    private Dialog progressDialog;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.FastMath;
 | 
			
		||||
import com.jme3.math.Quaternion;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.renderer.RenderManager;
 | 
			
		||||
import com.jme3.renderer.ViewPort;
 | 
			
		||||
@@ -8,7 +9,6 @@ import com.jme3.scene.Node;
 | 
			
		||||
import com.jme3.scene.control.AbstractControl;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.game.client.ClientGameLogic;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.UpdatePlayerView;
 | 
			
		||||
@@ -18,21 +18,40 @@ import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.Queue;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Control class for the figure objects.
 | 
			
		||||
 * 
 | 
			
		||||
 * Handles the movement of the figure along a path.
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class FigureControl extends AbstractControl implements GameEventListener {
 | 
			
		||||
 | 
			
		||||
    /** The Logger for this class */
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(FigureControl.class.getName());
 | 
			
		||||
    /** The Figure object to control */
 | 
			
		||||
    private final Figure figure;
 | 
			
		||||
    /** The spatial object of the figure*/
 | 
			
		||||
    private final Node spatial;
 | 
			
		||||
    /** The MonopolyApp instance */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private Queue<Vector3f> path; // Path to follow
 | 
			
		||||
    /** The path to follow */
 | 
			
		||||
    private Queue<Vector3f> path;
 | 
			
		||||
    /** The current target position */
 | 
			
		||||
    private Vector3f currentTarget;
 | 
			
		||||
    private float animationTime = 0f; // Time elapsed for the current movement
 | 
			
		||||
    private final float durationPerField = 0.5f; // Time to move between fields
 | 
			
		||||
    private float delayTime = 3f; // Verzögerung in Sekunden
 | 
			
		||||
    private float delayElapsed = 0f; // Zeit, die seit dem Start der Verzögerung vergangen ist
 | 
			
		||||
 | 
			
		||||
    /** The time elapsed for the current movement */
 | 
			
		||||
    private float animationTime = 0f;
 | 
			
		||||
    /** The duration per field */
 | 
			
		||||
    private final float durationPerField = 0.5f;
 | 
			
		||||
    /** The delay time */
 | 
			
		||||
    private float delayTime = 3f;
 | 
			
		||||
    /** The delay elapsed time */
 | 
			
		||||
    private float delayElapsed = 0f;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor for the FigureControl class
 | 
			
		||||
     * @param spatial The spatial object of the figure
 | 
			
		||||
     * @param figure The figure object
 | 
			
		||||
     * @param app The MonopolyApp object
 | 
			
		||||
     */
 | 
			
		||||
    public FigureControl(Node spatial, Figure figure, MonopolyApp app) {
 | 
			
		||||
        super();
 | 
			
		||||
        this.figure = figure;
 | 
			
		||||
@@ -42,6 +61,14 @@ public class FigureControl extends AbstractControl implements GameEventListener
 | 
			
		||||
        app.getGameLogic().addListener(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the figure's movement along a path.
 | 
			
		||||
     * 
 | 
			
		||||
     * Handles movement delays, rotates at specific fields (0, 10, 20, 30), 
 | 
			
		||||
     * and moves the figure with a hop effect toward the next target.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param tpf Time-per-frame since the last update.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void controlUpdate(float tpf) {
 | 
			
		||||
        if (delayTime > 0) {
 | 
			
		||||
@@ -50,14 +77,29 @@ public class FigureControl extends AbstractControl implements GameEventListener
 | 
			
		||||
                return; // Warte, bis die Verzögerung abgeschlossen ist
 | 
			
		||||
            }
 | 
			
		||||
            delayTime = 0; // Verzögerung abgeschlossen
 | 
			
		||||
            LOGGER.log(Level.DEBUG, "Delay completed. Starting animation...");
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (currentTarget == null && !path.isEmpty()) {
 | 
			
		||||
            // Hole das nächste Ziel aus dem Pfad
 | 
			
		||||
            currentTarget = path.poll();
 | 
			
		||||
            animationTime = 0f;
 | 
			
		||||
            LOGGER.log(Level.DEBUG, "Next target: {0}", currentTarget);
 | 
			
		||||
 | 
			
		||||
            // Prüfe, ob eine Drehung erforderlich ist (Felder 0, 10, 20, 30)
 | 
			
		||||
            int currentField = figure.getCurrentFieldID();
 | 
			
		||||
            
 | 
			
		||||
            if ((nextField(currentField) == 10) ||
 | 
			
		||||
                (nextField(currentField) ==  20) ||
 | 
			
		||||
                (nextField(currentField) ==  30) ||
 | 
			
		||||
                (nextField(currentField) ==  0)) {
 | 
			
		||||
                
 | 
			
		||||
                Quaternion rotation = spatial.getLocalRotation();
 | 
			
		||||
                Quaternion turnRight = new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y);
 | 
			
		||||
                spatial.setLocalRotation(rotation.mult(turnRight));
 | 
			
		||||
                
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (currentTarget != null) {
 | 
			
		||||
@@ -71,7 +113,7 @@ public class FigureControl extends AbstractControl implements GameEventListener
 | 
			
		||||
 | 
			
		||||
            // Hüpfeffekt hinzufügen
 | 
			
		||||
            float hopHeight = 0.5f * FastMath.sin(FastMath.PI * (animationTime / durationPerField));
 | 
			
		||||
            interpolatedPosition.setY(hopHeight + 1);
 | 
			
		||||
            interpolatedPosition.setY(hopHeight );
 | 
			
		||||
            spatial.setLocalTranslation(interpolatedPosition);
 | 
			
		||||
 | 
			
		||||
            // Ziel erreicht
 | 
			
		||||
@@ -79,18 +121,17 @@ public class FigureControl extends AbstractControl implements GameEventListener
 | 
			
		||||
                spatial.setLocalTranslation(currentTarget);
 | 
			
		||||
                figure.moveTo(currentTarget); // Synchronisiere die interne Position
 | 
			
		||||
                currentTarget = null; // Setze Ziel zurück
 | 
			
		||||
 | 
			
		||||
                LOGGER.log(Level.DEBUG, "Target reached. Remaining path: {0}", path.size());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Beispiel: Berechnung des nächsten Feldes
 | 
			
		||||
    private int nextField() {
 | 
			
		||||
        int currentField = figure.getCurrentFieldID();
 | 
			
		||||
        return (currentField + 1) % 40; // Weiter zum nächsten Feld
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculate the next field on the board
 | 
			
		||||
     * @param currentField The current field id
 | 
			
		||||
     * @return  The next field id
 | 
			
		||||
     */
 | 
			
		||||
    private int nextField(int currentField) {
 | 
			
		||||
        return (currentField + 1) % 40;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
@@ -100,6 +141,11 @@ public class FigureControl extends AbstractControl implements GameEventListener
 | 
			
		||||
        // No rendering logic required
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the path for the figure to follow
 | 
			
		||||
     * @param startField The field the figure is currently on
 | 
			
		||||
     * @param endField The field the figure should move to
 | 
			
		||||
     */
 | 
			
		||||
    public void setPath(int startField, int endField) {
 | 
			
		||||
        LOGGER.log(Level.TRACE, "setPath called with startField: {0} to endField {1}", startField, endField);
 | 
			
		||||
        path.clear();
 | 
			
		||||
@@ -137,9 +183,4 @@ public class FigureControl extends AbstractControl implements GameEventListener
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,26 +4,23 @@ import com.jme3.scene.Node;
 | 
			
		||||
import com.jme3.scene.Spatial;
 | 
			
		||||
import pp.monopoly.model.Item;
 | 
			
		||||
import pp.monopoly.model.Visitor;
 | 
			
		||||
import pp.monopoly.notification.DiceRollEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.ItemAddedEvent;
 | 
			
		||||
import pp.monopoly.notification.ItemRemovedEvent;
 | 
			
		||||
import pp.monopoly.notification.UpdatePlayerView;
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.view.ModelViewSynchronizer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Abstract base class for synchronizing the visual representation of a {@link Board} with its model state.
 | 
			
		||||
 * This class handles the addition and removal of items from the board, ensuring that changes in the model
 | 
			
		||||
 * are accurately reflected in the view.
 | 
			
		||||
 * <p>
 | 
			
		||||
 *
 | 
			
		||||
 * Subclasses are responsible for providing the specific implementation of how each item in the map
 | 
			
		||||
 * is represented visually by implementing the {@link Visitor} interface.
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
abstract class GameBoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
 | 
			
		||||
    // The board that this synchronizer is responsible for
 | 
			
		||||
    /** The board that this synchronizer is responsible for*/
 | 
			
		||||
    protected final Board board;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,24 @@ import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.game.server.PlayerColor;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A custom button class that uses images for its appearance. The button's appearance changes based on its state (enabled,
 | 
			
		||||
 */
 | 
			
		||||
public class ImageButton extends Button {
 | 
			
		||||
 | 
			
		||||
    /** The MonopolyApp instance */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    /** The button's functionality (e.g., "end_turn", "roll_dice") */
 | 
			
		||||
    private final String functionality;
 | 
			
		||||
    /** The player's color */
 | 
			
		||||
    private final PlayerColor playerColor;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new ImageButton with the given functionality and MonopolyApp instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param functionality the button's functionality (e.g., "end_turn", "roll_dice")
 | 
			
		||||
     * @param app the MonopolyApp instance
 | 
			
		||||
     */
 | 
			
		||||
    public ImageButton(String functionality, MonopolyApp app) {
 | 
			
		||||
        super("", "button-clear");
 | 
			
		||||
        this.app = app;
 | 
			
		||||
@@ -82,10 +94,12 @@ public class ImageButton extends Button {
 | 
			
		||||
        ENABLED, DISABLED, HOVER
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void addClickCommands( Command<? super Button> command ) {
 | 
			
		||||
        super.addCommands(ButtonAction.Down, command);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @SuppressWarnings("unchecked") // because Java doesn't like var-arg generics
 | 
			
		||||
    public void addClickCommands( Command<? super Button>... commands ) {
 | 
			
		||||
        super.addCommands(ButtonAction.Down, commands);
 | 
			
		||||
 
 | 
			
		||||
@@ -32,10 +32,10 @@ import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the lobby menu in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 *
 | 
			
		||||
 * Provides functionality for player configuration, including input for starting capital,
 | 
			
		||||
 * player name, and figure selection, as well as options to ready up or exit the game.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class LobbyMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
@@ -154,6 +154,7 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        figures.add("Katze");
 | 
			
		||||
        figures.add("OOP");
 | 
			
		||||
        figures.add("Handyholster");
 | 
			
		||||
        figures.add("Panzer");
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        figureDropdown = new Selector<>(figures, "glass");
 | 
			
		||||
@@ -269,9 +270,6 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        app.getGameLogic().send(new PlayerReady(true, playerInputField.getText(), figure, Integer.parseInt(startingCapital.getText())));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
@@ -290,11 +288,6 @@ public class LobbyMenu extends Dialog {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the current menu and transitions music playback.
 | 
			
		||||
     * Stops the secondary music (if playing) and resumes the main background music
 | 
			
		||||
     * if music is enabled in the preferences. Ensures smooth transitions in audio.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        GameMusic music = app.getStateManager().getState(GameMusic.class);
 | 
			
		||||
 
 | 
			
		||||
@@ -28,10 +28,15 @@ import java.util.stream.Collectors;
 | 
			
		||||
 * PropertyOverviewMenu is a dialog for displaying the player's properties in the game.
 | 
			
		||||
 */
 | 
			
		||||
public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
    /** The MonopolyApp instance */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    /** The main container for the menu layout */
 | 
			
		||||
    private final Container mainContainer;
 | 
			
		||||
    /** The container for displaying the "Gebäude" cards */
 | 
			
		||||
    private final Container displayContainer;
 | 
			
		||||
    /** The horizontal slider for scrolling through cards */
 | 
			
		||||
    private final Slider horizontalSlider;
 | 
			
		||||
    /** The list of cards to display */
 | 
			
		||||
    private final List<Container> cards;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -124,6 +129,9 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card for BuildingProperty with detailed rent and cost information.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param field The BuildingProperty to create a card for.
 | 
			
		||||
     * @return The created card container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createBuildingCard(BuildingProperty field) {
 | 
			
		||||
        Container card = new Container();
 | 
			
		||||
@@ -156,6 +164,9 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card for FoodField with dynamic pricing and rent details.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param field The FoodField to create a card for.
 | 
			
		||||
     * @return The created card container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createFoodFieldCard(FoodField field) {
 | 
			
		||||
        Container card = new Container();
 | 
			
		||||
@@ -188,6 +199,9 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a card for GateField with rent details for owning multiple gates.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param field The GateField to create a card for.
 | 
			
		||||
     * @return The created card container.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createGateFieldCard(GateField field) {
 | 
			
		||||
        Container card = new Container();
 | 
			
		||||
@@ -206,11 +220,11 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete: 250 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("2 Bahnhof besitzt: 500 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("2 Tore besitzt: 500 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("3 Bahnhof besitzt: 1000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("3 Tore besitzt: 1000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("4 Bahnhof besitzt: 2000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("4 Tore besitzt: 2000 EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text"))).setFontSize(14);
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Dark grey background
 | 
			
		||||
@@ -260,9 +274,6 @@ public class PropertyOverviewMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the dialog and detaches it from the GUI node.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(mainContainer);
 | 
			
		||||
 
 | 
			
		||||
@@ -136,9 +136,6 @@ public class SettingsMenu extends Dialog {
 | 
			
		||||
        update();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * As an escape action, this method closes the menu if it is the top dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,15 @@ package pp.monopoly.client.gui;
 | 
			
		||||
import com.simsilica.lemur.Slider;
 | 
			
		||||
import pp.monopoly.client.GameSound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A slider for the sound effects volume.
 | 
			
		||||
 */
 | 
			
		||||
public class SoundSlider extends Slider {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Manages sound effects for the game.
 | 
			
		||||
     */
 | 
			
		||||
    private final pp.monopoly.client.GameSound sound;
 | 
			
		||||
    private final GameSound sound;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Volume level for the game sounds.
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,9 @@ import pp.monopoly.notification.Sound;
 | 
			
		||||
 * Constructs the startup menu dialog for the Monopoly application.
 | 
			
		||||
 */
 | 
			
		||||
public class StartMenu extends Dialog {
 | 
			
		||||
    /**
 | 
			
		||||
     * The Monopoly application instance.
 | 
			
		||||
     */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -65,7 +68,7 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(centerMenu);
 | 
			
		||||
 | 
			
		||||
        // Load the Monopoly logo as a texture
 | 
			
		||||
        Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopoly.png");
 | 
			
		||||
        Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopolyw.png");
 | 
			
		||||
 | 
			
		||||
        // Create a container for the logo
 | 
			
		||||
        Container logoContainer = new Container();
 | 
			
		||||
@@ -91,8 +94,8 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        QuadBackgroundComponent unibwBackground = new QuadBackgroundComponent(unibwTexture);
 | 
			
		||||
        unibwContainer.setBackground(unibwBackground);
 | 
			
		||||
 | 
			
		||||
        float unibwWidth = 512;
 | 
			
		||||
        float unibwHeight = 128;
 | 
			
		||||
        float unibwWidth = 662;
 | 
			
		||||
        float unibwHeight = 180;
 | 
			
		||||
        unibwContainer.setPreferredSize(new Vector3f(unibwWidth, unibwHeight, 0));
 | 
			
		||||
 | 
			
		||||
        unibwContainer.setLocalTranslation(new Vector3f(
 | 
			
		||||
@@ -105,17 +108,11 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(unibwContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the startup menu and detaches all GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachAllChildren();
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,9 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
        container.setBackground(background);
 | 
			
		||||
 | 
			
		||||
        setupBorders(container);
 | 
			
		||||
        setupSpacer(container);
 | 
			
		||||
        setupPlayerInfoSection(container);
 | 
			
		||||
        setupSpacer(container);
 | 
			
		||||
        setupDiceSection(container);
 | 
			
		||||
        setupActionMenu(container);
 | 
			
		||||
 | 
			
		||||
@@ -135,6 +137,17 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
        app.getGuiNode().attachChild(border);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a spacer to the specified container.
 | 
			
		||||
     *
 | 
			
		||||
     * @param container the container to which the spacer is added
 | 
			
		||||
     */
 | 
			
		||||
    private void setupSpacer(Container container) {
 | 
			
		||||
        Container spacer = container.addChild(new Container());
 | 
			
		||||
        spacer.setPreferredSize(new Vector3f(20, 10, 0));
 | 
			
		||||
        spacer.setBackground(null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up the player information section of the toolbar interface.
 | 
			
		||||
     *
 | 
			
		||||
@@ -183,16 +196,6 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
        menuContainer.setBackground(null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the color of the current player.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The color of the current player.
 | 
			
		||||
     */
 | 
			
		||||
    private ColorRGBA getCurrentPlayerColor() {
 | 
			
		||||
        Player currentPlayer = playerHandler.getPlayerById(app.getId());
 | 
			
		||||
        return Player.getColor(currentPlayer.getId()).getColor();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the dice display section of the toolbar interface.
 | 
			
		||||
     *
 | 
			
		||||
@@ -280,7 +283,11 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the trade button.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The trade button.
 | 
			
		||||
     */
 | 
			
		||||
    private Button createTradeButton() {
 | 
			
		||||
        String iconPath = "icons/icon-handeln.png";
 | 
			
		||||
        // createActionButton(playerColor, "icons/icon-handeln.png", 100, () -> new ChoosePartner(app).open());
 | 
			
		||||
@@ -295,12 +302,17 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
 | 
			
		||||
        tradeButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            new ChoosePartner(app).open();
 | 
			
		||||
            
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return tradeButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the property menu button.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The property menu button.
 | 
			
		||||
     */
 | 
			
		||||
    private Button createPropertyMenuButton() {
 | 
			
		||||
 | 
			
		||||
        String iconPath = "icons/icon-gebaude.png";
 | 
			
		||||
@@ -320,6 +332,11 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
        return propertyMenuButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the end turn button.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The end turn button.
 | 
			
		||||
     */
 | 
			
		||||
    private Button createEndTurnButton() {
 | 
			
		||||
        // return createActionButton(playerColor, "icons/icon-zugbeenden.png", 75, () -> handleEndTurn());
 | 
			
		||||
 | 
			
		||||
@@ -334,25 +351,12 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
        endTurnButton.setIcon(icon);
 | 
			
		||||
 | 
			
		||||
        endTurnButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().send(new EndTurn());
 | 
			
		||||
            receivedEvent(new ButtonStatusEvent(false));
 | 
			
		||||
            handleEndTurn();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return endTurnButton;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a background with the specified color.
 | 
			
		||||
     *
 | 
			
		||||
     * @param color The color of the background.
 | 
			
		||||
     * @return The background component.
 | 
			
		||||
     */
 | 
			
		||||
    private QuadBackgroundComponent createButtonBackground(ColorRGBA color) {
 | 
			
		||||
        QuadBackgroundComponent background = new QuadBackgroundComponent(color);
 | 
			
		||||
        Texture gradient = app.getAssetManager().loadTexture("Textures/gradient.png");
 | 
			
		||||
        if (gradient != null) background.setTexture(gradient);
 | 
			
		||||
        return background;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the end turn event.
 | 
			
		||||
@@ -534,18 +538,11 @@ public class Toolbar extends Dialog implements GameEventListener {
 | 
			
		||||
        endTurnButton.setEnabled(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the toolbar, detaching it from the GUI.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(toolbarContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -30,10 +30,10 @@ import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the trade menu dialog in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 *
 | 
			
		||||
 * Facilitates trade interactions between players, including selection of properties,
 | 
			
		||||
 * currency, and special cards for offers and requests.
 | 
			
		||||
 * </p>
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
public class TradeMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
@@ -48,17 +48,26 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    /** Background geometry for the menu. */
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
    /** The building and card selector for the left column. */
 | 
			
		||||
    private Selector<String> leftBuildingSelector, leftSpecialCardSelector;
 | 
			
		||||
    /** The building and card selector for the right column. */
 | 
			
		||||
    private Selector<String> rightBuildingSelector, rightSpecialCardSelector;
 | 
			
		||||
    /** The labels for displaying selected properties. */
 | 
			
		||||
    private Label leftSelectionsLabel, rightSelectionsLabel;
 | 
			
		||||
    /** The text fields for currency input. */
 | 
			
		||||
    private TextField leftCurrencyInput, rightCurrencyInput;
 | 
			
		||||
 | 
			
		||||
    /** References for tracking UI changes. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> leftBuildingRef, rightBuildingRef;
 | 
			
		||||
    /** References for tracking UI changes. */
 | 
			
		||||
    private VersionedReference<Set<Integer>> leftCardRef, rightCardRef;
 | 
			
		||||
 | 
			
		||||
    /** The selected buildings for the trade. */
 | 
			
		||||
    private Set<String> rightselBuildings = new HashSet<>();
 | 
			
		||||
    /** The selected buildings for the trade. */
 | 
			
		||||
    private Set<String> leftselBuildings = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    /** The color for the trade menu background. */
 | 
			
		||||
    private static final ColorRGBA TRANSLUCENT_WHITE = new ColorRGBA(1, 1, 1, 0.5f);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -80,7 +89,11 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
        initializeReferences();
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the main container for the trade menu UI. */
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main container for the trade menu.
 | 
			
		||||
     * @return the created main container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createMainContainer() {
 | 
			
		||||
        Container container = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(1200, 800, 0));
 | 
			
		||||
@@ -90,7 +103,11 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        container.addChild(createMainContent());
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the header label for the trade menu. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the header label for the trade menu.
 | 
			
		||||
     * @return the created header label
 | 
			
		||||
     */
 | 
			
		||||
    private Label createHeader() {
 | 
			
		||||
        Label header = new Label("Handelsmenü", new ElementId("label-Bold"));
 | 
			
		||||
        header.setFontSize(50);
 | 
			
		||||
@@ -98,7 +115,11 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        header.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE));
 | 
			
		||||
        return header;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the main content section of the trade menu. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main content for the trade menu.
 | 
			
		||||
     * @return the created main content container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createMainContent() {
 | 
			
		||||
        Container mainContent = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
        mainContent.setPreferredSize(new Vector3f(1200, 700, 0));
 | 
			
		||||
@@ -110,7 +131,9 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        return mainContent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Sets the trade data based on the current selections. */
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the trade values based on the user input.
 | 
			
		||||
     */
 | 
			
		||||
    private void setTrades() {
 | 
			
		||||
        String leftCurreny = leftCurrencyInput.getText().equals("")? "0" : leftCurrencyInput.getText();
 | 
			
		||||
        String rightCurreny = rightCurrencyInput.getText().equals("")? "0" : rightCurrencyInput.getText();
 | 
			
		||||
@@ -232,13 +255,21 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        combinedProperties = combinedProperties.stream().sorted(Comparator.comparingInt(PropertyField::getId)).collect(Collectors.toList());
 | 
			
		||||
        return combinedProperties;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates a text field for currency input. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a currency input field for the trade menu.
 | 
			
		||||
     * @return the created currency input field
 | 
			
		||||
     */
 | 
			
		||||
    private TextField createCurrencyInput() {
 | 
			
		||||
        TextField currencyInput = new TextField("0");
 | 
			
		||||
        styleTextField(currencyInput);
 | 
			
		||||
        return currencyInput;
 | 
			
		||||
    }
 | 
			
		||||
    /** Creates the middle section containing buttons and summary fields. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the middle section of the trade menu.
 | 
			
		||||
     * @return the created middle section container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createMiddleSection() {
 | 
			
		||||
        Container middleSection = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        middleSection.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)));
 | 
			
		||||
@@ -281,13 +312,19 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        return middleSection;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Styles the given selector with insets and background color. */
 | 
			
		||||
    /**
 | 
			
		||||
     * Styles the given selector with insets and background color.
 | 
			
		||||
     * @param selector  the selector to style
 | 
			
		||||
     */
 | 
			
		||||
    private void styleSelector(Selector<String> selector) {
 | 
			
		||||
        selector.setInsets(new Insets3f(5, 10, 5, 10));
 | 
			
		||||
        selector.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Styles the given text field with insets and background color. */
 | 
			
		||||
    /**
 | 
			
		||||
     * Styles the given text field with insets and background color.
 | 
			
		||||
     * @param textField the text field to style
 | 
			
		||||
     */
 | 
			
		||||
    private void styleTextField(TextField textField) {
 | 
			
		||||
        textField.setInsets(new Insets3f(5, 10, 5, 10));
 | 
			
		||||
        textField.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
 | 
			
		||||
@@ -314,7 +351,10 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
            rightCurrencyInput = currencyInput;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    /** Positions the main container at the center of the screen. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Positions the main container in the center of the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void positionMainContainer() {
 | 
			
		||||
        mainContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2,
 | 
			
		||||
@@ -322,7 +362,10 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    /** Adds a background image to the trade menu. */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a background image to the trade menu.
 | 
			
		||||
     */
 | 
			
		||||
    private void addBackgroundImage() {
 | 
			
		||||
        Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
@@ -333,6 +376,7 @@ public class TradeMenu extends Dialog {
 | 
			
		||||
        background.setLocalTranslation(0, 0, 6);
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /** Initializes references for tracking UI changes. */
 | 
			
		||||
    private void initializeReferences() {
 | 
			
		||||
        leftBuildingRef = leftBuildingSelector.getSelectionModel().createReference();
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,9 @@ import pp.monopoly.client.GameMusic;
 | 
			
		||||
 */
 | 
			
		||||
public class VolumeSlider extends Slider {
 | 
			
		||||
 | 
			
		||||
    private final pp.monopoly.client.GameMusic music;
 | 
			
		||||
    /** The GameMusic instance to handel */
 | 
			
		||||
    private final GameMusic music;
 | 
			
		||||
    /** The volume of the music */
 | 
			
		||||
    private double vol;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -12,33 +12,31 @@ import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a confirmation dialog that appears when a trade is accepted.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Displays a message to the user informing them that the trade they proposed has been accepted,
 | 
			
		||||
 * along with a confirmation button to close the dialog.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * Displays a message to the user informing them that the trade was accepted.
 | 
			
		||||
 */
 | 
			
		||||
public class AcceptTrade extends Dialog {
 | 
			
		||||
public class AcceptTrade extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the dialog. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Container for the warning message content. */
 | 
			
		||||
    private final Container noMoneyWarningContainer;
 | 
			
		||||
    private Container noMoneyWarningContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the accept trade dialog.
 | 
			
		||||
     * Constructs the AcceptTrade dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     * @param msg the trade reply message containing details about the trade
 | 
			
		||||
@@ -47,80 +45,99 @@ public class AcceptTrade extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Initialize GUI elements
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createWarningContainer(msg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    private void createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        overlayBackground = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlayBackground.setMaterial(material);
 | 
			
		||||
        overlayBackground.setLocalTranslation(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container for the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBackgroundContainer() {
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main warning container for the dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the trade reply message
 | 
			
		||||
     */
 | 
			
		||||
    private void createWarningContainer(TradeReply msg) {
 | 
			
		||||
        noMoneyWarningContainer = new Container();
 | 
			
		||||
        noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        noMoneyWarningContainer.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        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);
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = noMoneyWarningContainer.addChild(new Label("Handel angenommen!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        // Message
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast Spieler"+ " " + msg.getTradeHandler().getReceiver().getName() + " " + "einen Handel vorgeschlagen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Du hast " + msg.getTradeHandler().getReceiver().getName() + " einen Handel vorgeschlagen.", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Der Handel wurde angenommen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Der Handel wurde angenommen.", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // 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(() -> {
 | 
			
		||||
        // Confirmation button
 | 
			
		||||
        Button confirmButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Centers the warning and background containers on the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void centerContainers() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        // Center main container
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        // Center background container with padding
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     * Displays the dialog by attaching it to the GUI through the DialogManager.
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
        centerContainers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -128,9 +145,9 @@ public class AcceptTrade extends Dialog {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -139,6 +156,6 @@ public class AcceptTrade extends Dialog {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -12,24 +12,24 @@ import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn
 | 
			
		||||
 * Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn.
 | 
			
		||||
 */
 | 
			
		||||
public class Bankrupt extends Dialog {
 | 
			
		||||
public class Bankrupt extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the bankruptcy warning content. */
 | 
			
		||||
    private final Container bankruptContainer;
 | 
			
		||||
    private Container bankruptContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the bankruptcy warning popup.
 | 
			
		||||
@@ -40,92 +40,99 @@ public class Bankrupt extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Initialize the components
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createBankruptContainer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     */
 | 
			
		||||
    private void createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        overlayBackground = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlayBackground.setMaterial(material);
 | 
			
		||||
        overlayBackground.setLocalTranslation(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container for the popup.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBackgroundContainer() {
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main container for the bankruptcy warning content.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBankruptContainer() {
 | 
			
		||||
        bankruptContainer = new Container();
 | 
			
		||||
        bankruptContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        bankruptContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
        bankruptContainer.setPreferredSize(new Vector3f(550, 350, 10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = bankruptContainer.addChild(new Label("Vorsicht!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = bankruptContainer.addChild(new Label("Vorsicht !", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        // Text content
 | 
			
		||||
        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!\n"+
 | 
			
		||||
        "Dieses PopUp wird nicht erneut angezeigt!", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label(
 | 
			
		||||
                "Du hast einen negativen Kontostand. Wenn du jetzt deinen Zug beendest, gehst du bankrott und verlierst das Spiel!\n"
 | 
			
		||||
                + "Dieses Pop-Up wird nicht erneut angezeigt!", 
 | 
			
		||||
                new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // 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));
 | 
			
		||||
        // Confirmation button
 | 
			
		||||
        Button confirmButton = bankruptContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(this::close));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Centers the popup containers on the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void centerContainers() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        // Center bankrupt container
 | 
			
		||||
        bankruptContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        // Center background container with padding
 | 
			
		||||
        backgroundContainer.setPreferredSize(bankruptContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - bankruptContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + bankruptContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(bankruptContainer);
 | 
			
		||||
        centerContainers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(bankruptContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape key action by closing the popup.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
@@ -8,6 +9,7 @@ import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
@@ -16,16 +18,15 @@ import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * BuildingPropertyCard creates the popup for field information
 | 
			
		||||
 * BuildingPropertyCard creates a popup for displaying field information.
 | 
			
		||||
 */
 | 
			
		||||
public class BuildingPropertyCard extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
public class BuildingPropertyCard extends Dialog implements PopupDialog {
 | 
			
		||||
 | 
			
		||||
    /**The Monopoly application instance*/
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the building property information. */
 | 
			
		||||
    /**The main container for the popup*/
 | 
			
		||||
    private final Container buildingPropertyContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the property card. */
 | 
			
		||||
    /**The background container for the popup*/
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -37,89 +38,120 @@ public class BuildingPropertyCard extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponding field
 | 
			
		||||
        int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
 | 
			
		||||
        BuildingProperty field = (BuildingProperty) new BoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
        // Create the main container for the popup
 | 
			
		||||
        buildingPropertyContainer = new Container();
 | 
			
		||||
        buildingPropertyContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
 | 
			
		||||
        addContentToContainer(buildingPropertyContainer, field);
 | 
			
		||||
        buildingPropertyContainer.setPreferredSize(new Vector3f(360,460,1));
 | 
			
		||||
        System.out.println(buildingPropertyContainer.getPreferredSize());
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des buildingPropertyContainer an
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray
 | 
			
		||||
 | 
			
		||||
        // Add padding to the background
 | 
			
		||||
        float padding = 10f;
 | 
			
		||||
        backgroundContainer.setPreferredSize(buildingPropertyContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        //Titel
 | 
			
		||||
        Label settingsTitle = buildingPropertyContainer.addChild(new Label( field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        settingsTitle.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
 | 
			
		||||
        settingsTitle.setFontSize(48);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Preise werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        Container propertyValuesContainer = buildingPropertyContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 1 Haus: " + field.getAllRent().get(1) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 2 Häuser: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 3 Häuser: " + field.getAllRent().get(3) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 4 Häuser: " + field.getAllRent().get(4) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 1 Hotel: " + field.getAllRent().get(5) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        System.out.println(backgroundContainer.getPreferredSize());
 | 
			
		||||
 | 
			
		||||
        // Position the containers
 | 
			
		||||
        centerContainers(padding);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds the property details and buttons to the container.
 | 
			
		||||
     *
 | 
			
		||||
     * @param container the main container for the property card
 | 
			
		||||
     * @param field     the building property to display
 | 
			
		||||
     */
 | 
			
		||||
    private void addContentToContainer(Container container, BuildingProperty field) {
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = container.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        title.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
 | 
			
		||||
        title.setFontSize(38);
 | 
			
		||||
 | 
			
		||||
        // Property details
 | 
			
		||||
        Container propertyValuesContainer = container.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete allein: " + field.getAllRent().get(0) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 1 Haus: " + field.getAllRent().get(1) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 2 Häusern: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 3 Häusern: " + field.getAllRent().get(3) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 4 Häusern: " + field.getAllRent().get(4) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- mit 1 Hotel: " + field.getAllRent().get(5) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("1 Haus kostet: " + field.getHousePrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = buildingPropertyContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        // Add buttons
 | 
			
		||||
        addButtons(container);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds the buttons for closing or buying the property.
 | 
			
		||||
     *
 | 
			
		||||
     * @param container the main container
 | 
			
		||||
     */
 | 
			
		||||
    private void addButtons(Container container) {
 | 
			
		||||
        // Quit button
 | 
			
		||||
        Button quitButton = container.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
        Button buyButton = buildingPropertyContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
 | 
			
		||||
        // Buy button
 | 
			
		||||
        Button buyButton = container.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
            app.getGameLogic().send(new BuyPropertyResponse());
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
    /**
 | 
			
		||||
     * Centers the containers on the screen.
 | 
			
		||||
     *
 | 
			
		||||
     * @param padding the padding size
 | 
			
		||||
     */
 | 
			
		||||
    private void centerContainers(float padding) {
 | 
			
		||||
        // Center main container
 | 
			
		||||
        buildingPropertyContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            10
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        // Center background container with padding
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                9
 | 
			
		||||
            7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(buildingPropertyContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes the associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(buildingPropertyContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(buildingPropertyContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
@@ -228,9 +227,6 @@ public class BuyHouse extends Dialog {
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(buyHouseContainer);
 | 
			
		||||
@@ -238,9 +234,6 @@ public class BuyHouse extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.client.gui.TradeMenu;
 | 
			
		||||
@@ -18,18 +19,18 @@ import pp.monopoly.notification.Sound;
 | 
			
		||||
/**
 | 
			
		||||
 * ConfirmTrade is a popup which appears when a trade is proposed to this certain player.
 | 
			
		||||
 */
 | 
			
		||||
public class ConfirmTrade extends Dialog {
 | 
			
		||||
public class ConfirmTrade extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the "Confirm Trade" popup UI. */
 | 
			
		||||
    private final Container confirmTradeContainer;
 | 
			
		||||
    private Container confirmTradeContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /** The trade handler managing the details of the trade proposal. */
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
    private final TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the "Confirm Trade" popup.
 | 
			
		||||
@@ -39,53 +40,61 @@ public class ConfirmTrade extends Dialog {
 | 
			
		||||
    public ConfirmTrade(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        tradeHandler = app.getGameLogic().getTradeHandler();
 | 
			
		||||
        this.tradeHandler = app.getGameLogic().getTradeHandler();
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        // Initialize components
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createConfirmTradeContainer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the background container.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBackgroundContainer() {
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the main confirm trade container and its UI components.
 | 
			
		||||
     */
 | 
			
		||||
    private void createConfirmTradeContainer() {
 | 
			
		||||
        confirmTradeContainer = new Container();
 | 
			
		||||
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        backgroundContainer.setPreferredSize(confirmTradeContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        
 | 
			
		||||
        // Titel
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = confirmTradeContainer.addChild(new Label("Handel", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Build trade information strings
 | 
			
		||||
        StringBuilder offeredProperties = new StringBuilder();
 | 
			
		||||
        for (PropertyField field : tradeHandler.getOfferedProperties()) {
 | 
			
		||||
            offeredProperties.append(field.getName());
 | 
			
		||||
            offeredProperties.append(", ");
 | 
			
		||||
            offeredProperties.append(field.getName()).append(", ");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        StringBuilder requestedProperties = new StringBuilder();
 | 
			
		||||
        for (PropertyField field : tradeHandler.getRequestedProperties()) {
 | 
			
		||||
            requestedProperties.append(field.getName());
 | 
			
		||||
            requestedProperties.append(", ");
 | 
			
		||||
            requestedProperties.append(field.getName()).append(", ");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Trade details
 | 
			
		||||
        Container propertyValuesContainer = confirmTradeContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Spieler " + " " + tradeHandler.getSender().getName() + " " +" möchte:", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label( tradeHandler.getSender().getName() + " möchte:", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + offeredProperties, new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedAmount() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedJailCards() + " Sonderkarten", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("gegen:", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + requestedProperties, new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + tradeHandler.getRequestedAmount() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- " + tradeHandler.getRequestedJailCards() + " Sonderkarten", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("tauschen, willst du das Angebot annehmen?", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Ablehnen-Button
 | 
			
		||||
        // Decline button
 | 
			
		||||
        Button declineButton = confirmTradeContainer.addChild(new Button("Ablehnen", new ElementId("button")));
 | 
			
		||||
        declineButton.setFontSize(32);
 | 
			
		||||
        declineButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
@@ -93,7 +102,8 @@ public class ConfirmTrade extends Dialog {
 | 
			
		||||
            app.getGameLogic().send(new TradeResponse(false, tradeHandler));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Verhandeln-Button
 | 
			
		||||
 | 
			
		||||
        // Negotiate button
 | 
			
		||||
        Button negotiateButton = confirmTradeContainer.addChild(new Button("Verhandeln", new ElementId("button")));
 | 
			
		||||
        negotiateButton.setFontSize(32);
 | 
			
		||||
        negotiateButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
@@ -103,7 +113,8 @@ public class ConfirmTrade extends Dialog {
 | 
			
		||||
            t.setReceiver(app.getGameLogic().getPlayerHandler().getPlayerById(tradeHandler.getReceiver().getId()));
 | 
			
		||||
            new TradeMenu(app, t).open();
 | 
			
		||||
        }));
 | 
			
		||||
        // Confirm-Button
 | 
			
		||||
 | 
			
		||||
        // Confirm button
 | 
			
		||||
        Button confirmButton = confirmTradeContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
@@ -111,27 +122,30 @@ public class ConfirmTrade extends Dialog {
 | 
			
		||||
            app.getGameLogic().send(new TradeResponse(true, tradeHandler));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Center and adjust sizes
 | 
			
		||||
        backgroundContainer.setPreferredSize(confirmTradeContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        confirmTradeContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - confirmTradeContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + confirmTradeContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach to GUI node
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(confirmTradeContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(confirmTradeContainer);
 | 
			
		||||
@@ -139,9 +153,6 @@ public class ConfirmTrade extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,25 +12,25 @@ import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * EventCardPopup is a popup which appears when a certain EventCard is triggered by entering a EventCardField
 | 
			
		||||
 * EventCardPopup is a popup which appears when a certain EventCard is triggered by entering an EventCardField.
 | 
			
		||||
 */
 | 
			
		||||
public class EventCardPopup extends Dialog {
 | 
			
		||||
public class EventCardPopup extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the event card information. */
 | 
			
		||||
    private final Container eventCardContainer;
 | 
			
		||||
    private Container eventCardContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the EventCardPopup to display the details of a triggered event card.
 | 
			
		||||
@@ -42,90 +42,94 @@ public class EventCardPopup extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        // Initialize the UI components
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createEventCardContainer(description);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the semi-transparent background overlay.
 | 
			
		||||
     */
 | 
			
		||||
    private void createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        overlayBackground = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlayBackground.setMaterial(material);
 | 
			
		||||
        overlayBackground.setLocalTranslation(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the background container.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBackgroundContainer() {
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the main event card container and its UI components.
 | 
			
		||||
     *
 | 
			
		||||
     * @param description the description of the triggered event card
 | 
			
		||||
     */
 | 
			
		||||
    private void createEventCardContainer(String description) {
 | 
			
		||||
        eventCardContainer = new Container();
 | 
			
		||||
        eventCardContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        eventCardContainer.setPreferredSize(new Vector3f(550, 400, 10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
        // Event description
 | 
			
		||||
        Container textContainer = eventCardContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label(description, new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        textContainer.setPreferredSize(new Vector3f(300, 200, 0));
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Erklärungsfelder werden automatisch den descriptions der Message entnommen
 | 
			
		||||
        Container propertyValuesContainer = eventCardContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label(description, new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        propertyValuesContainer.setPreferredSize(new Vector3f(300,200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog( () -> {
 | 
			
		||||
        // Confirm button
 | 
			
		||||
        Button confirmButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Adjust sizes and center elements
 | 
			
		||||
        backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        eventCardContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            10
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                9
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach components to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(eventCardContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f));
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(eventCardContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape key action by closing the popup.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package pp.monopoly.client.gui.popups;
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
@@ -12,27 +13,27 @@ import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
import pp.monopoly.model.fields.FoodField;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * FoodFieldCard creates the popup for field information
 | 
			
		||||
 * FoodFieldCard creates the popup for field information.
 | 
			
		||||
 */
 | 
			
		||||
public class FoodFieldCard extends Dialog {
 | 
			
		||||
public class FoodFieldCard extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the food field information. */
 | 
			
		||||
    private final Container foodFieldContainer;
 | 
			
		||||
    private Container foodFieldContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a FoodFieldCard popup displaying details about a food field.
 | 
			
		||||
@@ -43,50 +44,76 @@ public class FoodFieldCard extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Retrieve field information
 | 
			
		||||
        int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
 | 
			
		||||
        FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        // Create UI elements
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createFoodFieldContainer(field);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the semi-transparent background overlay.
 | 
			
		||||
     */
 | 
			
		||||
    private void createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        overlayBackground = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlayBackground.setMaterial(material);
 | 
			
		||||
        overlayBackground.setLocalTranslation(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the background container.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBackgroundContainer() {
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the main food field container and its UI components.
 | 
			
		||||
     *
 | 
			
		||||
     * @param field the food field information to display
 | 
			
		||||
     */
 | 
			
		||||
    private void createFoodFieldContainer(FoodField field) {
 | 
			
		||||
        foodFieldContainer = new Container();
 | 
			
		||||
        foodFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
 | 
			
		||||
        foodFieldContainer.setPreferredSize(new Vector3f(360,445,1));
 | 
			
		||||
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        settingsTitle.setFontSize(48);
 | 
			
		||||
        settingsTitle.setColor(ColorRGBA.White);
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.White);
 | 
			
		||||
 | 
			
		||||
        // Field details
 | 
			
		||||
        Container propertyValuesContainer = foodFieldContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Wenn man Besitzer des", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label(field.getName()+" ist, so ist die", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete 40-mal so hoch, wie", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Augen auf den zwei Würfeln sind.", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Wenn man Besitzer beider", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Restaurants ist, so ist die", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete 100-mal so hoch, wie", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Augen auf den zwei Würfeln sind.", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Miete: 40x Würfel-Augen,", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„wenn Besitzer eines ", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Restaurants.", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Miete: 100x Würfel-Augen, ", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„wenn Besitzer eines ", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Restaurants.", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        // Quit button
 | 
			
		||||
        Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
 | 
			
		||||
        // Buy button
 | 
			
		||||
        Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
@@ -94,57 +121,41 @@ public class FoodFieldCard extends Dialog {
 | 
			
		||||
            app.getGameLogic().send(new BuyPropertyResponse());
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Adjust sizes and center elements
 | 
			
		||||
        backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        foodFieldContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach components to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(foodFieldContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(foodFieldContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(foodFieldContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,15 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyResponse;
 | 
			
		||||
@@ -14,17 +17,17 @@ import pp.monopoly.model.fields.GateField;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * GateFieldCard creates the popup for field information
 | 
			
		||||
 * GateFieldCard creates the popup for field information.
 | 
			
		||||
 */
 | 
			
		||||
public class GateFieldCard extends Dialog {
 | 
			
		||||
public class GateFieldCard extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the gate field information. */
 | 
			
		||||
    private final Container gateFieldContainer;
 | 
			
		||||
    private Container gateFieldContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a GateFieldCard popup displaying details about a gate field.
 | 
			
		||||
@@ -35,51 +38,63 @@ public class GateFieldCard extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        // Generate the corresponding field
 | 
			
		||||
        int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
 | 
			
		||||
        GateField field = (GateField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
        // Initialize UI elements
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createGateFieldContainer(field);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the background container.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBackgroundContainer() {
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the main gate field container and its UI components.
 | 
			
		||||
     *
 | 
			
		||||
     * @param field the gate field information to display
 | 
			
		||||
     */
 | 
			
		||||
    private void createGateFieldContainer(GateField field) {
 | 
			
		||||
        gateFieldContainer = new Container();
 | 
			
		||||
        //TODO: Set the size of the container to the size of the screen @Simon
 | 
			
		||||
        gateFieldContainer.setPreferredSize(new Vector3f(360,460,1));
 | 
			
		||||
        gateFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des gateFieldContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe
 | 
			
		||||
        // Title
 | 
			
		||||
        Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Preise werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        // Field details
 | 
			
		||||
        Container propertyValuesContainer = gateFieldContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Miete: 250 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("2 Bahnhof besitzt: 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("3 Bahnhof besitzt: 1000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("4 Bahnhof besitzt: 2000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 2 Tore", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("besitzt: 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 3 Tore", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("besitzt: 1000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Wenn man 4 Tore", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("besitzt: 2000 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Empty line
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        // Quit button
 | 
			
		||||
        Button quitButton = gateFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
 | 
			
		||||
        // Buy button
 | 
			
		||||
        Button buyButton = gateFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
        buyButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
@@ -87,37 +102,37 @@ public class GateFieldCard extends Dialog {
 | 
			
		||||
            app.getGameLogic().send(new BuyPropertyResponse());
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Adjust sizes and center elements
 | 
			
		||||
        backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        gateFieldContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach components to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(gateFieldContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(gateFieldContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(gateFieldContainer); // Remove main container
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); // Remove background container
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -11,31 +11,33 @@ import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Gulag is a warning popup triggered when a player lands on the "Wache" field in the Monopoly game.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 
 | 
			
		||||
 * This popup informs the player that they are being sent to the Gulag and includes a confirmation button.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class Gulag extends Dialog {
 | 
			
		||||
public class Gulag extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the Gulag warning message. */
 | 
			
		||||
    private final Container gulagContainer;
 | 
			
		||||
    private Container gulagContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Gulag popup, displaying a warning when a player lands on the "Wache" field.
 | 
			
		||||
     * Constructs the Gulag popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
@@ -43,90 +45,88 @@ public class Gulag extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Initialize UI elements
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createGulagContainer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the semi-transparent overlay background for the popup.
 | 
			
		||||
     */
 | 
			
		||||
    private void createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        overlayBackground = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlayBackground.setMaterial(material);
 | 
			
		||||
        overlayBackground.setLocalTranslation(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container providing a border for the popup.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBackgroundContainer() {
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main container for the Gulag warning message.
 | 
			
		||||
     */
 | 
			
		||||
    private void createGulagContainer() {
 | 
			
		||||
        gulagContainer = new Container();
 | 
			
		||||
        gulagContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        gulagContainer.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(gulagContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = gulagContainer.addChild(new Label("Du kommst ins Gulag!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = gulagContainer.addChild(new Label("Du kommst ins Gulag!", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
        // Confirmation Button
 | 
			
		||||
        Button confirmButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        // Adjust and position the containers
 | 
			
		||||
        backgroundContainer.setPreferredSize(gulagContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        gulagContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - gulagContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - gulagContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
            7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Attach components to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(gulagContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(gulagContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(gulagContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the popup.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -7,26 +7,24 @@ import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.message.client.NotificationAnswer;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * GulagInfo is a popup that provides options for a player who is stuck in the "Gulag" (jail) field.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * This dialog offers multiple actions, including paying a bribe, using a "Get Out of Jail" card, or waiting.
 | 
			
		||||
 * </p>
 | 
			
		||||
 */
 | 
			
		||||
public class GulagInfo extends Dialog {
 | 
			
		||||
public class GulagInfo extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the Gulag information dialog. */
 | 
			
		||||
    private final Container gulagInfoContainer;
 | 
			
		||||
    private Container gulagInfoContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a styled border around the dialog. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a GulagInfo popup that provides the player with options for getting out of the "Gulag" field.
 | 
			
		||||
@@ -38,36 +36,54 @@ public class GulagInfo extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        // Initialize UI components
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createGulagInfoContainer(trys);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container providing a border for the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBackgroundContainer() {
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        attachChild(backgroundContainer);
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für das Bestätigungspopup
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main container for the Gulag information dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param trys the number of failed attempts to roll doubles for release
 | 
			
		||||
     */
 | 
			
		||||
    private void createGulagInfoContainer(int trys) {
 | 
			
		||||
        gulagInfoContainer = new Container();
 | 
			
		||||
        gulagInfoContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des confirmTradeContainer an
 | 
			
		||||
        backgroundContainer.setPreferredSize(gulagInfoContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        
 | 
			
		||||
        // Titel
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = gulagInfoContainer.addChild(new Label("Gulag", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Werte werden dem Handel entnommen (Iwas auch immer da dann ist)
 | 
			
		||||
        Container propertyValuesContainer = gulagInfoContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Du sitzt im Gefänginis und kommst nicht raus ...", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("Es sei denn, du ...", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- bestichst die Wache mit 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- löst eine Gulag-Frei-Karte ein", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- wartest 3 Runden und bezahlst dann", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("- oder du würfelst einen Pasch", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        // Text Description
 | 
			
		||||
        Container textContainer = gulagInfoContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("„Du sitzt im Gefängnis und kommst nicht raus ...", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Es sei denn, du ...", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("- bestichst die Wache mit 500 EUR", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("- löst eine Gulag-Frei-Karte ein", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("- wartest 3 Runden und bezahlst dann", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("- oder du würfelst einen Pasch", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Action Buttons
 | 
			
		||||
        addActionButtons(trys);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Bezahlen-Button
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds action buttons to the dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param trys the number of failed attempts to roll doubles for release
 | 
			
		||||
     */
 | 
			
		||||
    private void addActionButtons(int trys) {
 | 
			
		||||
        // Bribe Button
 | 
			
		||||
        Button payButton = gulagInfoContainer.addChild(new Button("Bestechungsgeld bezahlen", new ElementId("button")));
 | 
			
		||||
        payButton.setFontSize(32);
 | 
			
		||||
        payButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
@@ -75,62 +91,63 @@ public class GulagInfo extends Dialog {
 | 
			
		||||
            app.getGameLogic().send(new NotificationAnswer("PayJail"));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Ereigniskarte-Button
 | 
			
		||||
        Button eventCardButton = gulagInfoContainer.addChild(new Button("Ereigniskarte nutzen", new ElementId("button")));
 | 
			
		||||
 | 
			
		||||
        // Use Jail-Free Card Button
 | 
			
		||||
        Button eventCardButton = gulagInfoContainer.addChild(new Button("Ereigniskarte nutzen", new ElementId("button-toolbar2")));
 | 
			
		||||
        eventCardButton.setFontSize(32);
 | 
			
		||||
        eventCardButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.getGameLogic().send(new NotificationAnswer("UseJailCard"));
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        // Schließen-Button
 | 
			
		||||
 | 
			
		||||
        // Close Button
 | 
			
		||||
        Button closeButton = gulagInfoContainer.addChild(new Button("Schließen", new ElementId("button")));
 | 
			
		||||
        closeButton.setFontSize(32);
 | 
			
		||||
        closeButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
        closeButton.addClickCommands(s -> ifTopDialog(this::close));
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        // Disable options based on conditions
 | 
			
		||||
        if (app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getNumJailCard() == 0) {
 | 
			
		||||
            eventCardButton.setEnabled(false);
 | 
			
		||||
        }
 | 
			
		||||
        if (trys == 3) {
 | 
			
		||||
            closeButton.setEnabled(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Adjust the background size
 | 
			
		||||
        backgroundContainer.setPreferredSize(gulagInfoContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Center the dialog and background
 | 
			
		||||
        gulagInfoContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - gulagInfoContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + gulagInfoContainer.getPreferredSize().y + padding) / 2,
 | 
			
		||||
            7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if(app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getNumJailCard() == 0) {
 | 
			
		||||
            eventCardButton.setEnabled(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(trys == 3) {
 | 
			
		||||
            closeButton.setEnabled(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Attach containers to the GUI
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(gulagInfoContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the GulagInfo popup and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(gulagInfoContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(gulagInfoContainer); // Remove dialog
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); // Remove background
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the GulagInfo dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,9 @@ import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * LooserPopUp is a dialog that appears when a player loses the game.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 
 | 
			
		||||
 * This popup provides a message of encouragement and an option to quit the game.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class LooserPopUp extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
@@ -123,9 +123,6 @@ public class LooserPopUp extends Dialog {
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the LooserPopUp dialog and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(LooserContainer);  // Entferne das Menü
 | 
			
		||||
@@ -134,9 +131,6 @@ public class LooserPopUp extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,19 +12,14 @@ import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * NoMoneyWarning is a warning popup that appears when a player tries to perform
 | 
			
		||||
 * an action they cannot afford due to insufficient funds, such as attempting
 | 
			
		||||
 * to purchase a property or building.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * This dialog notifies the player of their lack of funds and provides a single
 | 
			
		||||
 * confirmation button to close the dialog.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * NoMoneyWarning is a warning popup that informs the player they lack sufficient funds to proceed with an action.
 | 
			
		||||
 */
 | 
			
		||||
public class NoMoneyWarning extends Dialog {
 | 
			
		||||
public class NoMoneyWarning extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
@@ -46,66 +41,15 @@ public class NoMoneyWarning extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        backgroundContainer = createBackgroundContainer();
 | 
			
		||||
        noMoneyWarningContainer = createNoMoneyWarningContainer();
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        noMoneyWarningContainer = new Container();
 | 
			
		||||
        noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Na, schon wieder Pleite?", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(38);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast nicht genug Geld, um dieses Gebäude zu kaufen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Bestätigen-Button
 | 
			
		||||
        Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
        adjustPaddingAndCenter();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background for the dialog.
 | 
			
		||||
     * Creates the semi-transparent overlay background.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The geometry representing the overlay background.
 | 
			
		||||
     */
 | 
			
		||||
@@ -113,7 +57,7 @@ public class NoMoneyWarning extends Dialog {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
@@ -121,19 +65,83 @@ public class NoMoneyWarning extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the menu and removes the GUI elements.
 | 
			
		||||
     * Creates the background container for the dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @return A styled container for the dialog background.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    private Container createBackgroundContainer() {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     * Creates the main container for the NoMoneyWarning dialog UI.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The container for the dialog content.
 | 
			
		||||
     */
 | 
			
		||||
    private Container createNoMoneyWarningContainer() {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = container.addChild(new Label("Na, schon wieder Pleite?", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(38);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Warning message
 | 
			
		||||
        Container textContainer = container.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast nicht genug Geld, um dieses Gebäude zu kaufen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
 | 
			
		||||
        // Confirmation button
 | 
			
		||||
        Button confirmButton = container.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adjusts the padding and centers the dialog on the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void adjustPaddingAndCenter() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,115 +12,95 @@ import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Rent is a popup that is triggered when a player lands on a property owned by another player
 | 
			
		||||
 * and needs to pay rent in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Displays the rent amount and the recipient player's name, with an option to confirm the payment.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * ReceivedRent is a popup that informs a player about rent they have received.
 | 
			
		||||
 */
 | 
			
		||||
public class ReceivedRent extends Dialog {
 | 
			
		||||
public class ReceivedRent extends Dialog implements PopupDialog {
 | 
			
		||||
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the rent information and action. */
 | 
			
		||||
    private final Container rentContainer;
 | 
			
		||||
    private Container rentContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the rent popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Rent popup displaying the rent amount and recipient player.
 | 
			
		||||
     * Constructs the ReceivedRent popup displaying the rent amount and payer.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app        the Monopoly application instance
 | 
			
		||||
     * @param playerName the name of the player to whom the rent is owed
 | 
			
		||||
     * @param amount     the amount of rent to be paid
 | 
			
		||||
     * @param playerName the name of the player who paid the rent
 | 
			
		||||
     * @param amount     the amount of rent received
 | 
			
		||||
     */
 | 
			
		||||
    public ReceivedRent(MonopolyApp app, String playerName, int amount) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the overlay
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create and position the background container
 | 
			
		||||
        backgroundContainer = createBackgroundContainer();
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Create and position the rent container
 | 
			
		||||
        rentContainer = createRentContainer(playerName, amount);
 | 
			
		||||
        app.getGuiNode().attachChild(rentContainer);
 | 
			
		||||
 | 
			
		||||
        centerContainers();
 | 
			
		||||
        // Initialize GUI elements
 | 
			
		||||
        createOverlayBackground();
 | 
			
		||||
        createBackgroundContainer();
 | 
			
		||||
        createRentContainer(playerName, amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the overlay geometry
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
    private void createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        overlayBackground = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
        overlayBackground.setMaterial(material);
 | 
			
		||||
        overlayBackground.setLocalTranslation(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container with styling.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the styled background container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createBackgroundContainer() {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
        return container;
 | 
			
		||||
    private void createBackgroundContainer() {
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main rent container with title, text, and button.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerName the name of the player to whom the rent is owed
 | 
			
		||||
     * @param playerName the name of the player who paid the rent
 | 
			
		||||
     * @param amount     the rent amount
 | 
			
		||||
     * @return the rent container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createRentContainer(String playerName, int amount) {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
    private void createRentContainer(String playerName, int amount) {
 | 
			
		||||
        rentContainer = new Container();
 | 
			
		||||
        rentContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
 | 
			
		||||
        rentContainer.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = container.addChild(new Label("Miete!", new ElementId("warning-title")));
 | 
			
		||||
        Label title = rentContainer.addChild(new Label("Miete!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Rent message
 | 
			
		||||
        Container textContainer = container.addChild(new Container());
 | 
			
		||||
        Container textContainer = rentContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label(playerName + " zahlt dir " + amount + " EUR Miete",
 | 
			
		||||
                new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
        textContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
 | 
			
		||||
        // Payment button
 | 
			
		||||
        Button payButton = container.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        payButton.setFontSize(32);
 | 
			
		||||
        payButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
        // Confirmation button
 | 
			
		||||
        Button confirmButton = rentContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -145,20 +125,22 @@ public class ReceivedRent extends Dialog {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(rentContainer);
 | 
			
		||||
        centerContainers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(rentContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(rentContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,19 +12,16 @@ import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * RejectTrade is a popup that appears when a trade proposal is rejected by another player
 | 
			
		||||
 * in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Displays a message indicating that the proposed trade has been declined, along with
 | 
			
		||||
 * details of the involved players and provides an option to close the popup.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * RejectTrade is a popup that appears when a trade proposal is rejected by another player.
 | 
			
		||||
 * Displays a message indicating the rejection and provides an option to close the popup.
 | 
			
		||||
 */
 | 
			
		||||
public class RejectTrade extends Dialog {
 | 
			
		||||
public class RejectTrade extends Dialog implements PopupDialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
@@ -32,12 +29,11 @@ public class RejectTrade extends Dialog {
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the rejection message content. */
 | 
			
		||||
    private final Container noMoneyWarningContainer;
 | 
			
		||||
    private final Container rejectTradeContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the RejectTrade popup displaying the rejection of a trade proposal.
 | 
			
		||||
     *
 | 
			
		||||
@@ -48,68 +44,15 @@ public class RejectTrade extends Dialog {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        backgroundContainer = createBackgroundContainer();
 | 
			
		||||
        rejectTradeContainer = createRejectTradeContainer(msg);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Warnung
 | 
			
		||||
        noMoneyWarningContainer = new Container();
 | 
			
		||||
        noMoneyWarningContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        noMoneyWarningContainer.setPreferredSize(new Vector3f(550,250,10));
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Passt den backgroundContainer an die Größe des bankruptContainers an
 | 
			
		||||
        backgroundContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label gateFieldTitle = noMoneyWarningContainer.addChild(new Label("Handel abgelehnt!", new ElementId("warning-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der im Popup steht
 | 
			
		||||
        Container textContainer = noMoneyWarningContainer.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast Spieler"+ " " + msg.getTradeHandler().getReceiver().getName() + " " + "einen Handel vorgeschlagen", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Der Handel wurde abgelehnt", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Passt den textContainer an die Größe des bankruptContainers an
 | 
			
		||||
        textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        noMoneyWarningContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Popup
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - noMoneyWarningContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + noMoneyWarningContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(noMoneyWarningContainer);
 | 
			
		||||
        adjustPaddingAndCenter();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent background overlay for the popup.
 | 
			
		||||
     * Creates the semi-transparent background overlay for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
@@ -117,7 +60,7 @@ public class RejectTrade extends Dialog {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
@@ -125,19 +68,87 @@ public class RejectTrade extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the menu and removes the GUI elements.
 | 
			
		||||
     * Creates the background container for the dialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @return A styled container for the dialog background.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(noMoneyWarningContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        super.close();
 | 
			
		||||
    private Container createBackgroundContainer() {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape key action by closing the popup.
 | 
			
		||||
     * Creates the main container for the RejectTrade dialog UI.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the trade reply message containing details about the rejected trade
 | 
			
		||||
     * @return The container for the rejection message and action button
 | 
			
		||||
     */
 | 
			
		||||
    private Container createRejectTradeContainer(TradeReply msg) {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = container.addChild(new Label("Handel abgelehnt!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Rejection message
 | 
			
		||||
        Container textContainer = container.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du hast " + msg.getTradeHandler().getReceiver().getName()
 | 
			
		||||
                + " einen Handel vorgeschlagen.", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.addChild(new Label("Der Handel wurde abgelehnt.", new ElementId("label-Text")));
 | 
			
		||||
        textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
 | 
			
		||||
 | 
			
		||||
        // Confirmation button
 | 
			
		||||
        Button confirmButton = container.addChild(new Button("Bestätigen", new ElementId("button")));
 | 
			
		||||
        confirmButton.setFontSize(32);
 | 
			
		||||
        confirmButton.addClickCommands(source -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            close();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adjusts the padding and centers the dialog on the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private void adjustPaddingAndCenter() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
        backgroundContainer.setPreferredSize(rejectTradeContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
        rejectTradeContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - rejectTradeContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + rejectTradeContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            7
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(rejectTradeContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(rejectTradeContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,65 +12,58 @@ import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.PopupDialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Rent is a popup that is triggered when a player lands on a property owned by another player
 | 
			
		||||
 * and needs to pay rent in the Monopoly application.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 
 | 
			
		||||
 * Displays the rent amount and the recipient player's name, with an option to confirm the payment.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class Rent extends Dialog {
 | 
			
		||||
public class Rent extends Dialog implements PopupDialog {
 | 
			
		||||
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /** Semi-transparent overlay background for the popup. */
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
 | 
			
		||||
    /** Main container for the rent information and action. */
 | 
			
		||||
    private final Container rentContainer;
 | 
			
		||||
 | 
			
		||||
    /** Background container providing a border for the rent popup. */
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Rent popup displaying the rent amount and recipient player.
 | 
			
		||||
     * Constructs the Rent popup displaying the rent amount and recipient player's name.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app        the Monopoly application instance
 | 
			
		||||
     * @param playerName the name of the player to whom the rent is owed
 | 
			
		||||
     * @param amount     the amount of rent to be paid
 | 
			
		||||
     * @param playerName the name of the player to pay rent to
 | 
			
		||||
     * @param amount     the amount of rent to pay
 | 
			
		||||
     */
 | 
			
		||||
    public Rent(MonopolyApp app, String playerName, int amount) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Create the overlay
 | 
			
		||||
        // Create the overlay and containers
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create and position the background container
 | 
			
		||||
        backgroundContainer = createBackgroundContainer();
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Create and position the rent container
 | 
			
		||||
        rentContainer = createRentContainer(playerName, amount);
 | 
			
		||||
        app.getGuiNode().attachChild(rentContainer);
 | 
			
		||||
 | 
			
		||||
        // Center containers (positioning logic only, no GUI attachment)
 | 
			
		||||
        centerContainers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a semi-transparent overlay background.
 | 
			
		||||
     * Creates the semi-transparent overlay background for the popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the overlay geometry
 | 
			
		||||
     * @return the geometry of the overlay
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f));
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
@@ -78,21 +71,21 @@ public class Rent extends Dialog {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the background container with styling.
 | 
			
		||||
     * Creates the background container for the rent popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the styled background container
 | 
			
		||||
     * @return the background container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createBackgroundContainer() {
 | 
			
		||||
        Container container = new Container();
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
        return container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the main rent container with title, text, and button.
 | 
			
		||||
     * Creates the main container for the rent popup.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerName the name of the player to whom the rent is owed
 | 
			
		||||
     * @param amount     the rent amount
 | 
			
		||||
     * @param playerName the name of the player to pay rent to
 | 
			
		||||
     * @param amount     the amount of rent to pay
 | 
			
		||||
     * @return the rent container
 | 
			
		||||
     */
 | 
			
		||||
    private Container createRentContainer(String playerName, int amount) {
 | 
			
		||||
@@ -100,25 +93,21 @@ public class Rent extends Dialog {
 | 
			
		||||
        container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
 | 
			
		||||
        container.setPreferredSize(new Vector3f(550, 250, 10));
 | 
			
		||||
 | 
			
		||||
        // Title
 | 
			
		||||
        Label title = container.addChild(new Label("Miete!", new ElementId("warning-title")));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
        title.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Rent message
 | 
			
		||||
        Container textContainer = container.addChild(new Container());
 | 
			
		||||
        textContainer.addChild(new Label("Du musst " + amount + " EUR Miete an " + playerName + " zahlen",
 | 
			
		||||
                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;
 | 
			
		||||
@@ -130,14 +119,12 @@ public class Rent extends Dialog {
 | 
			
		||||
    private void centerContainers() {
 | 
			
		||||
        float padding = 10;
 | 
			
		||||
 | 
			
		||||
        // Center rent container
 | 
			
		||||
        rentContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - rentContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + rentContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Center background container with padding
 | 
			
		||||
        backgroundContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
 | 
			
		||||
@@ -146,22 +133,25 @@ public class Rent extends Dialog {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void show() {
 | 
			
		||||
        // Attach components to GUI only when the dialog is displayed via DialogManager
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(rentContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(rentContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(rentContainer);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
@@ -30,10 +29,10 @@ import java.util.stream.Collectors;
 | 
			
		||||
/**
 | 
			
		||||
 * RepayMortage is a popup that appears when a player selects the "Repay Mortgage" option
 | 
			
		||||
 * in the Building Administration Menu.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 
 | 
			
		||||
 * This popup allows the player to select mortgaged properties and repay their mortgages,
 | 
			
		||||
 * showing the total cost of the repayment. Includes options to confirm or cancel the repayment.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class RepayMortage extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
@@ -232,9 +231,6 @@ public class RepayMortage extends Dialog {
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the popup and removes its associated GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(repayMortageContainer);  // Entferne das Menü
 | 
			
		||||
@@ -242,9 +238,6 @@ public class RepayMortage extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu when the escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
@@ -30,10 +29,10 @@ import java.util.stream.Collectors;
 | 
			
		||||
/**
 | 
			
		||||
 * SellHouse is a popup that appears when a player clicks on the "Demolish" button
 | 
			
		||||
 * in the BuildingAdminMenu.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 
 | 
			
		||||
 * This dialog allows players to select their properties and demolish houses or hotels
 | 
			
		||||
 * for a partial refund of their purchase cost.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class SellHouse extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
@@ -231,9 +230,6 @@ public class SellHouse extends Dialog {
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the dialog and removes GUI elements from the screen.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(sellhouseContainer);  // Entferne das Menü
 | 
			
		||||
@@ -241,9 +237,6 @@ public class SellHouse extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
@@ -241,9 +240,6 @@ public class TakeMortage extends Dialog {
 | 
			
		||||
        this.cost.setText(cost+"");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the dialog and removes GUI elements from the screen.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(takeMortageContainer);  // Entferne das Menü
 | 
			
		||||
@@ -251,9 +247,6 @@ public class TakeMortage extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,9 @@ import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * WinnerPopUp is a dialog displayed when a player wins the Monopoly game.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 
 | 
			
		||||
 * This popup congratulates the player for their victory and provides an option to quit the game.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
public class WinnerPopUp extends Dialog {
 | 
			
		||||
    /** Reference to the Monopoly application instance. */
 | 
			
		||||
@@ -121,9 +121,6 @@ public class WinnerPopUp extends Dialog {
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the WinnerPopUp dialog and removes its GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachChild(WinnerContainer);  // Entferne das Menü
 | 
			
		||||
@@ -132,9 +129,6 @@ public class WinnerPopUp extends Dialog {
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the escape action to close the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
 
 | 
			
		||||
| 
		 After Width: | Height: | Size: 121 KiB  | 
| 
		 After Width: | Height: | Size: 114 KiB  | 
| 
		 After Width: | Height: | Size: 304 KiB  | 
| 
		 After Width: | Height: | Size: 473 KiB  | 
| 
		 After Width: | Height: | Size: 94 KiB  | 
| 
		 After Width: | Height: | Size: 136 KiB  | 
| 
		 After Width: | Height: | Size: 136 KiB  | 
| 
		 After Width: | Height: | Size: 588 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Textures/Bot.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 707 KiB  | 
| 
		 Before Width: | Height: | Size: 18 MiB After Width: | Height: | Size: 14 MiB  | 
| 
		 After Width: | Height: | Size: 215 KiB  | 
| 
		 After Width: | Height: | Size: 60 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Textures/Top.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 478 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Projekte/monopoly/client/src/main/resources/Textures/grass.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.2 MiB  | 
| 
		 After Width: | Height: | Size: 3.5 KiB  | 
| 
		 Before Width: | Height: | Size: 518 KiB  | 
| 
		 Before Width: | Height: | Size: 55 KiB  | 
| 
		 Before Width: | Height: | Size: 552 KiB  | 
| 
		 Before Width: | Height: | Size: 100 KiB  | 
| 
		 Before Width: | Height: | Size: 24 MiB  | 
| 
		 After Width: | Height: | Size: 215 KiB  | 
| 
		 After Width: | Height: | Size: 60 KiB  | 
| 
		 Before Width: | Height: | Size: 66 KiB  | 
| 
		 Before Width: | Height: | Size: 200 KiB  | 
| 
		 Before Width: | Height: | Size: 6.7 MiB  | 
| 
		 Before Width: | Height: | Size: 41 KiB  | 
| 
		 Before Width: | Height: | Size: 31 MiB After Width: | Height: | Size: 57 MiB  | 
@@ -69,10 +69,13 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
    /** The current state of the client game logic. */
 | 
			
		||||
    private ClientState state = new LobbyState(this);
 | 
			
		||||
 | 
			
		||||
    /** The player handler containing information about all players in the game. */
 | 
			
		||||
    private PlayerHandler playerHandler;
 | 
			
		||||
 | 
			
		||||
    /** The board manager containing information about all fields on the board. */
 | 
			
		||||
    private BoardManager boardManager = new BoardManager();
 | 
			
		||||
 | 
			
		||||
    /** The trade handler containing information about trades in the game. */
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -114,6 +117,11 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
        state.entry();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the player handler containing information about all players in the game.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the player handler
 | 
			
		||||
     */
 | 
			
		||||
    public PlayerHandler getPlayerHandler() {
 | 
			
		||||
        return playerHandler;
 | 
			
		||||
    }
 | 
			
		||||
@@ -127,6 +135,11 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
        return board;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the trade handler containing information about trades in the game.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the trade handler
 | 
			
		||||
     */
 | 
			
		||||
    public TradeHandler getTradeHandler() {
 | 
			
		||||
        return tradeHandler;
 | 
			
		||||
    }
 | 
			
		||||
@@ -205,6 +218,11 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
        state.update(delta);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns if it is the player's turn.
 | 
			
		||||
     *
 | 
			
		||||
     * @return true if it is the player's turn, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isTurn() {
 | 
			
		||||
        return state.isTurn();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -40,23 +41,34 @@ import pp.monopoly.model.fields.WacheField;
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class Player implements FieldVisitor<Void> {
 | 
			
		||||
    /** The logger for this class */
 | 
			
		||||
    private final static Logger LOGGER = System.getLogger(Player.class.getName());
 | 
			
		||||
    /** The player id */
 | 
			
		||||
    private final int id;
 | 
			
		||||
    /** The player name */
 | 
			
		||||
    private String name;
 | 
			
		||||
    /** The player account balance */
 | 
			
		||||
    private int accountBalance = 15000;
 | 
			
		||||
    /** The player figure */
 | 
			
		||||
    private String figure;
 | 
			
		||||
    /** The player properties */
 | 
			
		||||
    private Set<Integer> properties = new HashSet<>();
 | 
			
		||||
    /** The number of GetOutOfJailCards owned by the player */
 | 
			
		||||
    private int getOutOfJailCard;
 | 
			
		||||
    /** The current field id of the player */
 | 
			
		||||
    private int fieldID;
 | 
			
		||||
    /** The result of the last dice roll */
 | 
			
		||||
    private DiceResult rollResult;
 | 
			
		||||
    /** The player handler */
 | 
			
		||||
    private transient final PlayerHandler handler;
 | 
			
		||||
    /** The current state of the player */
 | 
			
		||||
    private transient PlayerState state = new WaitForTurnState();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private Player(){
 | 
			
		||||
        id = 0;
 | 
			
		||||
        handler = null;
 | 
			
		||||
        this(0, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -69,6 +81,7 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.id = id;
 | 
			
		||||
        this.handler = handler;
 | 
			
		||||
        LOGGER.log(Logger.Level.INFO, "Player created: " + name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -77,8 +90,7 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
     * @param handler the PlayerHandler this player is a part of
 | 
			
		||||
     */
 | 
			
		||||
    public Player(int id, PlayerHandler handler) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
        this.handler = handler;
 | 
			
		||||
        this(id, null, handler);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -97,6 +109,12 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        return figure;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the color of the player
 | 
			
		||||
     * 
 | 
			
		||||
     * @param id the id of the player
 | 
			
		||||
     * @return the color of the player
 | 
			
		||||
     */
 | 
			
		||||
    public static PlayerColor getColor(int id) {
 | 
			
		||||
        switch ((id%6)+1) {
 | 
			
		||||
            case 1: return PlayerColor.CYAN;
 | 
			
		||||
@@ -143,6 +161,10 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        return fieldID;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the state of the player to active
 | 
			
		||||
     * If the player is in jail, the player will be asked to pay the bail
 | 
			
		||||
     */
 | 
			
		||||
    void setActive() {
 | 
			
		||||
        System.out.println("State:   "+state.getClass().getName());
 | 
			
		||||
        if(!(state instanceof JailState)) {
 | 
			
		||||
@@ -153,6 +175,11 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Finish the turn of the player
 | 
			
		||||
     * If the player has a negative account balance, the player will be bankrupted
 | 
			
		||||
     * @return true if the turn was finished successfully, false if the player is bankrupt
 | 
			
		||||
     */
 | 
			
		||||
    boolean finishTurn() {
 | 
			
		||||
        if(canFinishTurn()) {
 | 
			
		||||
            if (state instanceof ActiveState) state = new WaitForTurnState();
 | 
			
		||||
@@ -164,14 +191,26 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the player can finish the turn
 | 
			
		||||
     * @return true if the player can finish the turn, false if the player is bankrupt
 | 
			
		||||
     */
 | 
			
		||||
    boolean canFinishTurn() {
 | 
			
		||||
        return accountBalance >= 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current state of the player
 | 
			
		||||
     * @return the current state of the player
 | 
			
		||||
     */
 | 
			
		||||
    public PlayerState getState() {
 | 
			
		||||
        return state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the state of the player
 | 
			
		||||
     * @param state the new state of the player
 | 
			
		||||
     */
 | 
			
		||||
    public void setState(PlayerState state) {
 | 
			
		||||
        this.state = state;
 | 
			
		||||
    }
 | 
			
		||||
@@ -297,7 +336,7 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of GEtOutOfJailCards owned by this player
 | 
			
		||||
     * @return
 | 
			
		||||
     * @return the number of GetOutOfJailCards owned by this player
 | 
			
		||||
     */
 | 
			
		||||
    public int getNumJailCard() {
 | 
			
		||||
        return getOutOfJailCard;
 | 
			
		||||
@@ -335,7 +374,11 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        state.useJailCard();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void sendRentNotification(String keyword, Player player, int amount) {
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a notification to the player
 | 
			
		||||
     * @param keyword the keyword of the notification
 | 
			
		||||
     */
 | 
			
		||||
    private void sendNotification(String keyword, Player player, int amount) {
 | 
			
		||||
        NotificationMessage msg = new NotificationMessage(keyword);
 | 
			
		||||
        msg.setRentAmount(amount);
 | 
			
		||||
        msg.setRentOwnerId(player.getName());
 | 
			
		||||
@@ -351,8 +394,8 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
            int rent = field.calcRent();
 | 
			
		||||
            field.getOwner().earnMoney(rent);
 | 
			
		||||
            pay(rent);
 | 
			
		||||
            sendRentNotification("ReceivedRent", field.getOwner(), rent);
 | 
			
		||||
            sendRentNotification("rent", this, rent);
 | 
			
		||||
            sendNotification("ReceivedRent", this, rent);
 | 
			
		||||
            sendNotification("rent", field.getOwner(), rent);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
@@ -369,8 +412,8 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
            int rent = rollResult.calcTotal()*factor;
 | 
			
		||||
            field.getOwner().earnMoney(rent);
 | 
			
		||||
            pay(rent);
 | 
			
		||||
            sendRentNotification("ReceivedRent", field.getOwner(), rent);
 | 
			
		||||
            sendRentNotification("rent", this, rent);
 | 
			
		||||
            sendNotification("ReceivedRent", this, rent);
 | 
			
		||||
            sendNotification("rent", field.getOwner(), rent);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
@@ -384,8 +427,8 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
 | 
			
		||||
            field.getOwner().earnMoney(rent);
 | 
			
		||||
            pay(rent);
 | 
			
		||||
            sendRentNotification("ReceivedRent", field.getOwner(), rent);
 | 
			
		||||
            sendRentNotification("rent", this, rent);
 | 
			
		||||
            sendNotification("ReceivedRent", this, rent);
 | 
			
		||||
            sendNotification("rent", field.getOwner(), rent);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
@@ -431,6 +474,10 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the properties owned by the player
 | 
			
		||||
     * @return the properties owned by the player
 | 
			
		||||
     */
 | 
			
		||||
    public List<PropertyField> getPropertyFields() {
 | 
			
		||||
        List<PropertyField> properties = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
@@ -450,6 +497,9 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        handler.getLogic().send(this, new JailEvent(true));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends the player to jail by setting position and state.
 | 
			
		||||
     */
 | 
			
		||||
    void jail() {
 | 
			
		||||
        state = new JailState();
 | 
			
		||||
        fieldID = 10;
 | 
			
		||||
@@ -473,6 +523,10 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        return count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of Houses owned by the player
 | 
			
		||||
     * @return the number of houses owned by the player
 | 
			
		||||
     */
 | 
			
		||||
    public int getNumHouses() {
 | 
			
		||||
        int total = 0;
 | 
			
		||||
        for (PropertyField field : getPropertyFields()) {
 | 
			
		||||
@@ -483,6 +537,10 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        return total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of Hotels owned by the player
 | 
			
		||||
     * @return the number of hotels owned by the player
 | 
			
		||||
     */
 | 
			
		||||
    public int getNumHotels() {
 | 
			
		||||
        int total = 0;
 | 
			
		||||
        for (PropertyField field : getPropertyFields()) {
 | 
			
		||||
@@ -527,6 +585,9 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        return state.rollDice();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Bankrupts the player by removing all properties and setting the account balance to 0.
 | 
			
		||||
     */
 | 
			
		||||
    private void bankrupt() {
 | 
			
		||||
        for (PropertyField field : getPropertyFields()) {
 | 
			
		||||
            field.setOwner(null);
 | 
			
		||||
@@ -654,6 +715,10 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * A class to represent the WaitForTurn PlayerState
 | 
			
		||||
     * Set when it is not the players turn
 | 
			
		||||
     */
 | 
			
		||||
    private class WaitForTurnState implements PlayerState {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
@@ -676,10 +741,18 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        return "Player{name=" + name + ", figure=" + figure + "}";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a property to the player
 | 
			
		||||
     * @param id the id of the property to be added
 | 
			
		||||
     */
 | 
			
		||||
    public void addProperty(Integer id) {
 | 
			
		||||
        properties.add(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes a property from the player
 | 
			
		||||
     * @param id the id of the property to be removed
 | 
			
		||||
     */
 | 
			
		||||
    public void removeProperty(Integer id) {
 | 
			
		||||
        properties.remove(id);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,16 +6,39 @@ import com.jme3.math.ColorRGBA;
 | 
			
		||||
 * Enum representing six distinct colors for players in the game.
 | 
			
		||||
 */
 | 
			
		||||
public enum PlayerColor {
 | 
			
		||||
    /**
 | 
			
		||||
     * Representing the color cyan.
 | 
			
		||||
     */
 | 
			
		||||
    CYAN(new ColorRGBA(69 / 255f, 205 / 255f, 205 / 255f, 1), "Cyan"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Representing the color yellow.
 | 
			
		||||
     */
 | 
			
		||||
    YELLOW(new ColorRGBA(225 / 255f, 201 / 255f, 44 / 255f, 1), "Yellow"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Representing the color red.
 | 
			
		||||
     */
 | 
			
		||||
    RED(new ColorRGBA(255 / 255f, 33 / 255f, 33 / 255f, 1), "Red"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Representing the color pink.
 | 
			
		||||
     */
 | 
			
		||||
    PINK(new ColorRGBA(196 / 255f, 73 / 255f, 240 / 255f, 1), "Pink"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Representing the color green.
 | 
			
		||||
     */
 | 
			
		||||
    GREEN(new ColorRGBA(61 / 255f, 227 / 255f, 58 / 255f, 1), "Green"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Representing the color purple.
 | 
			
		||||
     */
 | 
			
		||||
    PURPLE(new ColorRGBA(60 / 255f, 74 / 255f, 223 / 255f, 1), "Purple");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** The corresponding ColorRGBA color */
 | 
			
		||||
    private final ColorRGBA color;
 | 
			
		||||
    /** The name of the color */
 | 
			
		||||
    private final String colorName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,7 @@ public class PlayerHandler {
 | 
			
		||||
     * @param index the index of the queue
 | 
			
		||||
     * @return the Player at the required index
 | 
			
		||||
     */
 | 
			
		||||
    Player getPlayerAtIndex(int index) {
 | 
			
		||||
    public Player getPlayerAtIndex(int index) {
 | 
			
		||||
        return players.get(index);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -172,12 +172,20 @@ public class PlayerHandler {
 | 
			
		||||
        players.get(0).setActive();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the starting balance for all players
 | 
			
		||||
     * @param amount the amount to be set
 | 
			
		||||
     */
 | 
			
		||||
    public void setStartBalance(int amount) {
 | 
			
		||||
        for (Player player : players) {
 | 
			
		||||
            player.setAccountBalance(amount);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a player to have an extra turn
 | 
			
		||||
     * @param player the player to have an extra turn
 | 
			
		||||
     */
 | 
			
		||||
    public void extraTurn(Player player) {
 | 
			
		||||
        if (players.contains(player)) extra = player;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -38,15 +38,26 @@ import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
 * Manages game states, player interactions, and message handling.
 | 
			
		||||
 */
 | 
			
		||||
public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    /**
 | 
			
		||||
     * The logger for the ServerGameLogic class.
 | 
			
		||||
     */
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(ServerGameLogic.class.getName());
 | 
			
		||||
 | 
			
		||||
    /** The game configuration. */
 | 
			
		||||
    private final MonopolyConfig config;
 | 
			
		||||
    /** The player handler for managing players. */
 | 
			
		||||
    private final PlayerHandler playerHandler = new PlayerHandler(this);
 | 
			
		||||
    /** The sender used to send messages to clients. */
 | 
			
		||||
    private final ServerSender serverSender;
 | 
			
		||||
    /** The current state of the game. */
 | 
			
		||||
    private ServerState state = ServerState.LOBBY;
 | 
			
		||||
    /** The maximum number of players allowed in the game. */
 | 
			
		||||
    private static final int MAX_PLAYERS = 6;
 | 
			
		||||
    /** The board manager for managing the game board. */
 | 
			
		||||
    private BoardManager boardManager = new BoardManager();
 | 
			
		||||
    /** The deck helper for managing card decks. */
 | 
			
		||||
    private final DeckHelper deckHelper = new DeckHelper();
 | 
			
		||||
    /** The amount of money each player starts with. */
 | 
			
		||||
    private int startMoney;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -383,10 +394,21 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
        return boardManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the player handler, which manages player actions and turns.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id the id of the player to retrieve
 | 
			
		||||
     * @return the PlayerHandler instance managing players
 | 
			
		||||
     */
 | 
			
		||||
    public Player getPlayerById(int id) {
 | 
			
		||||
        return playerHandler.getPlayerById(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the deck helper, which manages decks of cards.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the deck helper
 | 
			
		||||
     */
 | 
			
		||||
    public DeckHelper getDeckHelper() {
 | 
			
		||||
        return deckHelper;
 | 
			
		||||
    }
 | 
			
		||||
@@ -452,6 +474,9 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
        updateAllPlayers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Generates a predefined game state for testing and demo purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private void generatePredefinedGameState() {
 | 
			
		||||
 | 
			
		||||
        if(playerHandler.getPlayerCount() < 2) {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,24 @@ import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sent by the client to the server to alter the properties of a field.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class AlterProperty extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    /** The keyword to indicate what action should be performed */
 | 
			
		||||
    private String keyword;
 | 
			
		||||
    /** The properties that should be altered */
 | 
			
		||||
    private Set<Integer> properties;
 | 
			
		||||
 | 
			
		||||
    /** No-Args Construcotr for serilization */
 | 
			
		||||
    private AlterProperty() {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new AlterProperty message.
 | 
			
		||||
     * @param keyword The keyword to indicate what action should be performed
 | 
			
		||||
     */
 | 
			
		||||
    public AlterProperty(String keyword) {
 | 
			
		||||
        this.keyword = keyword;
 | 
			
		||||
    }
 | 
			
		||||
@@ -21,14 +31,26 @@ public class AlterProperty extends ClientMessage{
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the keyword to indicate what action should be performed.
 | 
			
		||||
     * @return keyword The keyword to indicate what action should be performed
 | 
			
		||||
     */
 | 
			
		||||
    public String getKeyword() {
 | 
			
		||||
        return keyword;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the properties that should be altered.
 | 
			
		||||
     * @param properties The properties that should be altered
 | 
			
		||||
     */
 | 
			
		||||
    public void setProperties(Set<Integer> properties) {
 | 
			
		||||
        this.properties = properties;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the properties that should be altered.
 | 
			
		||||
     * @return properties The properties that should be altered
 | 
			
		||||
     */
 | 
			
		||||
    public Set<Integer> getProperties() {
 | 
			
		||||
        return properties;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,17 +2,30 @@ package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sent by the client to answer a notification.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class NotificationAnswer extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    /** The keyword to indicate the awnser */
 | 
			
		||||
    private String keyword;
 | 
			
		||||
 | 
			
		||||
    /** No-Args constructor for serilization */
 | 
			
		||||
    private NotificationAnswer() {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new NotificationAnswer
 | 
			
		||||
     * @param keyword the keyword to indicate the awnser
 | 
			
		||||
     */
 | 
			
		||||
    public NotificationAnswer(String keyword) {
 | 
			
		||||
        this.keyword = keyword;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the keyword to indicate the awnser
 | 
			
		||||
     * @return the keyword to indicate the awnser
 | 
			
		||||
     */
 | 
			
		||||
    public String getKeyword() {
 | 
			
		||||
        return keyword;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -31,18 +31,34 @@ public class PlayerReady extends ClientMessage {
 | 
			
		||||
        this.startMoney = startMoney;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the name of the player.
 | 
			
		||||
     * @return the name of the player
 | 
			
		||||
     */
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the figure of the player.
 | 
			
		||||
     * @return the figure of the player
 | 
			
		||||
     */
 | 
			
		||||
    public String getFigure() {
 | 
			
		||||
        return figure;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether the player is ready.
 | 
			
		||||
     * @return whether the player is ready
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isReady() {
 | 
			
		||||
        return isReady;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the initial capital of the game.
 | 
			
		||||
     * @return the initial capital of the game
 | 
			
		||||
     */
 | 
			
		||||
    public int getStartMoney() {
 | 
			
		||||
        return startMoney;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,11 @@ public class TradeOffer extends ClientMessage{
 | 
			
		||||
        this.tradehandler = tradehandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the tradehandler.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the tradehandler
 | 
			
		||||
     */
 | 
			
		||||
    public TradeHandler getTradeHandler() { return tradehandler; }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,10 @@ import com.jme3.network.serializing.Serializable;
 | 
			
		||||
@Serializable
 | 
			
		||||
public class ViewAssetsRequest extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    public ViewAssetsRequest() {
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor needed for the serialization.
 | 
			
		||||
     */
 | 
			
		||||
    public ViewAssetsRequest() {}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,26 +2,44 @@ package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sent from server to client to inform about a build action.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class BuildInfo extends ServerMessage {
 | 
			
		||||
 | 
			
		||||
    /** Id of the field that was altered */
 | 
			
		||||
    private final int id;
 | 
			
		||||
    /** True if a house/hotel was added, false if it was removed */
 | 
			
		||||
    private final boolean added;
 | 
			
		||||
 | 
			
		||||
    /** No-args constructor required for serialization */
 | 
			
		||||
    private BuildInfo() {
 | 
			
		||||
        this(0, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new BuildInfo message.
 | 
			
		||||
     * @param id Id of the field that was altered
 | 
			
		||||
     * @param added True if a house/hotel was added, false if it was removed
 | 
			
		||||
     */
 | 
			
		||||
    public BuildInfo(int id, boolean added) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
        this.added = added;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the id of the field that was altered.
 | 
			
		||||
     * @return Id of the field that was altered
 | 
			
		||||
     */
 | 
			
		||||
    public int getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a house/hotel was added.
 | 
			
		||||
     * @return True if a house/hotel was added, false if it was removed
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isAdded() {
 | 
			
		||||
        return added;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,15 @@ package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sent by the server to the client to request the client to show a buy property popup.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class BuyPropertyRequest extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructor for the BuyPropertyRequest.
 | 
			
		||||
     */
 | 
			
		||||
    public BuyPropertyRequest(){}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,15 @@ import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sent by the server to the client to inform the client about the result of a dice roll.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class DiceResult extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    /** The first value of the DiceRoll */
 | 
			
		||||
    private final int a;
 | 
			
		||||
    /** The second value of the DiceRoll */
 | 
			
		||||
    private final int b;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -18,11 +23,20 @@ public class DiceResult extends ServerMessage{
 | 
			
		||||
        b = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new DiceResult with the given values.
 | 
			
		||||
     * @param a The first value of the DiceRoll
 | 
			
		||||
     * @param b The second value of the DiceRoll
 | 
			
		||||
     */
 | 
			
		||||
    public DiceResult(int a, int b) {
 | 
			
		||||
        this.a = a;
 | 
			
		||||
        this.b = b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the values of the DiceRoll.
 | 
			
		||||
     * @return The values of the DiceRoll
 | 
			
		||||
     */
 | 
			
		||||
    public List<Integer> getRollResult() {
 | 
			
		||||
        return List.of(a,b);
 | 
			
		||||
    }
 | 
			
		||||
@@ -32,10 +46,18 @@ public class DiceResult extends ServerMessage{
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether the DiceRoll is a doublets.
 | 
			
		||||
     * @return Whether the DiceRoll is a doublets
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isDoublets() {
 | 
			
		||||
        return a == b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the total value of the DiceRoll.
 | 
			
		||||
     * @return The total value of the DiceRoll
 | 
			
		||||
     */
 | 
			
		||||
    public int calcTotal() {
 | 
			
		||||
        return a+b;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,9 @@ package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Message for drawing a card from the chance or community chest deck.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class EventDrawCard extends ServerMessage{
 | 
			
		||||
    private String cardDescription;
 | 
			
		||||
@@ -11,6 +14,11 @@ public class EventDrawCard extends ServerMessage{
 | 
			
		||||
     */
 | 
			
		||||
    private EventDrawCard() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new EventDrawCard message.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param cardDescription the description of the card that was drawn
 | 
			
		||||
     */
 | 
			
		||||
    public EventDrawCard(String cardDescription) {
 | 
			
		||||
        this.cardDescription = cardDescription;
 | 
			
		||||
    }
 | 
			
		||||
@@ -20,6 +28,11 @@ public class EventDrawCard extends ServerMessage{
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the description of the card that was drawn.
 | 
			
		||||
     * 
 | 
			
		||||
     * @return the description of the card that was drawn
 | 
			
		||||
     */
 | 
			
		||||
    public String getCardDescription() {
 | 
			
		||||
        return cardDescription;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,14 @@ package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Message to inform the player that the game is over and if he won or not.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class GameOver extends ServerMessage {
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the player is the winner.
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isWinner;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -11,10 +17,20 @@ public class GameOver extends ServerMessage{
 | 
			
		||||
     */
 | 
			
		||||
    private GameOver() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new GameOver message.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param isWinner true if the player is the winner, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public GameOver(boolean isWinner) {
 | 
			
		||||
        this.isWinner = isWinner;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether the player is the winner.
 | 
			
		||||
     * 
 | 
			
		||||
     * @return true if the player is the winner, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isWinner() {
 | 
			
		||||
        return isWinner;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||