mirror of
				https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02.git
				synced 2025-11-04 04:15:52 +01:00 
			
		
		
		
	Compare commits
	
		
			26 Commits
		
	
	
		
			b6968df451
			...
			b_schmelz_
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					237d93f38b | ||
| 
						 | 
					f78106b43d | ||
| 
						 | 
					113202278f | ||
| 
						 | 
					6b2b917864 | ||
| 
						 | 
					0f44d37d4a | ||
| 
						 | 
					f248a77c81 | ||
| 
						 | 
					aa9c073931 | ||
| 
						 | 
					1740988629 | ||
| 
						 | 
					dcc7cf9c20 | ||
| 
						 | 
					5501c0716d | ||
| 
						 | 
					8261e1b3b2 | ||
| 
						 | 
					5cca8f5c05 | ||
| 
						 | 
					133921cfbb | ||
| 
						 | 
					4cf14d02ee | ||
| 
						 | 
					50bee91775 | ||
| 
						 | 
					a656ab5062 | ||
| 
						 | 
					b2a6f86fc2 | ||
| 
						 | 
					9f90d92198 | ||
| 
						 | 
					3e913f636c | ||
| 
						 | 
					806c00c94a | ||
| 
						 | 
					4fff32c13e | ||
| 
						 | 
					1c99117ca0 | ||
| 
						 | 
					62421e87cc | ||
| 
						 | 
					e343074240 | ||
| 
						 | 
					35f154aa0f | ||
| 
						 | 
					4488911e82 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -4,7 +4,6 @@ build
 | 
			
		||||
 | 
			
		||||
# VSC
 | 
			
		||||
bin
 | 
			
		||||
.vscode
 | 
			
		||||
 | 
			
		||||
# IntelliJ
 | 
			
		||||
*.iml
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +0,0 @@
 | 
			
		||||
<component name="ProjectRunConfigurationManager">
 | 
			
		||||
  <configuration default="false" name="MonopolyApp" type="Application" factoryName="Application" singleton="false"
 | 
			
		||||
                 nameIsGenerated="true">
 | 
			
		||||
    <option name="MAIN_CLASS_NAME" value="pp.monopoly.client.MonopolyApp"/>
 | 
			
		||||
    <module name="Projekte.monopoly.client.main"/>
 | 
			
		||||
    <option name="VM_PARAMETERS" value="-Djava.util.logging.config.file=logging.properties"/>
 | 
			
		||||
    <option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$"/>
 | 
			
		||||
    <extension name="coverage">
 | 
			
		||||
      <pattern>
 | 
			
		||||
        <option name="PATTERN" value="pp.monopoly.client.*"/>
 | 
			
		||||
        <option name="ENABLED" value="true"/>
 | 
			
		||||
      </pattern>
 | 
			
		||||
    </extension>
 | 
			
		||||
    <method v="2">
 | 
			
		||||
      <option name="Make" enabled="true"/>
 | 
			
		||||
    </method>
 | 
			
		||||
  </configuration>
 | 
			
		||||
</component>
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
<component name="ProjectRunConfigurationManager">
 | 
			
		||||
  <configuration default="false" name="MonopolyServer" type="Application" factoryName="Application"
 | 
			
		||||
                 nameIsGenerated="true">
 | 
			
		||||
    <option name="MAIN_CLASS_NAME" value="pp.monopoly.server.MonopolyServer"/>
 | 
			
		||||
    <module name="Projekte.monopoly.server.main"/>
 | 
			
		||||
    <option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$"/>
 | 
			
		||||
    <extension name="coverage">
 | 
			
		||||
      <pattern>
 | 
			
		||||
        <option name="PATTERN" value="pp.monopoly.server.*"/>
 | 
			
		||||
        <option name="ENABLED" value="true"/>
 | 
			
		||||
      </pattern>
 | 
			
		||||
    </extension>
 | 
			
		||||
    <method v="2">
 | 
			
		||||
      <option name="Make" enabled="true"/>
 | 
			
		||||
    </method>
 | 
			
		||||
  </configuration>
 | 
			
		||||
</component>
 | 
			
		||||
@@ -7,21 +7,22 @@
 | 
			
		||||
 | 
			
		||||
package pp.battleship.client;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.prefs.Preferences;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Checkbox;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import static pp.battleship.Resources.lookup;
 | 
			
		||||
import pp.battleship.client.gui.GameMusic;
 | 
			
		||||
import pp.battleship.client.gui.VolumeSlider;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.StateCheckboxModel;
 | 
			
		||||
import pp.dialog.TextInputDialog;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.prefs.Preferences;
 | 
			
		||||
 | 
			
		||||
import static pp.battleship.Resources.lookup;
 | 
			
		||||
import static pp.util.PreferencesUtils.getPreferences;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -38,7 +39,7 @@ class Menu extends Dialog {
 | 
			
		||||
    private final VolumeSlider slider;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Menu dialog for the Battleship application.+
 | 
			
		||||
     * Constructs the Menu dialog for the Battleship application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the BattleshipApp instance
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -45,12 +45,7 @@ public class ModelExporter extends SimpleApplication {
 | 
			
		||||
        export("Models/BoatSmall/12219_boat_v2_L2.obj", "BoatSmall.j3o"); //NON-NLS
 | 
			
		||||
        export("Models/Battle/14084_WWII_Ship_German_Type_II_U-boat_v2_L1.obj", "Battle.j3o"); //NON-NLS
 | 
			
		||||
        export("Models/CV/essex_scb-125_generic.obj", "CV.j3o"); //NON-NLS
 | 
			
		||||
        export("Models/Figures/Würfel_blau.obj", "Würfel_blau.j30");
 | 
			
		||||
        export("Models/Figures/Würfel_gelb.obj", "Würfel_gelb.j30");
 | 
			
		||||
        export("Models/Figures/Würfel_grün.obj", "Würfel_grün.j30");
 | 
			
		||||
        export("Models/Figures/Würfel_rosa.obj", "Würfel_rosa.j30");
 | 
			
		||||
        export("Models/Figures/Würfel_rot.obj", "Würfel_rot.j30");
 | 
			
		||||
        export("Models/Figures/Würfel_schwarz.obj", "Würfel_schwarz.j30");
 | 
			
		||||
 | 
			
		||||
        stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,7 @@ public class DialogManager {
 | 
			
		||||
     *
 | 
			
		||||
     * @param dialog the dialog to open
 | 
			
		||||
     */
 | 
			
		||||
    public void open(Dialog dialog) {
 | 
			
		||||
    void open(Dialog dialog) {
 | 
			
		||||
        dialogStack.push(dialog);
 | 
			
		||||
        dialog.update();
 | 
			
		||||
        app.getGuiNode().attachChild(dialog);
 | 
			
		||||
@@ -133,7 +133,7 @@ public class DialogManager {
 | 
			
		||||
     * @param dialog the dialog to close
 | 
			
		||||
     * @throws IllegalArgumentException if the specified dialog is not the top dialog
 | 
			
		||||
     */
 | 
			
		||||
    public void close(Dialog dialog) {
 | 
			
		||||
    void close(Dialog dialog) {
 | 
			
		||||
        if (!isTop(dialog))
 | 
			
		||||
            throw new IllegalArgumentException(dialog + " is not the top dialog");
 | 
			
		||||
        dialogStack.pop();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,7 @@
 | 
			
		||||
// Styling of Lemur components
 | 
			
		||||
// For documentation, see:
 | 
			
		||||
// For documentation, see
 | 
			
		||||
// https://github.com/jMonkeyEngine-Contributions/Lemur/wiki/Styling
 | 
			
		||||
import com.simsilica.lemur.*
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Button
 | 
			
		||||
import com.simsilica.lemur.Button.ButtonAction
 | 
			
		||||
import com.simsilica.lemur.Command
 | 
			
		||||
@@ -11,19 +10,14 @@ import com.simsilica.lemur.Insets3f
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent
 | 
			
		||||
import com.simsilica.lemur.component.TbtQuadBackgroundComponent
 | 
			
		||||
 | 
			
		||||
def bgColor = color(1, 1, 1, 1)
 | 
			
		||||
def buttonEnabledColor = color(0, 0, 0, 1)
 | 
			
		||||
def bgColor = color(0.25, 0.5, 0.5, 1)
 | 
			
		||||
def buttonEnabledColor = color(0.8, 0.9, 1, 1)
 | 
			
		||||
def buttonDisabledColor = color(0.8, 0.9, 1, 0.2)
 | 
			
		||||
def buttonBgColor = color(1, 1, 1, 1)
 | 
			
		||||
def buttonBgColor = color(0, 0.75, 0.75, 1)
 | 
			
		||||
def sliderColor = color(0.6, 0.8, 0.8, 1)
 | 
			
		||||
def sliderBgColor = color(0.5, 0.75, 0.75, 1)
 | 
			
		||||
def gradientColor = color(0.5, 0.75, 0.85, 0.5)
 | 
			
		||||
def tabbuttonEnabledColor = color(0.4, 0.45, 0.5, 1)
 | 
			
		||||
def solidWhiteBackground = new QuadBackgroundComponent(color(1, 1, 1, 1)) // Solid white
 | 
			
		||||
def greyBackground = color(0.8, 0.8, 0.8, 1)  // Grey background color
 | 
			
		||||
def redBorderColor = color(1, 0, 0, 1)        // Red border color
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gradient = TbtQuadBackgroundComponent.create(
 | 
			
		||||
        texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png",
 | 
			
		||||
@@ -33,14 +27,7 @@ def gradient = TbtQuadBackgroundComponent.create(
 | 
			
		||||
 | 
			
		||||
def doubleGradient = new QuadBackgroundComponent(gradientColor)
 | 
			
		||||
doubleGradient.texture = texture(name: "/com/simsilica/lemur/icons/double-gradient-128.png",
 | 
			
		||||
        generateMips: false)
 | 
			
		||||
 | 
			
		||||
def orangeBorder = TbtQuadBackgroundComponent.create(
 | 
			
		||||
        texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png", // Replace with an appropriate texture if needed
 | 
			
		||||
                generateMips: false),
 | 
			
		||||
        1, 1, 1, 126, 126,
 | 
			
		||||
        1f, false)
 | 
			
		||||
orangeBorder.color = color(1, 0.5, 0, 1) // Orange color
 | 
			
		||||
                                 generateMips: false)
 | 
			
		||||
 | 
			
		||||
selector("pp") {
 | 
			
		||||
    font = font("Interface/Fonts/Metropolis/Metropolis-Regular-32.fnt")
 | 
			
		||||
@@ -59,26 +46,10 @@ selector("header", "pp") {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
selector("container", "pp") {
 | 
			
		||||
    background = solidWhiteBackground.clone()
 | 
			
		||||
    background = gradient.clone()
 | 
			
		||||
    background.setColor(bgColor)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
selector("toolbar") {
 | 
			
		||||
    // Set the grey background
 | 
			
		||||
    background = new QuadBackgroundComponent(greyBackground)
 | 
			
		||||
 | 
			
		||||
    // Add a red border using a TbtQuadBackgroundComponent
 | 
			
		||||
    def redBorder = TbtQuadBackgroundComponent.create(
 | 
			
		||||
            texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png",
 | 
			
		||||
                    generateMips: false),
 | 
			
		||||
            1, 1, 1, 1, 1,
 | 
			
		||||
            1f, false)
 | 
			
		||||
    redBorder.color = redBorderColor
 | 
			
		||||
    background = greyBackground
 | 
			
		||||
 | 
			
		||||
    // Optional: Set padding inside the toolbar
 | 
			
		||||
    insets = new Insets3f(10, 10, 10, 10)
 | 
			
		||||
}
 | 
			
		||||
selector("slider", "pp") {
 | 
			
		||||
    background = gradient.clone()
 | 
			
		||||
    background.setColor(bgColor)
 | 
			
		||||
@@ -144,7 +115,7 @@ selector("title", "pp") {
 | 
			
		||||
    shadowOffset = vec3(2, -2, -1)
 | 
			
		||||
    background = new QuadBackgroundComponent(color(0.5, 0.75, 0.85, 1))
 | 
			
		||||
    background.texture = texture(name: "/com/simsilica/lemur/icons/double-gradient-128.png",
 | 
			
		||||
            generateMips: false)
 | 
			
		||||
                                 generateMips: false)
 | 
			
		||||
    insets = new Insets3f(2, 2, 2, 2)
 | 
			
		||||
 | 
			
		||||
    buttonCommands = stdButtonCommands
 | 
			
		||||
@@ -152,14 +123,11 @@ selector("title", "pp") {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
selector("button", "pp") {
 | 
			
		||||
    def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Orange border
 | 
			
		||||
    def innerBackground = new QuadBackgroundComponent(buttonBgColor) // Inner button background
 | 
			
		||||
    background = gradient.clone()
 | 
			
		||||
    color = buttonEnabledColor
 | 
			
		||||
    background.setColor(buttonBgColor)
 | 
			
		||||
    insets = new Insets3f(2, 2, 2, 2)
 | 
			
		||||
 | 
			
		||||
    // 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
 | 
			
		||||
    buttonCommands = stdButtonCommands
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -208,7 +176,6 @@ selector("slider.down.button", "pp") {
 | 
			
		||||
 | 
			
		||||
selector("checkbox", "pp") {
 | 
			
		||||
    color = buttonEnabledColor
 | 
			
		||||
    fontSize = 20
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
selector("rollup", "pp") {
 | 
			
		||||
@@ -225,20 +192,10 @@ selector("tabbedPanel.container", "pp") {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
selector("tab.button", "pp") {
 | 
			
		||||
    background = solidWhiteBackground.clone()
 | 
			
		||||
    background = gradient.clone()
 | 
			
		||||
    background.setColor(bgColor)
 | 
			
		||||
    color = tabbuttonEnabledColor
 | 
			
		||||
    insets = new Insets3f(4, 2, 0, 2)
 | 
			
		||||
 | 
			
		||||
    buttonCommands = stdButtonCommands
 | 
			
		||||
}
 | 
			
		||||
selector("settings-title", "pp") {
 | 
			
		||||
    fontSize = 48 // Set font size
 | 
			
		||||
    background = new QuadBackgroundComponent(color(0.4157f, 0.4235f, 0.4392f, 1.0f)) // Grey background
 | 
			
		||||
 }
 | 
			
		||||
 | 
			
		||||
selector("menu-button", "pp") {
 | 
			
		||||
    fontSize = 40 // Set font size
 | 
			
		||||
    background = new QuadBackgroundComponent(color(0.4157f, 0.4235f, 0.4392f, 1.0f)) // Grey background
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
plugins {
 | 
			
		||||
    id 'buildlogic.jme-application-conventions'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
description = 'Monopoly Client'
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    implementation project(":jme-common")
 | 
			
		||||
    implementation project(":monopoly:model")
 | 
			
		||||
    implementation project(":monopoly:server")
 | 
			
		||||
 | 
			
		||||
    implementation libs.jme3.desktop
 | 
			
		||||
 | 
			
		||||
    runtimeOnly libs.jme3.awt.dialogs
 | 
			
		||||
    runtimeOnly libs.jme3.plugins
 | 
			
		||||
    runtimeOnly libs.jme3.jogg
 | 
			
		||||
    runtimeOnly libs.jme3.testdata
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
application {
 | 
			
		||||
    mainClass = 'pp.monopoly.client.MonopolyApp'
 | 
			
		||||
    applicationName = 'monopoly'
 | 
			
		||||
}
 | 
			
		||||
@@ -1,73 +0,0 @@
 | 
			
		||||
########################################
 | 
			
		||||
## Programming project code
 | 
			
		||||
## UniBw M, 2022, 2023, 2024
 | 
			
		||||
## www.unibw.de/inf2
 | 
			
		||||
## (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
########################################
 | 
			
		||||
#
 | 
			
		||||
# Battleship client configuration
 | 
			
		||||
#
 | 
			
		||||
# Specifies the map used by the opponent in single mode.
 | 
			
		||||
# Single mode is activated if this property is set.
 | 
			
		||||
#map.opponent=maps/map2.json
 | 
			
		||||
#
 | 
			
		||||
# Specifies the map used by the player in single mode.
 | 
			
		||||
# The player must define their own map if this property is not set.
 | 
			
		||||
map.own=maps/map1.json
 | 
			
		||||
#
 | 
			
		||||
# Coordinates of the shots fired by the RobotClient in the order listed.
 | 
			
		||||
# Example:
 | 
			
		||||
#   2, 0,\
 | 
			
		||||
#   2, 1,\
 | 
			
		||||
#   2, 2,\
 | 
			
		||||
#   2, 3
 | 
			
		||||
#  defines four shots, namely at the coordinates
 | 
			
		||||
#  (x=2, y=0), (x=2, y=1), (x=2, y=2), and (x=2, y=3)
 | 
			
		||||
robot.targets=2, 0,\
 | 
			
		||||
              2, 1,\
 | 
			
		||||
              2, 2,\
 | 
			
		||||
              2, 3
 | 
			
		||||
#
 | 
			
		||||
# Delay in milliseconds between each shot fired by the RobotClient.
 | 
			
		||||
robot.delay=500
 | 
			
		||||
#
 | 
			
		||||
# The dimensions of the game map used in single mode.
 | 
			
		||||
# 'map.width' defines the number of columns, and 'map.height' defines the number of rows.
 | 
			
		||||
map.width=10
 | 
			
		||||
map.height=10
 | 
			
		||||
#
 | 
			
		||||
# The number of ships of each length available in single mode.
 | 
			
		||||
# The value is a comma-separated list where each element corresponds to the number of ships
 | 
			
		||||
# with a specific length. For example:
 | 
			
		||||
# ship.nums=4, 3, 2, 1
 | 
			
		||||
# This configuration means:
 | 
			
		||||
#   - 4 ships of length 1
 | 
			
		||||
#   - 3 ships of length 2
 | 
			
		||||
#   - 2 ships of length 3
 | 
			
		||||
#   - 1 ship of length 4
 | 
			
		||||
ship.nums=4, 3, 2, 1
 | 
			
		||||
#
 | 
			
		||||
# Screen settings
 | 
			
		||||
#
 | 
			
		||||
# Color of the text displayed at the top of the overlay.
 | 
			
		||||
# The format is (red, green, blue, alpha) where each value ranges from 0 to 1.
 | 
			
		||||
overlay.top.color=1, 1, 1, 1
 | 
			
		||||
#
 | 
			
		||||
# Application settings configuration
 | 
			
		||||
# Determines whether the settings window is shown at startup.
 | 
			
		||||
settings.show=false
 | 
			
		||||
#
 | 
			
		||||
# Specifies the width of the application window in pixels.
 | 
			
		||||
settings.resolution.width=1200
 | 
			
		||||
#
 | 
			
		||||
# Specifies the height of the application window in pixels.
 | 
			
		||||
settings.resolution.height=800
 | 
			
		||||
#
 | 
			
		||||
# Determines whether the application runs in full-screen mode.
 | 
			
		||||
settings.full-screen=false
 | 
			
		||||
#
 | 
			
		||||
# Enables or disables gamma correction to improve color accuracy.
 | 
			
		||||
settings.use-gamma-correction=true
 | 
			
		||||
#
 | 
			
		||||
# Indicates whether the statistics window is displayed during gameplay.
 | 
			
		||||
statistics.show=false
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
handlers=java.util.logging.ConsoleHandler
 | 
			
		||||
.level=INFO
 | 
			
		||||
pp.level=FINE
 | 
			
		||||
com.jme3.network.level=INFO
 | 
			
		||||
;com.jme3.util.TangentBinormalGenerator.level=SEVERE
 | 
			
		||||
java.util.logging.ConsoleHandler.level=FINER
 | 
			
		||||
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
 | 
			
		||||
;java.util.logging.SimpleFormatter.format=[%4$s %2$s] %5$s%n
 | 
			
		||||
@@ -1,122 +0,0 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import static pp.util.PreferencesUtils.getPreferences;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.prefs.Preferences;
 | 
			
		||||
 | 
			
		||||
import com.jme3.app.Application;
 | 
			
		||||
import com.jme3.app.state.AbstractAppState;
 | 
			
		||||
import com.jme3.app.state.AppStateManager;
 | 
			
		||||
import com.jme3.asset.AssetLoadException;
 | 
			
		||||
import com.jme3.asset.AssetNotFoundException;
 | 
			
		||||
import com.jme3.audio.AudioData;
 | 
			
		||||
import com.jme3.audio.AudioNode;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handles the background music beeing played. Is able to start and stop the music. Set the Volume of the Audio.
 | 
			
		||||
 */
 | 
			
		||||
public class GameMusic extends AbstractAppState{
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(GameMusic.class.getName());
 | 
			
		||||
    private static final Preferences PREFERENCES = getPreferences(GameMusic.class);
 | 
			
		||||
    private static final String ENABLED_PREF = "enabled"; //NON-NLS
 | 
			
		||||
    private static final String VOLUME_PREF = "volume"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    private AudioNode music;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if sound is enabled in the preferences.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@code true} if sound is enabled, {@code false} otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean enabledInPreferences() {
 | 
			
		||||
        return PREFERENCES.getBoolean(ENABLED_PREF, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
     * Checks if sound is enabled in the preferences.
 | 
			
		||||
     *
 | 
			
		||||
     * @return float to which the volume is set
 | 
			
		||||
     */
 | 
			
		||||
    public static float volumeInPreferences() {
 | 
			
		||||
        return PREFERENCES.getFloat(VOLUME_PREF, 0.5f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the sound effects for the game.
 | 
			
		||||
     * Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
 | 
			
		||||
     *
 | 
			
		||||
     * @param stateManager The state manager
 | 
			
		||||
     * @param app          The application
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void initialize(AppStateManager stateManager, Application app) {
 | 
			
		||||
        super.initialize(stateManager, app);
 | 
			
		||||
        music = loadSound(app, "Sound/background.ogg");
 | 
			
		||||
        setVolume(volumeInPreferences());
 | 
			
		||||
        music.setLooping(true);
 | 
			
		||||
        if (isEnabled() && music != null) {
 | 
			
		||||
            music.play();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a sound from the specified file.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app  The application
 | 
			
		||||
     * @param name The name of the sound file.
 | 
			
		||||
     * @return The loaded AudioNode.
 | 
			
		||||
     */
 | 
			
		||||
    private AudioNode loadSound(Application app, String name) {
 | 
			
		||||
        try {
 | 
			
		||||
            final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
 | 
			
		||||
            sound.setLooping(false);
 | 
			
		||||
            sound.setPositional(false);
 | 
			
		||||
            return sound;
 | 
			
		||||
        }
 | 
			
		||||
        catch (AssetLoadException | AssetNotFoundException ex) {
 | 
			
		||||
            LOGGER.log(Level.ERROR, ex.getMessage(), ex);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the enabled state of this AppState.
 | 
			
		||||
     * Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
 | 
			
		||||
     *
 | 
			
		||||
     * @param enabled {@code true} to enable the AppState, {@code false} to disable it.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setEnabled(boolean enabled) {
 | 
			
		||||
        if (isEnabled() == enabled) return;
 | 
			
		||||
 | 
			
		||||
        if (music != null) {
 | 
			
		||||
            if (enabled) {
 | 
			
		||||
                music.play();
 | 
			
		||||
            } else {
 | 
			
		||||
                music.stop();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        super.setEnabled(enabled);
 | 
			
		||||
        LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS
 | 
			
		||||
        PREFERENCES.putBoolean(ENABLED_PREF, enabled);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Toggles the game sound on or off.
 | 
			
		||||
     */
 | 
			
		||||
    public void toggleSound() {
 | 
			
		||||
        setEnabled(!isEnabled());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the volume of music
 | 
			
		||||
     * @param vol the volume to which the music should be set
 | 
			
		||||
     */
 | 
			
		||||
    public void setVolume(float vol){
 | 
			
		||||
        music.setVolume(vol);
 | 
			
		||||
        PREFERENCES.putFloat(VOLUME_PREF, vol);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,213 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.prefs.Preferences;
 | 
			
		||||
 | 
			
		||||
import com.jme3.app.Application;
 | 
			
		||||
import com.jme3.app.state.AbstractAppState;
 | 
			
		||||
import com.jme3.app.state.AppStateManager;
 | 
			
		||||
import com.jme3.asset.AssetLoadException;
 | 
			
		||||
import com.jme3.asset.AssetNotFoundException;
 | 
			
		||||
import com.jme3.audio.AudioData;
 | 
			
		||||
import com.jme3.audio.AudioNode;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.SoundEvent;
 | 
			
		||||
import static pp.util.PreferencesUtils.getPreferences;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An application state that plays sounds.
 | 
			
		||||
 */
 | 
			
		||||
public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(GameSound.class.getName());
 | 
			
		||||
    private static final Preferences PREFERENCES = getPreferences(GameSound.class);
 | 
			
		||||
    private static final String ENABLED_PREF = "enabled"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    private AudioNode passStartSound;
 | 
			
		||||
    private AudioNode eventCardSound;
 | 
			
		||||
    private AudioNode gulagSound;
 | 
			
		||||
    private AudioNode diceRollSound;
 | 
			
		||||
    private AudioNode moneyCollectSound;
 | 
			
		||||
    private AudioNode moneyLostSound;
 | 
			
		||||
    private AudioNode tradeAcceptedSound;
 | 
			
		||||
    private AudioNode tradeRejectedSound;
 | 
			
		||||
    private AudioNode winnerSound;
 | 
			
		||||
    private AudioNode looserSound;
 | 
			
		||||
    private AudioNode buttonSound;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if sound is enabled in the preferences.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@code true} if sound is enabled, {@code false} otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean enabledInPreferences() {
 | 
			
		||||
        return PREFERENCES.getBoolean(ENABLED_PREF, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Toggles the game sound on or off.
 | 
			
		||||
     */
 | 
			
		||||
    public void toggleSound() {
 | 
			
		||||
        setEnabled(!isEnabled());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the enabled state of this AppState.
 | 
			
		||||
     * Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
 | 
			
		||||
     *
 | 
			
		||||
     * @param enabled {@code true} to enable the AppState, {@code false} to disable it.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setEnabled(boolean enabled) {
 | 
			
		||||
        if (isEnabled() == enabled) return;
 | 
			
		||||
        super.setEnabled(enabled);
 | 
			
		||||
        LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS
 | 
			
		||||
        PREFERENCES.putBoolean(ENABLED_PREF, enabled);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the sound effects for the game.
 | 
			
		||||
     * Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
 | 
			
		||||
     *
 | 
			
		||||
     * @param stateManager The state manager
 | 
			
		||||
     * @param app          The application
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void initialize(AppStateManager stateManager, Application app) {
 | 
			
		||||
        super.initialize(stateManager, app);
 | 
			
		||||
        passStartSound = loadSound(app, "Sound/Effects/passStart.ogg");
 | 
			
		||||
        eventCardSound = loadSound(app, "Sound/Effects/eventCard.ogg");
 | 
			
		||||
        gulagSound = loadSound(app, "Sound/Effects/gulag.ogg");
 | 
			
		||||
        diceRollSound = loadSound(app, "Sound/Effects/diceRoll.ogg");
 | 
			
		||||
        moneyCollectSound = loadSound(app, "Sound/Effects/moneyCollect.ogg");
 | 
			
		||||
        moneyLostSound = loadSound(app, "Sound/Effects/moneyLost.ogg");
 | 
			
		||||
        tradeAcceptedSound = loadSound(app, "Sound/Effects/tradeAccepted.ogg");
 | 
			
		||||
        tradeRejectedSound = loadSound(app, "Sound/Effects/tradeRejected.ogg");
 | 
			
		||||
        winnerSound = loadSound(app, "Sound/Effects/winner.ogg");
 | 
			
		||||
        looserSound = loadSound(app, "Sound/Effects/looser.ogg");
 | 
			
		||||
        buttonSound = loadSound(app, "Sound/Effects/button.ogg");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a sound from the specified file.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app  The application
 | 
			
		||||
     * @param name The name of the sound file.
 | 
			
		||||
     * @return The loaded AudioNode.
 | 
			
		||||
     */
 | 
			
		||||
    private AudioNode loadSound(Application app, String name) {
 | 
			
		||||
        try {
 | 
			
		||||
            final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
 | 
			
		||||
            sound.setLooping(false);
 | 
			
		||||
            sound.setPositional(false);
 | 
			
		||||
            return sound;
 | 
			
		||||
        }
 | 
			
		||||
        catch (AssetLoadException | AssetNotFoundException ex) {
 | 
			
		||||
            LOGGER.log(Level.ERROR, ex.getMessage(), ex);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the passStart sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void passStart() {
 | 
			
		||||
        if (isEnabled() && passStartSound != null)
 | 
			
		||||
            passStartSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the eventCard sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void eventCard() {
 | 
			
		||||
        if (isEnabled() && eventCardSound != null)
 | 
			
		||||
            eventCardSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the gulag sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void gulag() {
 | 
			
		||||
        if (isEnabled() && gulagSound != null)
 | 
			
		||||
            gulagSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the diceRoll sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void diceRoll() {
 | 
			
		||||
        if (isEnabled() && diceRollSound != null)
 | 
			
		||||
            diceRollSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the moneyCollect sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void moneyCollect() {
 | 
			
		||||
        if (isEnabled() && moneyCollectSound != null)
 | 
			
		||||
            moneyCollectSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the moneyLost sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void moneyLost() {
 | 
			
		||||
        if (isEnabled() && moneyLostSound != null)
 | 
			
		||||
            moneyLostSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the tradeAccepted sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void tradeAccepted() {
 | 
			
		||||
        if (isEnabled() && tradeAcceptedSound != null)
 | 
			
		||||
            tradeAcceptedSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the tradeRejected sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void tradeRejected() {
 | 
			
		||||
        if (isEnabled() && tradeRejectedSound != null)
 | 
			
		||||
            tradeRejectedSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the winner sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void winner() {
 | 
			
		||||
        if (isEnabled() && winnerSound != null)
 | 
			
		||||
            winnerSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the looser sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void looser() {
 | 
			
		||||
        if (isEnabled() && looserSound != null)
 | 
			
		||||
            looserSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Plays the button sound effect.
 | 
			
		||||
     */
 | 
			
		||||
    public void button() {
 | 
			
		||||
        if (isEnabled() && buttonSound != null)
 | 
			
		||||
            buttonSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(SoundEvent event) {
 | 
			
		||||
        switch (event.sound()) {
 | 
			
		||||
            case PASS_START -> passStart();
 | 
			
		||||
            case EVENT_CARD -> eventCard();
 | 
			
		||||
            case GULAG -> eventCard();
 | 
			
		||||
            case DICE_ROLL -> eventCard();
 | 
			
		||||
            case MONEY_COLLECTED -> eventCard();
 | 
			
		||||
            case MONEY_LOST -> eventCard();
 | 
			
		||||
            case TRADE_ACCEPTED -> eventCard();
 | 
			
		||||
            case TRADE_REJECTED -> eventCard();
 | 
			
		||||
            case WINNER -> eventCard();
 | 
			
		||||
            case LOSER -> eventCard();
 | 
			
		||||
            case BUTTON -> eventCard();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,51 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import java.util.prefs.Preferences;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import static pp.util.PreferencesUtils.getPreferences;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The Menu class represents the main menu in the Battleship game application.
 | 
			
		||||
 * It extends the Dialog class and provides functionalities for loading, saving,
 | 
			
		||||
 * returning to the game, and quitting the application.
 | 
			
		||||
 */
 | 
			
		||||
class Menu extends Dialog {
 | 
			
		||||
    private static final Preferences PREFERENCES = getPreferences(Menu.class);
 | 
			
		||||
    private static final String LAST_PATH = "last.file.path";
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Menu dialog for the Battleship application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the BattleshipApp instance
 | 
			
		||||
     */
 | 
			
		||||
    public Menu(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the state of the load and save buttons based on the game logic.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * As an escape action, this method closes the menu if it is the top dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,235 +0,0 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import java.util.concurrent.ExecutorService;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
 | 
			
		||||
import com.jme3.app.SimpleApplication;
 | 
			
		||||
import com.jme3.font.BitmapFont;
 | 
			
		||||
import com.jme3.font.BitmapText;
 | 
			
		||||
import com.jme3.input.KeyInput;
 | 
			
		||||
import com.jme3.input.controls.ActionListener;
 | 
			
		||||
import com.jme3.input.controls.KeyTrigger;
 | 
			
		||||
 | 
			
		||||
import com.jme3.system.AppSettings;
 | 
			
		||||
import com.simsilica.lemur.GuiGlobals;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.style.BaseStyles;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.DialogBuilder;
 | 
			
		||||
import pp.dialog.DialogManager;
 | 
			
		||||
import pp.graphics.Draw;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.client.gui.TestWorld;
 | 
			
		||||
import pp.monopoly.game.client.ClientGameLogic;
 | 
			
		||||
import pp.monopoly.game.client.MonopolyClient;
 | 
			
		||||
import pp.monopoly.game.client.ServerConnection;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.InfoTextEvent;
 | 
			
		||||
import pp.monopoly.server.MonopolyServer;
 | 
			
		||||
 | 
			
		||||
public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener {
 | 
			
		||||
    private BitmapText topText;
 | 
			
		||||
    private final ServerConnection serverConnection;
 | 
			
		||||
    private final ClientGameLogic logic;
 | 
			
		||||
    private final MonopolyAppConfig config;
 | 
			
		||||
    private final ActionListener escapeListener = (name, isPressed, tpf) -> handleEscape(isPressed);
 | 
			
		||||
    private final DialogManager dialogManager = new DialogManager(this);
 | 
			
		||||
    private final ExecutorService executor = Executors.newCachedThreadPool();
 | 
			
		||||
    private final Draw draw;
 | 
			
		||||
    private SettingsMenu settingsMenu;
 | 
			
		||||
    private TestWorld testWorld;
 | 
			
		||||
    private boolean isSettingsMenuOpen = false;
 | 
			
		||||
    private boolean inputBlocked = false;
 | 
			
		||||
    private MonopolyServer monopolyServer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Path to the styles script for GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    private static final String STYLES_SCRIPT = "Interface/Lemur/pp-styles.groovy"; //NON-NLS
 | 
			
		||||
    /**
 | 
			
		||||
     * Path to the font resource used in the GUI.
 | 
			
		||||
     */
 | 
			
		||||
    private static final String FONT = "Interface/Fonts/Default.fnt"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        new MonopolyApp().start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MonopolyApp() {
 | 
			
		||||
        this.draw = new Draw(assetManager);
 | 
			
		||||
        config = new MonopolyAppConfig();
 | 
			
		||||
        serverConnection = new NetworkSupport(this);
 | 
			
		||||
        logic = new ClientGameLogic(serverConnection);
 | 
			
		||||
        logic.addListener(this);
 | 
			
		||||
        setShowSettings(config.getShowSettings());
 | 
			
		||||
        setSettings(makeSettings());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public MonopolyAppConfig getConfig() {
 | 
			
		||||
        return config;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ClientGameLogic getGameLogic() {
 | 
			
		||||
        return logic;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private AppSettings makeSettings() {
 | 
			
		||||
        final AppSettings settings = new AppSettings(true);
 | 
			
		||||
        settings.setTitle("Monopoly Game");
 | 
			
		||||
        settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight());
 | 
			
		||||
        settings.setFullscreen(config.fullScreen());
 | 
			
		||||
        return settings;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void simpleInitApp() {
 | 
			
		||||
        GuiGlobals.initialize(this);
 | 
			
		||||
        BaseStyles.loadStyleResources(STYLES_SCRIPT);
 | 
			
		||||
        GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS
 | 
			
		||||
        final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
 | 
			
		||||
 | 
			
		||||
        setupInput();
 | 
			
		||||
        setupGui();
 | 
			
		||||
 | 
			
		||||
        // Zeige das Startmenü
 | 
			
		||||
        StartMenu.createStartMenu(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void setupGui() {
 | 
			
		||||
        BitmapFont normalFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
 | 
			
		||||
        topText = new BitmapText(normalFont);
 | 
			
		||||
        topText.setLocalTranslation(10, settings.getHeight() - 10, 0);
 | 
			
		||||
        guiNode.attachChild(topText);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void setupInput() {
 | 
			
		||||
        inputManager.deleteMapping(INPUT_MAPPING_EXIT);
 | 
			
		||||
        inputManager.setCursorVisible(true);
 | 
			
		||||
        inputManager.addMapping("ESC", new KeyTrigger(KeyInput.KEY_ESCAPE));
 | 
			
		||||
        inputManager.addListener(escapeListener, "ESC");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void handleEscape(boolean isPressed) {
 | 
			
		||||
        if (isPressed) {
 | 
			
		||||
            if (settingsMenu != null && isSettingsMenuOpen) {
 | 
			
		||||
                // Schließe das SettingsMenu
 | 
			
		||||
                System.out.println("Schließe SettingsMenu...");
 | 
			
		||||
                settingsMenu.close();
 | 
			
		||||
                settingsMenu = null;
 | 
			
		||||
                setSettingsMenuOpen(false);
 | 
			
		||||
            } else {
 | 
			
		||||
                // Öffne das SettingsMenu
 | 
			
		||||
                System.out.println("Öffne SettingsMenu...");
 | 
			
		||||
                settingsMenu = new SettingsMenu(this);
 | 
			
		||||
                settingsMenu.open();
 | 
			
		||||
                setSettingsMenuOpen(true);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    private void blockInputs() {
 | 
			
		||||
        if (!inputBlocked) {
 | 
			
		||||
            System.out.println("Blockiere Eingaben...");
 | 
			
		||||
            inputManager.setCursorVisible(true); // Cursor sichtbar machen
 | 
			
		||||
            inputManager.clearMappings();       // Alle Mappings entfernen
 | 
			
		||||
            inputBlocked = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void unblockInputs() {
 | 
			
		||||
        if (inputBlocked) {
 | 
			
		||||
            System.out.println("Aktiviere Eingaben...");
 | 
			
		||||
            setupInput(); // Standard-Eingaben neu registrieren
 | 
			
		||||
            inputBlocked = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setInfoText(String text) {
 | 
			
		||||
        topText.setText(text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(InfoTextEvent event) {
 | 
			
		||||
        setInfoText(event.key());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void stop(boolean waitFor) {
 | 
			
		||||
        if (executor != null) executor.shutdownNow();
 | 
			
		||||
        serverConnection.disconnect();
 | 
			
		||||
        super.stop(waitFor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public DialogManager getDialogManager() {
 | 
			
		||||
        return dialogManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Draw getDraw() {
 | 
			
		||||
        return draw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ExecutorService getExecutor() {
 | 
			
		||||
        return executor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void closeApp() {
 | 
			
		||||
        stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void errorDialog(String errorMessage) {
 | 
			
		||||
        DialogBuilder.simple(dialogManager)
 | 
			
		||||
                .setTitle("Fehler")
 | 
			
		||||
                .setText(errorMessage)
 | 
			
		||||
                .setOkButton("OK")
 | 
			
		||||
                .build()
 | 
			
		||||
                .open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSettingsMenuOpen(boolean isOpen) {
 | 
			
		||||
        this.isSettingsMenuOpen = isOpen;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void simpleUpdate(float tpf) {
 | 
			
		||||
        if (testWorld != null) {
 | 
			
		||||
            testWorld.update(tpf); // Aktualisiere die Kamera in der TestWorld
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void startTestWorld() {
 | 
			
		||||
        guiNode.detachAllChildren(); // Entferne GUI
 | 
			
		||||
        testWorld = new TestWorld(this); // Erstelle eine Instanz von TestWorld
 | 
			
		||||
        testWorld.initializeScene();     // Initialisiere die Szene
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void returnToMenu() {
 | 
			
		||||
        guiNode.detachAllChildren(); // Entferne die GUI
 | 
			
		||||
        StartMenu.createStartMenu(this); // Zeige das Startmenü erneut
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Startet den Server in einem neuen Thread.
 | 
			
		||||
     */
 | 
			
		||||
    public void startServer() {
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            try {
 | 
			
		||||
                monopolyServer = new MonopolyServer(); // Erstelle Serverinstanz
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                e.printStackTrace();
 | 
			
		||||
            }
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MonopolyServer getMonopolyServer() {
 | 
			
		||||
        return monopolyServer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ServerConnection getServerConnection() {
 | 
			
		||||
        return serverConnection;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,190 +0,0 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.client.MonopolyClientConfig;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides access to the Monopoly application configuration.
 | 
			
		||||
 * Extends {@link MonopolyClientConfig} to include additional properties specific to the client,
 | 
			
		||||
 * particularly those related to screen settings and visual customization.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * <b>Note:</b> Attributes of this class should not be marked as {@code final}
 | 
			
		||||
 * to ensure proper functionality when reading from a properties file.
 | 
			
		||||
 * </p>
 | 
			
		||||
 */
 | 
			
		||||
public class MonopolyAppConfig extends MonopolyClientConfig {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts a string value found in the properties file into an object of the specified type.
 | 
			
		||||
     * Extends the superclass method to support conversion to {@link ColorRGBA}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param value      the string value to be converted
 | 
			
		||||
     * @param targetType the target type into which the value string is converted
 | 
			
		||||
     * @return the converted object of the specified type
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    protected Object convertToType(String value, Class<?> targetType) {
 | 
			
		||||
        if (targetType == ColorRGBA.class)
 | 
			
		||||
            return makeColorRGBA(value);
 | 
			
		||||
        return super.convertToType(value, targetType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts the specified string value to a corresponding {@link ColorRGBA} object.
 | 
			
		||||
     *
 | 
			
		||||
     * @param value the color in the format "red, green, blue, alpha" with all values in the range [0..1]
 | 
			
		||||
     * @return a {@link ColorRGBA} object representing the color
 | 
			
		||||
     * @throws IllegalArgumentException if the input string is not in the expected format
 | 
			
		||||
     */
 | 
			
		||||
    private static ColorRGBA makeColorRGBA(String value) {
 | 
			
		||||
        String[] split = value.split(",", -1);
 | 
			
		||||
        try {
 | 
			
		||||
            if (split.length == 4)
 | 
			
		||||
                return new ColorRGBA(Float.parseFloat(split[0]),
 | 
			
		||||
                                     Float.parseFloat(split[1]),
 | 
			
		||||
                                     Float.parseFloat(split[2]),
 | 
			
		||||
                                     Float.parseFloat(split[3]));
 | 
			
		||||
        }
 | 
			
		||||
        catch (NumberFormatException e) {
 | 
			
		||||
            // deliberately left empty
 | 
			
		||||
        }
 | 
			
		||||
        throw new IllegalArgumentException(value + " should consist of exactly 4 numbers");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The width of the game view resolution in pixels.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("settings.resolution.width") //NON-NLS
 | 
			
		||||
    private int resolutionWidth = 1200;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The height of the game view resolution in pixels.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("settings.resolution.height") //NON-NLS
 | 
			
		||||
    private int resolutionHeight = 800;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Specifies whether the game should start in full-screen mode.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("settings.full-screen") //NON-NLS
 | 
			
		||||
    private boolean fullScreen = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Specifies whether gamma correction should be enabled.
 | 
			
		||||
     * If enabled, the main framebuffer is configured for sRGB colors,
 | 
			
		||||
     * and sRGB images are linearized.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * Requires a GPU that supports GL_ARB_framebuffer_sRGB; otherwise, this setting will be ignored.
 | 
			
		||||
     * </p>
 | 
			
		||||
     */
 | 
			
		||||
    @Property("settings.use-gamma-correction") //NON-NLS
 | 
			
		||||
    private boolean useGammaCorrection = true;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Specifies whether full resolution framebuffers should be used on Retina displays.
 | 
			
		||||
     * This setting is ignored on non-Retina platforms.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("settings.use-retina-framebuffer") //NON-NLS
 | 
			
		||||
    private boolean useRetinaFrameBuffer = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Specifies whether the settings window should be shown for configuring the game.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("settings.show") //NON-NLS
 | 
			
		||||
    private boolean showSettings = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Specifies whether the JME statistics window should be shown in the lower left corner of the screen.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("statistics.show") //NON-NLS
 | 
			
		||||
    private boolean showStatistics = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The color of the top text during gameplay, represented as a {@link ColorRGBA} object.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("overlay.top.color") //NON-NLS
 | 
			
		||||
    private ColorRGBA topColor = ColorRGBA.White;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a default {@code MonopolyAppConfig} with predefined values.
 | 
			
		||||
     */
 | 
			
		||||
    public MonopolyAppConfig() {
 | 
			
		||||
        // Default constructor
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the width of the game view resolution in pixels.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the width of the game view resolution in pixels
 | 
			
		||||
     */
 | 
			
		||||
    public int getResolutionWidth() {
 | 
			
		||||
        return resolutionWidth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the height of the game view resolution in pixels.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the height of the game view resolution in pixels
 | 
			
		||||
     */
 | 
			
		||||
    public int getResolutionHeight() {
 | 
			
		||||
        return resolutionHeight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether the game should start in full-screen mode.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@code true} if the game should start in full-screen mode; {@code false} otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean fullScreen() {
 | 
			
		||||
        return fullScreen;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether gamma correction is enabled.
 | 
			
		||||
     * If enabled, the main framebuffer is configured for sRGB colors,
 | 
			
		||||
     * and sRGB images are linearized.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@code true} if gamma correction is enabled; {@code false} otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean useGammaCorrection() {
 | 
			
		||||
        return useGammaCorrection;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether full resolution framebuffers should be used on Retina displays.
 | 
			
		||||
     * This setting is ignored on non-Retina platforms.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@code true} if full resolution framebuffers should be used on Retina displays; {@code false} otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean useRetinaFrameBuffer() {
 | 
			
		||||
        return useRetinaFrameBuffer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether the settings window should be shown for configuring the game.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@code true} if the settings window should be shown; {@code false} otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getShowSettings() {
 | 
			
		||||
        return showSettings;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether the JME statistics window should be shown in the lower left corner of the screen.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@code true} if the statistics window should be shown; {@code false} otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getShowStatistics() {
 | 
			
		||||
        return showStatistics;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the color of the top text during gameplay as a {@link ColorRGBA} object.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the color of the top text during gameplay
 | 
			
		||||
     */
 | 
			
		||||
    public ColorRGBA getTopColor() {
 | 
			
		||||
        return topColor;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,84 +0,0 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.app.Application;
 | 
			
		||||
import com.jme3.app.state.AbstractAppState;
 | 
			
		||||
import com.jme3.app.state.AppStateManager;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.client.ClientGameLogic;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Abstract class representing a state in the Monopoly game.
 | 
			
		||||
 * Extends the AbstractAppState from jMonkeyEngine to manage state behavior.
 | 
			
		||||
 */
 | 
			
		||||
public abstract class MonopolyAppState extends AbstractAppState {
 | 
			
		||||
    private MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new MonopolyAppState that is initially disabled.
 | 
			
		||||
     */
 | 
			
		||||
    protected MonopolyAppState() {
 | 
			
		||||
        setEnabled(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the state manager and application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param stateManager The state manager
 | 
			
		||||
     * @param application  The application instance
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void initialize(AppStateManager stateManager, Application application) {
 | 
			
		||||
        super.initialize(stateManager, application);
 | 
			
		||||
        this.app = (MonopolyApp) application;
 | 
			
		||||
        if (isEnabled()) {
 | 
			
		||||
            enableState();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the MonopolyApp instance associated with this MonopolyAppState.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The MonopolyApp instance.
 | 
			
		||||
     */
 | 
			
		||||
    public MonopolyApp getApp() {
 | 
			
		||||
        return app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the client game logic handler.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the client game logic handler
 | 
			
		||||
     */
 | 
			
		||||
    public ClientGameLogic getGameLogic() {
 | 
			
		||||
        return app.getGameLogic();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the enabled state of the MonopolyAppState.
 | 
			
		||||
     * If the new state is the same as the current state, the method returns.
 | 
			
		||||
     *
 | 
			
		||||
     * @param enabled The new enabled state.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setEnabled(boolean enabled) {
 | 
			
		||||
        if (isEnabled() == enabled) return;
 | 
			
		||||
        super.setEnabled(enabled);
 | 
			
		||||
        if (app != null) {
 | 
			
		||||
            if (enabled) {
 | 
			
		||||
                enableState();
 | 
			
		||||
            } else {
 | 
			
		||||
                disableState();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when the state is enabled. Override to define specific behavior.
 | 
			
		||||
     */
 | 
			
		||||
    protected abstract void enableState();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when the state is disabled. Override to define specific behavior.
 | 
			
		||||
     */
 | 
			
		||||
    protected abstract void disableState();
 | 
			
		||||
}
 | 
			
		||||
@@ -1,146 +0,0 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.concurrent.ExecutionException;
 | 
			
		||||
import java.util.concurrent.Future;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.DialogBuilder;
 | 
			
		||||
import pp.dialog.SimpleDialog;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a dialog for setting up a network connection in the Monopoly game.
 | 
			
		||||
 * Allows users to specify the host and port for connecting to a game server.
 | 
			
		||||
 */
 | 
			
		||||
class NetworkDialog extends SimpleDialog {
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(NetworkDialog.class.getName());
 | 
			
		||||
    private static final String LOCALHOST = "localhost";
 | 
			
		||||
    private static final String DEFAULT_PORT = "1234";
 | 
			
		||||
    private final NetworkSupport network;
 | 
			
		||||
    private final TextField host = new TextField(LOCALHOST);
 | 
			
		||||
    private final TextField port = new TextField(DEFAULT_PORT);
 | 
			
		||||
    private String hostname;
 | 
			
		||||
    private int portNumber;
 | 
			
		||||
    private Future<Object> connectionFuture;
 | 
			
		||||
    private Dialog progressDialog;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new NetworkDialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param network The NetworkSupport instance to be used for network operations.
 | 
			
		||||
     */
 | 
			
		||||
    NetworkDialog(NetworkSupport network) {
 | 
			
		||||
        super(network.getApp().getDialogManager());
 | 
			
		||||
        this.network = network;
 | 
			
		||||
        initializeDialog();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the dialog with input fields and connection buttons.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeDialog() {
 | 
			
		||||
        final MonopolyApp app = network.getApp();
 | 
			
		||||
        Container inputContainer = new Container();
 | 
			
		||||
 | 
			
		||||
        // Titel und Eingabefelder für Host und Port
 | 
			
		||||
        inputContainer.addChild(new Label("Server-Adresse"));
 | 
			
		||||
        inputContainer.addChild(host);
 | 
			
		||||
 | 
			
		||||
        inputContainer.addChild(new Label("Port"));
 | 
			
		||||
        inputContainer.addChild(port);
 | 
			
		||||
 | 
			
		||||
        Button connectButton = inputContainer.addChild(new Button("Verbinden"));
 | 
			
		||||
        connectButton.addClickCommands(source -> connect());
 | 
			
		||||
 | 
			
		||||
        Button cancelButton = inputContainer.addChild(new Button("Abbrechen"));
 | 
			
		||||
        cancelButton.addClickCommands(source -> app.closeApp());
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(inputContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initiates the connection attempt based on the entered host and port.
 | 
			
		||||
     */
 | 
			
		||||
    private void connect() {
 | 
			
		||||
        LOGGER.log(Level.INFO, "Connecting to host={0}, port={1}", host, port);
 | 
			
		||||
        try {
 | 
			
		||||
            hostname = host.getText().trim().isEmpty() ? LOCALHOST : host.getText();
 | 
			
		||||
            portNumber = Integer.parseInt(port.getText());
 | 
			
		||||
            openProgressDialog();
 | 
			
		||||
            connectionFuture = network.getApp().getExecutor().submit(this::initNetwork);
 | 
			
		||||
        } catch (NumberFormatException e) {
 | 
			
		||||
            network.getApp().errorDialog("Port muss eine Zahl sein.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens a progress dialog while connecting.
 | 
			
		||||
     */
 | 
			
		||||
    private void openProgressDialog() {
 | 
			
		||||
        progressDialog = DialogBuilder.simple(network.getApp().getDialogManager())
 | 
			
		||||
                                      .setText("Verbinde zum Server...")
 | 
			
		||||
                                      .build();
 | 
			
		||||
        progressDialog.open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Attempts to initialize the network connection.
 | 
			
		||||
     *
 | 
			
		||||
     * @throws RuntimeException If an error occurs when creating the client.
 | 
			
		||||
     */
 | 
			
		||||
    private Object initNetwork() {
 | 
			
		||||
        try {
 | 
			
		||||
            network.initNetwork(hostname, portNumber);
 | 
			
		||||
            return null;
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the connection status and handles completion or failure.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        if (connectionFuture != null && connectionFuture.isDone()) {
 | 
			
		||||
            try {
 | 
			
		||||
                connectionFuture.get();
 | 
			
		||||
                onSuccess();
 | 
			
		||||
            } catch (ExecutionException e) {
 | 
			
		||||
                onFailure(e.getCause());
 | 
			
		||||
            } catch (InterruptedException e) {
 | 
			
		||||
                LOGGER.log(Level.WARNING, "Connection interrupted.", e);
 | 
			
		||||
                Thread.currentThread().interrupt();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a successful connection to the game server.
 | 
			
		||||
     */
 | 
			
		||||
    private void onSuccess() {
 | 
			
		||||
        connectionFuture = null;
 | 
			
		||||
        progressDialog.close();
 | 
			
		||||
        this.close();
 | 
			
		||||
        network.getApp().setInfoText("Warte auf einen Gegner...");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a failed connection attempt.
 | 
			
		||||
     *
 | 
			
		||||
     * @param e The cause of the failure.
 | 
			
		||||
     */
 | 
			
		||||
    private void onFailure(Throwable e) {
 | 
			
		||||
        connectionFuture = null;
 | 
			
		||||
        progressDialog.close();
 | 
			
		||||
        network.getApp().errorDialog("Verbindung zum Server fehlgeschlagen.");
 | 
			
		||||
        network.getApp().setInfoText(e.getLocalizedMessage());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -1,144 +0,0 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.Client;
 | 
			
		||||
import com.jme3.network.ClientStateListener;
 | 
			
		||||
import com.jme3.network.Message;
 | 
			
		||||
import com.jme3.network.MessageListener;
 | 
			
		||||
import com.jme3.network.Network;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.client.ServerConnection;
 | 
			
		||||
import pp.monopoly.message.client.ClientMessage;
 | 
			
		||||
import pp.monopoly.message.server.ServerMessage;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Manages the network connection for the Monopoly application.
 | 
			
		||||
 * Handles connecting to and disconnecting from the server, and sending messages.
 | 
			
		||||
 */
 | 
			
		||||
class NetworkSupport implements MessageListener<Client>, ClientStateListener, ServerConnection {
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(NetworkSupport.class.getName());
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private Client client;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a NetworkSupport instance for the Monopoly application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The Monopoly application instance.
 | 
			
		||||
     */
 | 
			
		||||
    public NetworkSupport(MonopolyApp app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the Monopoly application instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Monopoly application instance
 | 
			
		||||
     */
 | 
			
		||||
    MonopolyApp getApp() {
 | 
			
		||||
        return app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if there is a connection to the game server.
 | 
			
		||||
     *
 | 
			
		||||
     * @return true if there is a connection to the game server, false otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isConnected() {
 | 
			
		||||
        return client != null && client.isConnected();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Attempts to join the game if there is no connection yet.
 | 
			
		||||
     * Opens a dialog for the user to enter the host and port information.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void connect() {
 | 
			
		||||
        if (client == null) {
 | 
			
		||||
            new NetworkDialog(this).open();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the client connection.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void disconnect() {
 | 
			
		||||
        if (client == null) return;
 | 
			
		||||
        client.close();
 | 
			
		||||
        client = null;
 | 
			
		||||
        LOGGER.log(Level.INFO, "Client connection closed.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the network connection.
 | 
			
		||||
     *
 | 
			
		||||
     * @param host The server's address.
 | 
			
		||||
     * @param port The server's port.
 | 
			
		||||
     * @throws IOException If an I/O error occurs when creating the client.
 | 
			
		||||
     */
 | 
			
		||||
    void initNetwork(String host, int port) throws IOException {
 | 
			
		||||
        if (client != null) {
 | 
			
		||||
            throw new IllegalStateException("Already connected to the game server.");
 | 
			
		||||
        }
 | 
			
		||||
        client = Network.connectToServer(host, port);
 | 
			
		||||
        client.start();
 | 
			
		||||
        client.addMessageListener(this);
 | 
			
		||||
        client.addClientStateListener(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when a message is received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param client  The client instance that received the message.
 | 
			
		||||
     * @param message The message received from the server.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void messageReceived(Client client, Message message) {
 | 
			
		||||
        LOGGER.log(Level.INFO, "Message received from server: {0}", message);
 | 
			
		||||
        if (message instanceof ServerMessage serverMessage) {
 | 
			
		||||
            app.enqueue(() -> serverMessage.accept(app.getGameLogic()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when the client has successfully connected to the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param client The client that connected to the server.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void clientConnected(Client client) {
 | 
			
		||||
        LOGGER.log(Level.INFO, "Successfully connected to server: {0}", client);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when the client is disconnected from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param client         The client that was disconnected.
 | 
			
		||||
     * @param disconnectInfo Information about the disconnection.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void clientDisconnected(Client client, DisconnectInfo disconnectInfo) {
 | 
			
		||||
        LOGGER.log(Level.INFO, "Disconnected from server: {0}", disconnectInfo);
 | 
			
		||||
        this.client = null;
 | 
			
		||||
        app.enqueue(() -> app.setInfoText("Verbindung zum Server verloren."));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends the specified message to the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param message The message to be sent to the server.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void send(ClientMessage message) {
 | 
			
		||||
        LOGGER.log(Level.INFO, "Sending message to server: {0}", message);
 | 
			
		||||
        if (client == null) {
 | 
			
		||||
            app.errorDialog("Verbindung zum Server verloren.");
 | 
			
		||||
        } else {
 | 
			
		||||
            client.send(message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,181 +0,0 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.HAlignment;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.gui.CreateGameMenu;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Constructs the startup menu dialog for the Monopoly application.
 | 
			
		||||
import pp.monopoly.client.gui.GameMenu;
 | 
			
		||||
 */
 | 
			
		||||
public class StartMenu extends Dialog {
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private Container logoContainer;
 | 
			
		||||
    private Container unibwLogoContainer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Startup Menu dialog for the Monopoly application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the MonopolyApp instance
 | 
			
		||||
     */
 | 
			
		||||
    public StartMenu(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates and displays the Start Menu with buttons for starting the game,
 | 
			
		||||
     * opening settings, and quitting the application.
 | 
			
		||||
     */
 | 
			
		||||
    public static void createStartMenu(MonopolyApp app) {
 | 
			
		||||
        int screenWidth = app.getContext().getSettings().getWidth();
 | 
			
		||||
        int screenHeight = app.getContext().getSettings().getHeight();
 | 
			
		||||
 | 
			
		||||
        // Set up the background image
 | 
			
		||||
        Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
 | 
			
		||||
        Quad quad = new Quad(screenWidth, screenHeight);
 | 
			
		||||
        Geometry background = new Geometry("Background", quad);
 | 
			
		||||
        Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        backgroundMaterial.setTexture("ColorMap", backgroundImage);
 | 
			
		||||
        background.setMaterial(backgroundMaterial);
 | 
			
		||||
        background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
 | 
			
		||||
        createMonopolyLogo(app);
 | 
			
		||||
        createUnibwLogo(app);
 | 
			
		||||
 | 
			
		||||
        // Center container for title and play button
 | 
			
		||||
        Container centerMenu = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
 | 
			
		||||
        Button startButton = new Button("Spielen");
 | 
			
		||||
        startButton.setPreferredSize(new Vector3f(190, 60, 0)); // Increase button size (width, height)
 | 
			
		||||
        startButton.setFontSize(40); // Set the font size for the button text
 | 
			
		||||
        startButton.setTextHAlignment(HAlignment.Center); // Center the text horizontally
 | 
			
		||||
 | 
			
		||||
        startButton.addClickCommands(source -> startGame(app));
 | 
			
		||||
        centerMenu.addChild(startButton);
 | 
			
		||||
 | 
			
		||||
        // Position the center container in the middle of the screen
 | 
			
		||||
        centerMenu.setLocalTranslation(new Vector3f(screenWidth / 2f - centerMenu.getPreferredSize().x / 2f,
 | 
			
		||||
                                                    screenHeight / 2f - 280 + centerMenu.getPreferredSize().y / 2f,
 | 
			
		||||
                                                    0));
 | 
			
		||||
        app.getGuiNode().attachChild(centerMenu);
 | 
			
		||||
 | 
			
		||||
        // Lower-left container for "Spiel beenden" button
 | 
			
		||||
        Container lowerLeftMenu = new Container();
 | 
			
		||||
        lowerLeftMenu.setLocalTranslation(new Vector3f(100, 90, 0));
 | 
			
		||||
        Button quitButton = new Button("Spiel beenden");
 | 
			
		||||
        quitButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height)
 | 
			
		||||
        quitButton.setFontSize(18);
 | 
			
		||||
        quitButton.addClickCommands(source -> quitGame());
 | 
			
		||||
        lowerLeftMenu.addChild(quitButton);
 | 
			
		||||
        app.getGuiNode().attachChild(lowerLeftMenu);
 | 
			
		||||
 | 
			
		||||
        // Lower-right container for "Einstellungen" button
 | 
			
		||||
        Container lowerRightMenu = new Container();
 | 
			
		||||
        lowerRightMenu.setLocalTranslation(new Vector3f(screenWidth - 200, 90, 0));
 | 
			
		||||
        Button settingsButton = new Button("Einstellungen");
 | 
			
		||||
        settingsButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height)
 | 
			
		||||
        settingsButton.setFontSize(18); // Increase the font size for the text
 | 
			
		||||
        settingsButton.addClickCommands(source -> openSettings(app));
 | 
			
		||||
        lowerRightMenu.addChild(settingsButton);
 | 
			
		||||
        app.getGuiNode().attachChild(lowerRightMenu);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates and positions the Monopoly logo container in the center of the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private static void createMonopolyLogo(MonopolyApp app) {
 | 
			
		||||
        int screenWidth = app.getContext().getSettings().getWidth();
 | 
			
		||||
        int screenHeight = app.getContext().getSettings().getHeight();
 | 
			
		||||
 | 
			
		||||
        // Load the Monopoly logo as a texture
 | 
			
		||||
        Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopoly.png");
 | 
			
		||||
 | 
			
		||||
        // Create a container for the logo
 | 
			
		||||
        Container logoContainer = new Container();
 | 
			
		||||
        QuadBackgroundComponent logoBackground = new QuadBackgroundComponent(logoTexture);
 | 
			
		||||
        logoContainer.setBackground(logoBackground);
 | 
			
		||||
 | 
			
		||||
        // Set the size of the container to fit the logo
 | 
			
		||||
        float logoWidth = 512;  // Adjust these values based on the logo dimensions
 | 
			
		||||
        float logoHeight = 128; // Adjust these values based on the logo dimensions
 | 
			
		||||
        logoContainer.setPreferredSize(new Vector3f(logoWidth, logoHeight, 0));
 | 
			
		||||
 | 
			
		||||
        // Position the container at the center of the screen
 | 
			
		||||
        logoContainer.setLocalTranslation(new Vector3f(
 | 
			
		||||
                screenWidth / 2f - logoWidth / 2f,
 | 
			
		||||
                screenHeight / 2f + 200, // Adjust this value for vertical position
 | 
			
		||||
                0
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        // Attach the container to the GUI node
 | 
			
		||||
        app.getGuiNode().attachChild(logoContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates and positions the Unibw logo container in the center of the screen.
 | 
			
		||||
     */
 | 
			
		||||
    private static void createUnibwLogo(MonopolyApp app) {
 | 
			
		||||
        int screenWidth = app.getContext().getSettings().getWidth();
 | 
			
		||||
        int screenHeight = app.getContext().getSettings().getHeight();
 | 
			
		||||
 | 
			
		||||
        // Load the Unibw logo as a texture
 | 
			
		||||
        Texture unibwTexture = app.getAssetManager().loadTexture("Pictures/logo-unibw.png");
 | 
			
		||||
 | 
			
		||||
        // Create a container for the Unibw logo
 | 
			
		||||
        Container unibwContainer = new Container();
 | 
			
		||||
        QuadBackgroundComponent unibwBackground = new QuadBackgroundComponent(unibwTexture);
 | 
			
		||||
        unibwContainer.setBackground(unibwBackground);
 | 
			
		||||
 | 
			
		||||
        // Set the size of the container to fit the Unibw logo
 | 
			
		||||
        float unibwWidth = 512;  // Adjust these values based on the logo dimensions
 | 
			
		||||
        float unibwHeight = 128; // Adjust these values based on the logo dimensions
 | 
			
		||||
        unibwContainer.setPreferredSize(new Vector3f(unibwWidth, unibwHeight, 0));
 | 
			
		||||
 | 
			
		||||
        // Position the container slightly below the Monopoly logo
 | 
			
		||||
        unibwContainer.setLocalTranslation(new Vector3f(
 | 
			
		||||
                screenWidth / 2f - unibwWidth / 2f,
 | 
			
		||||
                screenHeight / 2f + 100, // Adjust this value for vertical position
 | 
			
		||||
                0
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        // Attach the container to the GUI node
 | 
			
		||||
        app.getGuiNode().attachChild(unibwContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts the game by transitioning to the CreateGameMenu.
 | 
			
		||||
     */
 | 
			
		||||
    private static void startGame(MonopolyApp app) {
 | 
			
		||||
        app.getGuiNode().detachAllChildren();
 | 
			
		||||
        new CreateGameMenu(app);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu.
 | 
			
		||||
     */
 | 
			
		||||
    private static void openSettings(MonopolyApp app) {
 | 
			
		||||
        app.getGuiNode().detachAllChildren();
 | 
			
		||||
        new SettingsMenu(app);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Quits the game application.
 | 
			
		||||
     */
 | 
			
		||||
    private static void quitGame() {
 | 
			
		||||
        System.exit(0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,74 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.scene.Node;
 | 
			
		||||
import com.jme3.scene.Spatial;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.model.Item;
 | 
			
		||||
import pp.monopoly.model.Visitor;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.ItemAddedEvent;
 | 
			
		||||
import pp.monopoly.notification.ItemRemovedEvent;
 | 
			
		||||
import pp.view.ModelViewSynchronizer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Abstract base class for synchronizing the visual representation of a {@link Board} with its model state.
 | 
			
		||||
 * This class handles the addition and removal of items from the map, ensuring that changes in the model
 | 
			
		||||
 * are accurately reflected in the view.
 | 
			
		||||
 */
 | 
			
		||||
abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
 | 
			
		||||
    protected final Board board;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new BoardSynchronizer.
 | 
			
		||||
     *
 | 
			
		||||
     * @param board the game board to synchronize
 | 
			
		||||
     * @param root  the root node to which the view representations of the board items are attached
 | 
			
		||||
     */
 | 
			
		||||
    protected BoardSynchronizer(Board board, Node root) {
 | 
			
		||||
        super(root);
 | 
			
		||||
        this.board = board;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Translates a model item into its corresponding visual representation.
 | 
			
		||||
     *
 | 
			
		||||
     * @param item the item from the model to be translated
 | 
			
		||||
     * @return the visual representation of the item as a {@link Spatial}
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    protected Spatial translate(Item item) {
 | 
			
		||||
        return item.accept(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds the existing items from the board to the view during initialization.
 | 
			
		||||
     */
 | 
			
		||||
    protected void addExisting() {
 | 
			
		||||
        board.getItems().forEach(this::add);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the event when an item is removed from the board.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event the event indicating that an item has been removed from the board
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(ItemRemovedEvent event) {
 | 
			
		||||
        if (board == event.getBoard()) {
 | 
			
		||||
            delete(event.getItem());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the event when an item is added to the board.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event the event indicating that an item has been added to the board
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(ItemAddedEvent event) {
 | 
			
		||||
        if (board == event.getBoard()) {
 | 
			
		||||
            add(event.getItem());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,59 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.FastMath;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.renderer.Camera;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Steuert die Kamerabewegung in der Szene.
 | 
			
		||||
 */
 | 
			
		||||
public class CameraController {
 | 
			
		||||
    private final Camera camera;
 | 
			
		||||
    private final Vector3f center; // Fokuspunkt der Kamera
 | 
			
		||||
    private final float radius;    // Radius der Kreisbewegung
 | 
			
		||||
    private final float height;    // Höhe der Kamera über dem Spielfeld
 | 
			
		||||
    private final float speed;     // Geschwindigkeit der Kamerabewegung
 | 
			
		||||
    private float angle;           // Aktueller Winkel in der Kreisbewegung
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Konstruktor für den CameraController.
 | 
			
		||||
     *
 | 
			
		||||
     * @param camera Die Kamera, die gesteuert werden soll
 | 
			
		||||
     * @param center Der Mittelpunkt der Kreisbewegung (Fokuspunkt)
 | 
			
		||||
     * @param radius Der Radius der Kreisbewegung
 | 
			
		||||
     * @param height Die Höhe der Kamera über dem Fokuspunkt
 | 
			
		||||
     * @param speed  Die Geschwindigkeit der Kamerabewegung
 | 
			
		||||
     */
 | 
			
		||||
    public CameraController(Camera camera, Vector3f center, float radius, float height, float speed) {
 | 
			
		||||
        this.camera = camera;
 | 
			
		||||
        this.center = center;
 | 
			
		||||
        this.radius = radius;
 | 
			
		||||
        this.height = height;
 | 
			
		||||
        this.speed = speed;
 | 
			
		||||
        this.angle = 0; // Starte bei Winkel 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Aktualisiert die Kameraposition und -ausrichtung.
 | 
			
		||||
     *
 | 
			
		||||
     * @param tpf Zeit pro Frame
 | 
			
		||||
     */
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        // Aktualisiere den Winkel basierend auf der Geschwindigkeit
 | 
			
		||||
        angle += speed * tpf;
 | 
			
		||||
        if (angle >= FastMath.TWO_PI) {
 | 
			
		||||
            angle -= FastMath.TWO_PI; // Winkel zurücksetzen, um Überläufe zu vermeiden
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Berechne die neue Position der Kamera
 | 
			
		||||
        float x = center.x + radius * FastMath.cos(angle);
 | 
			
		||||
        float z = center.z + radius * FastMath.sin(angle);
 | 
			
		||||
        float y = center.y + height;
 | 
			
		||||
 | 
			
		||||
        // Setze die Kameraposition
 | 
			
		||||
        camera.setLocation(new Vector3f(x, y, z));
 | 
			
		||||
 | 
			
		||||
        // Lasse die Kamera auf den Fokuspunkt blicken
 | 
			
		||||
        camera.lookAt(center, Vector3f.UNIT_Y);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,132 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import javax.swing.JOptionPane;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.network.Client;
 | 
			
		||||
import com.jme3.network.Network;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.StartMenu;
 | 
			
		||||
import pp.monopoly.server.MonopolyServer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * CreateGameMenu class represents the menu for creating a new game.
 | 
			
		||||
 */
 | 
			
		||||
public class CreateGameMenu {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Container menuContainer;
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
    private Label serverStatusLabel;
 | 
			
		||||
 | 
			
		||||
    public CreateGameMenu(MonopolyApp app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Hintergrundbild laden und hinzufügen
 | 
			
		||||
        addBackgroundImage();
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für das Menü
 | 
			
		||||
        menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        menuContainer.setPreferredSize(new Vector3f(600, 400, 0)); // Feste Größe des Containers
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label title = menuContainer.addChild(new Label("Neues Spiel"));
 | 
			
		||||
        title.setFontSize(48);
 | 
			
		||||
 | 
			
		||||
        // Eingabefelder-Container
 | 
			
		||||
        Container inputContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X)));
 | 
			
		||||
        inputContainer.setPreferredSize(new Vector3f(200, 150, 0)); // Eingabefelder nicht ganz so breit
 | 
			
		||||
        inputContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand
 | 
			
		||||
 | 
			
		||||
        inputContainer.addChild(new Label("Server-Adresse:"));
 | 
			
		||||
        TextField playerNameField = inputContainer.addChild(new TextField("localhost"));
 | 
			
		||||
        playerNameField.setPreferredWidth(400); // Breite des Textfelds
 | 
			
		||||
 | 
			
		||||
        inputContainer.addChild(new Label("Port:"));
 | 
			
		||||
        TextField serverAddressField = inputContainer.addChild(new TextField("42069"));
 | 
			
		||||
        serverAddressField.setPreferredWidth(400); // Breite des Textfelds
 | 
			
		||||
 | 
			
		||||
        // Button-Container
 | 
			
		||||
        Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
 | 
			
		||||
        buttonContainer.setPreferredSize(new Vector3f(400, 50, 0));
 | 
			
		||||
        buttonContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand
 | 
			
		||||
 | 
			
		||||
        // "Abbrechen"-Button
 | 
			
		||||
        Button cancelButton = buttonContainer.addChild(new Button("Abbrechen"));
 | 
			
		||||
        cancelButton.setPreferredSize(new Vector3f(120, 40, 0));
 | 
			
		||||
        cancelButton.addClickCommands(source -> goBackToStartMenu());
 | 
			
		||||
 | 
			
		||||
        // "Selber hosten"-Button
 | 
			
		||||
        Button hostButton = buttonContainer.addChild(new Button("Selber hosten"));
 | 
			
		||||
        hostButton.setPreferredSize(new Vector3f(120, 40, 0));
 | 
			
		||||
        hostButton.addClickCommands(source -> startServer());
 | 
			
		||||
 | 
			
		||||
        // "Beitreten"-Button (vorerst funktionslos)
 | 
			
		||||
        Button joinButton = buttonContainer.addChild(new Button("Beitreten"));
 | 
			
		||||
        joinButton.setPreferredSize(new Vector3f(120, 40, 0));
 | 
			
		||||
 | 
			
		||||
        // Serverstatus-Label
 | 
			
		||||
        serverStatusLabel = menuContainer.addChild(new Label("Serverstatus: Noch nicht gestartet"));
 | 
			
		||||
        serverStatusLabel.setFontSize(24);
 | 
			
		||||
 | 
			
		||||
        // Zentrierung des Containers
 | 
			
		||||
        menuContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - menuContainer.getPreferredSize().x) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + menuContainer.getPreferredSize().y) / 2,
 | 
			
		||||
                1  // Höhere Z-Ebene für den Vordergrund
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getInputManager().addMapping("OpenTestWorld", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_T));
 | 
			
		||||
        app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onAction(String name, boolean isPressed, float tpf) {
 | 
			
		||||
                if (name.equals("OpenTestWorld") && isPressed) {
 | 
			
		||||
                    app.startTestWorld(); // Öffnet die TestWorld
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }, "OpenTestWorld");
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(menuContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu.
 | 
			
		||||
     */
 | 
			
		||||
    private void addBackgroundImage() {
 | 
			
		||||
        Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        background = new Geometry("Background", quad);
 | 
			
		||||
        Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        backgroundMaterial.setTexture("ColorMap", backgroundImage);
 | 
			
		||||
        background.setMaterial(backgroundMaterial);
 | 
			
		||||
        background.setLocalTranslation(0, 0, -1); // Hintergrundebene
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird.
 | 
			
		||||
     */
 | 
			
		||||
    private void goBackToStartMenu() {
 | 
			
		||||
        app.getGuiNode().detachChild(menuContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
 | 
			
		||||
        StartMenu.createStartMenu(app);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void startServer() {
 | 
			
		||||
        app.start();
 | 
			
		||||
        app.getServerConnection().connect();
 | 
			
		||||
        JOptionPane.showMessageDialog(null, "Server Started");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,124 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.Node;
 | 
			
		||||
import com.jme3.scene.Spatial;
 | 
			
		||||
import com.jme3.scene.shape.Box;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.game.server.PlayerColor;
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.model.Rotation;
 | 
			
		||||
import static pp.util.FloatMath.HALF_PI;
 | 
			
		||||
import static pp.util.FloatMath.PI;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The {@code GameBoardSynchronizer} class is responsible for synchronizing the graphical
 | 
			
		||||
 * representation of the ships and shots on the sea map with the underlying data model.
 | 
			
		||||
 * It extends the {@link BoardSynchronizer} to provide specific synchronization
 | 
			
		||||
 * logic for the sea map.
 | 
			
		||||
 */
 | 
			
		||||
class GameBoardSynchronizer extends BoardSynchronizer {
 | 
			
		||||
    private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
 | 
			
		||||
    private static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md";
 | 
			
		||||
    private static final String COLOR = "Color"; //NON-NLS
 | 
			
		||||
    private static final String FIGURE = "figure"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final ParticleEffectFactory particleFactory;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a {@code GameBoardSynchronizer} object with the specified application, root node, and ship map.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app  the Battleship application
 | 
			
		||||
     * @param root the root node to which graphical elements will be attached
 | 
			
		||||
     * @param map  the ship map containing the ships and shots
 | 
			
		||||
     */
 | 
			
		||||
    public GameBoardSynchronizer(MonopolyApp app, Node root, Board board) {
 | 
			
		||||
        super(board, root);
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        this.particleFactory = new ParticleEffectFactory(app);
 | 
			
		||||
        addExisting();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Visits a {@link Battleship} and creates a graphical representation of it.
 | 
			
		||||
     * The representation is either a 3D model or a simple box depending on the
 | 
			
		||||
     * type of battleship.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ship the battleship to be represented
 | 
			
		||||
     * @return the node containing the graphical representation of the battleship
 | 
			
		||||
     */
 | 
			
		||||
    public Spatial visit(Figure figure) {
 | 
			
		||||
        final Node node = new Node(FIGURE);
 | 
			
		||||
        node.attachChild(createBox(figure));
 | 
			
		||||
        // compute the center of the ship in world coordinates
 | 
			
		||||
        final float x = 1;
 | 
			
		||||
        final float z = 1;
 | 
			
		||||
        node.setLocalTranslation(x, 0f, z);
 | 
			
		||||
        return node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a simple box to represent a battleship that is not of the "King George V" type.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ship the battleship to be represented
 | 
			
		||||
     * @return the geometry representing the battleship as a box
 | 
			
		||||
     */
 | 
			
		||||
    private Spatial createBox(Figure figure) {
 | 
			
		||||
        final Box box = new Box(0.5f * (figure.getMaxY() - figure.getMinY()) + 0.3f,
 | 
			
		||||
                                0.3f,
 | 
			
		||||
                                0.5f * (figure.getMaxX() - figure.getMinX()) + 0.3f);
 | 
			
		||||
        final Geometry geometry = new Geometry(FIGURE, box);
 | 
			
		||||
        geometry.setMaterial(createColoredMaterial(PlayerColor.PINK.getColor()));
 | 
			
		||||
        geometry.setShadowMode(ShadowMode.CastAndReceive);
 | 
			
		||||
 | 
			
		||||
        return geometry;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new {@link Material} with the specified color.
 | 
			
		||||
     * If the color includes transparency (i.e., alpha value less than 1),
 | 
			
		||||
     * the material's render state is set to use alpha blending, allowing for
 | 
			
		||||
     * semi-transparent rendering.
 | 
			
		||||
     *
 | 
			
		||||
     * @param color the {@link ColorRGBA} to be applied to the material. If the alpha value
 | 
			
		||||
     *              of the color is less than 1, the material will support transparency.
 | 
			
		||||
     * @return a {@link Material} instance configured with the specified color and,
 | 
			
		||||
     * if necessary, alpha blending enabled.
 | 
			
		||||
     */
 | 
			
		||||
    private Material createColoredMaterial(ColorRGBA color) {
 | 
			
		||||
        final Material material = new Material(app.getAssetManager(), UNSHADED);
 | 
			
		||||
        if (color.getAlpha() < 1f)
 | 
			
		||||
            material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        material.setColor(COLOR, color);
 | 
			
		||||
        return material;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculates the rotation angle for the specified rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @param rot the rotation of the battleship
 | 
			
		||||
     * @return the rotation angle in radians
 | 
			
		||||
     */
 | 
			
		||||
    private static float calculateRotationAngle(Rotation rot) {
 | 
			
		||||
        return switch (rot) {
 | 
			
		||||
            case RIGHT -> HALF_PI;
 | 
			
		||||
            case DOWN -> 0f;
 | 
			
		||||
            case LEFT -> -HALF_PI;
 | 
			
		||||
            case UP -> PI;
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,51 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
public class GameMenu extends Dialog {
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the SettingsMenu dialog for the Monopoly application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the MonopolyApp instance
 | 
			
		||||
     */
 | 
			
		||||
    public GameMenu(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Add a title label for Settings
 | 
			
		||||
        Label settingsTitle = new Label("Einstellungen", new ElementId("settings-title"));
 | 
			
		||||
        settingsTitle.setFontSize(48);  // Set font size for the title
 | 
			
		||||
        settingsTitle.setColor(ColorRGBA.White);
 | 
			
		||||
 | 
			
		||||
        // Add any settings-related components here, such as volume control, toggles, etc.
 | 
			
		||||
 | 
			
		||||
        // Add a back button to return to StartMenu
 | 
			
		||||
        Button backButton = new Button("Zurück", new ElementId("menu-button"));
 | 
			
		||||
        backButton.setColor(ColorRGBA.White);
 | 
			
		||||
        backButton.setFontSize(24);
 | 
			
		||||
        backButton.addClickCommands(source -> returnToStartMenu());
 | 
			
		||||
 | 
			
		||||
        // Add components to this dialog
 | 
			
		||||
        addChild(settingsTitle);
 | 
			
		||||
        addChild(backButton);
 | 
			
		||||
 | 
			
		||||
        // You can add more settings components here, like checkboxes or sliders.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns to the StartMenu when the back button is clicked.
 | 
			
		||||
     */
 | 
			
		||||
    private void returnToStartMenu() {
 | 
			
		||||
        app.getDialogManager().close(this); // Close the current settings dialog
 | 
			
		||||
        //TODO return zum Ausgangsmenü
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,75 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.Node;
 | 
			
		||||
import com.jme3.scene.Spatial.CullHint;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the visual view of a {@link Board}, used to display the map structure and elements.
 | 
			
		||||
 * This class handles the graphical representation of the board, including background setup and grid lines.
 | 
			
		||||
 */
 | 
			
		||||
class MapView {
 | 
			
		||||
    private static final float FIELD_SIZE = 40f;
 | 
			
		||||
    private static final float BACKGROUND_DEPTH = -4f;
 | 
			
		||||
    private static final ColorRGBA BACKGROUND_COLOR = new ColorRGBA(0, 0.05f, 0.05f, 0.5f);
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Node mapNode = new Node("map");
 | 
			
		||||
    private final Board board;
 | 
			
		||||
    private final MapViewSynchronizer synchronizer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new MapView for a given {@link Board} and {@link MonopolyApp}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param board the board to visualize
 | 
			
		||||
     * @param app   the main application instance
 | 
			
		||||
     */
 | 
			
		||||
    MapView(Board board, MonopolyApp app) {
 | 
			
		||||
        this.board = board;
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        this.synchronizer = new MapViewSynchronizer(this);
 | 
			
		||||
        setupBackground();
 | 
			
		||||
        app.getGameLogic().addListener(synchronizer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Unregisters the {@link MapViewSynchronizer} from listening to board changes.
 | 
			
		||||
     */
 | 
			
		||||
    void unregister() {
 | 
			
		||||
        app.getGameLogic().removeListener(synchronizer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up the background of the map view using a quad geometry.
 | 
			
		||||
     */
 | 
			
		||||
    private void setupBackground() {
 | 
			
		||||
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        mat.setColor("Color", BACKGROUND_COLOR);
 | 
			
		||||
        mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        Geometry background = new Geometry("MapBackground", new Quad(board.getWidth() * FIELD_SIZE, board.getHeight() * FIELD_SIZE));
 | 
			
		||||
        background.setMaterial(mat);
 | 
			
		||||
        background.setLocalTranslation(0f, 1f, BACKGROUND_DEPTH);
 | 
			
		||||
        background.setCullHint(CullHint.Never);
 | 
			
		||||
        mapNode.attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the root node containing all visual elements in this map view.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the root node for the map view
 | 
			
		||||
     */
 | 
			
		||||
    public Node getNode() {
 | 
			
		||||
        return mapNode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Board getBoard() {
 | 
			
		||||
        return board;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,45 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.scene.Spatial;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Synchronizes the visual representation of the board with the game model.
 | 
			
		||||
 * Handles updates for items on the board.
 | 
			
		||||
 */
 | 
			
		||||
class MapViewSynchronizer extends BoardSynchronizer {
 | 
			
		||||
    private final MapView view;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new MapViewSynchronizer for the given MapView.
 | 
			
		||||
     *
 | 
			
		||||
     * @param view the MapView to synchronize with the game model
 | 
			
		||||
     */
 | 
			
		||||
    public MapViewSynchronizer(MapView view) {
 | 
			
		||||
        super(view.getBoard(), view.getNode());
 | 
			
		||||
        this.view = view;
 | 
			
		||||
        addExisting();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Enables the state by performing initial setup, such as adding any items to the view.
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    protected void enableState() {
 | 
			
		||||
        // Platz für zusätzliche Initialisierungen
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Disables the state by clearing the view.
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    protected void disableState() {
 | 
			
		||||
        view.getNode().detachAllChildren(); // Entfernt alle visuellen Elemente vom Knoten
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    public Spatial visit(Figure figure) {
 | 
			
		||||
        return figure.accept(this);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.effect.ParticleMesh.Type;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Factory class responsible for creating particle effects used in the game.
 | 
			
		||||
 * This centralizes the creation of various types of particle emitters.
 | 
			
		||||
 */
 | 
			
		||||
public class ParticleEffectFactory {
 | 
			
		||||
    private static final int COUNT_FACTOR = 1;
 | 
			
		||||
    private static final float COUNT_FACTOR_F = 1f;
 | 
			
		||||
    private static final boolean POINT_SPRITE = true;
 | 
			
		||||
    private static final Type EMITTER_TYPE = POINT_SPRITE ? Type.Point : Type.Triangle;
 | 
			
		||||
    
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    ParticleEffectFactory(MonopolyApp app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,89 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import java.awt.BorderLayout;
 | 
			
		||||
import java.awt.FlowLayout;
 | 
			
		||||
 | 
			
		||||
import javax.swing.JButton;
 | 
			
		||||
import javax.swing.JFrame;
 | 
			
		||||
import javax.swing.JLabel;
 | 
			
		||||
import javax.swing.JOptionPane;
 | 
			
		||||
import javax.swing.JPanel;
 | 
			
		||||
import javax.swing.JTextField;
 | 
			
		||||
import javax.swing.SwingUtilities;
 | 
			
		||||
 | 
			
		||||
public class ServerScreen {
 | 
			
		||||
    private JFrame frame;
 | 
			
		||||
    private JTextField inputField;
 | 
			
		||||
    private JLabel label;
 | 
			
		||||
    private JButton startButton;
 | 
			
		||||
    private JButton stopButton;
 | 
			
		||||
 | 
			
		||||
    public ServerScreen() {
 | 
			
		||||
        initialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void initialize() {
 | 
			
		||||
        // Erstelle das Hauptfenster
 | 
			
		||||
        frame = new JFrame("Server Placeholder"); // Setze den Titel
 | 
			
		||||
        frame.setSize(400, 200);
 | 
			
		||||
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 | 
			
		||||
        frame.setLayout(new BorderLayout());
 | 
			
		||||
 | 
			
		||||
        // Eingabefeld und Label im oberen Bereich
 | 
			
		||||
        JPanel topPanel = new JPanel();
 | 
			
		||||
        topPanel.setLayout(new FlowLayout());
 | 
			
		||||
        
 | 
			
		||||
        label = new JLabel("Server-Port:");
 | 
			
		||||
        inputField = new JTextField("42069", 10);
 | 
			
		||||
        topPanel.add(label);
 | 
			
		||||
        topPanel.add(inputField);
 | 
			
		||||
 | 
			
		||||
        // Buttons im unteren Bereich
 | 
			
		||||
        JPanel bottomPanel = new JPanel();
 | 
			
		||||
        bottomPanel.setLayout(new FlowLayout());
 | 
			
		||||
        
 | 
			
		||||
        startButton = new JButton("Start Server");
 | 
			
		||||
        stopButton = new JButton("Stop Server");
 | 
			
		||||
        stopButton.setEnabled(false); // Stop-Button ist anfangs deaktiviert
 | 
			
		||||
        
 | 
			
		||||
        bottomPanel.add(startButton);
 | 
			
		||||
        bottomPanel.add(stopButton);
 | 
			
		||||
 | 
			
		||||
        // Füge die Panels zum Hauptfenster hinzu
 | 
			
		||||
        frame.add(topPanel, BorderLayout.NORTH);
 | 
			
		||||
        frame.add(bottomPanel, BorderLayout.SOUTH);
 | 
			
		||||
 | 
			
		||||
        // Aktion für Start-Button
 | 
			
		||||
        startButton.addActionListener(e -> startServer());
 | 
			
		||||
 | 
			
		||||
        // Aktion für Stop-Button
 | 
			
		||||
        stopButton.addActionListener(e -> stopServer());
 | 
			
		||||
 | 
			
		||||
        // Zeige das Fenster
 | 
			
		||||
        frame.setVisible(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void startServer() {
 | 
			
		||||
        String port = inputField.getText();
 | 
			
		||||
        try {
 | 
			
		||||
            int portNumber = Integer.parseInt(port);
 | 
			
		||||
            // Server-Startlogik hier einfügen
 | 
			
		||||
            JOptionPane.showMessageDialog(frame, "Server gestartet auf Port " + portNumber);
 | 
			
		||||
            startButton.setEnabled(false); // Deaktiviere den Start-Button
 | 
			
		||||
            stopButton.setEnabled(true);  // Aktiviere den Stop-Button
 | 
			
		||||
        } catch (NumberFormatException e) {
 | 
			
		||||
            JOptionPane.showMessageDialog(frame, "Ungültiger Port: " + port, "Fehler", JOptionPane.ERROR_MESSAGE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void stopServer() {
 | 
			
		||||
        // Server-Stoplogik hier einfügen
 | 
			
		||||
        JOptionPane.showMessageDialog(frame, "Server gestoppt.");
 | 
			
		||||
        startButton.setEnabled(true); // Aktiviere den Start-Button
 | 
			
		||||
        stopButton.setEnabled(false); // Deaktiviere den Stop-Button
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        SwingUtilities.invokeLater(ServerScreen::new);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,120 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Checkbox;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.Slider;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
 | 
			
		||||
 */
 | 
			
		||||
public class SettingsMenu extends Dialog {
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private final Container settingsContainer;
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    public SettingsMenu(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für das Menü
 | 
			
		||||
        settingsContainer = new Container();
 | 
			
		||||
        settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label settingsTitle = settingsContainer.addChild(new Label("Einstellungen", new ElementId("settings-title")));
 | 
			
		||||
        settingsTitle.setFontSize(48);
 | 
			
		||||
 | 
			
		||||
        // Effekt-Sound: Slider und Checkbox
 | 
			
		||||
        Container effectSoundContainer = settingsContainer.addChild(new Container());
 | 
			
		||||
        effectSoundContainer.addChild(new Label("Effekt Sound", new ElementId("label")));
 | 
			
		||||
        effectSoundContainer.addChild(new Slider());
 | 
			
		||||
        effectSoundContainer.addChild(new Checkbox("Soundeffekte an")).setChecked(true);
 | 
			
		||||
        effectSoundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
        // Hintergrundmusik: Slider und Checkbox
 | 
			
		||||
        Container backgroundMusicContainer = settingsContainer.addChild(new Container());
 | 
			
		||||
        backgroundMusicContainer.addChild(new Label("Hintergrund Musik", new ElementId("label")));
 | 
			
		||||
        backgroundMusicContainer.addChild(new Slider());
 | 
			
		||||
        backgroundMusicContainer.addChild(new Checkbox("Musik an")).setChecked(true);
 | 
			
		||||
        backgroundMusicContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("menu-button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> app.stop());
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Padding around the settingsContainer for the background
 | 
			
		||||
        backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        settingsContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            4
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                3
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(settingsContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt einen halbtransparenten Hintergrund für das Menü.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Geometrie des Overlays
 | 
			
		||||
     */
 | 
			
		||||
    private Geometry createOverlayBackground() {
 | 
			
		||||
        Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        Geometry overlay = new Geometry("Overlay", quad);
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
 | 
			
		||||
        material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 | 
			
		||||
        overlay.setMaterial(material);
 | 
			
		||||
        overlay.setLocalTranslation(0, 0, 0);
 | 
			
		||||
        return overlay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Schließt das Menü und entfernt die GUI-Elemente.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
 | 
			
		||||
        app.getGuiNode().detachChild(settingsContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren
 | 
			
		||||
        app.unblockInputs();                             // Eingaben wieder aktivieren
 | 
			
		||||
        System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,107 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Box;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TestWorld zeigt eine einfache Szene mit einem texturierten Quadrat.
 | 
			
		||||
 * Die Kamera wird durch den CameraController gesteuert.
 | 
			
		||||
 */
 | 
			
		||||
public class TestWorld {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private CameraController cameraController; // Steuert die Kamera
 | 
			
		||||
    private Geometry cube; // Spielfigur
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Konstruktor für TestWorld.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app Die Hauptanwendung (MonopolyApp)
 | 
			
		||||
     */
 | 
			
		||||
    public TestWorld(MonopolyApp app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialisiert die Szene und startet die Kamerabewegung.
 | 
			
		||||
     */
 | 
			
		||||
    public void initializeScene() {
 | 
			
		||||
        app.getGuiNode().detachAllChildren(); // Entferne GUI
 | 
			
		||||
        app.getRootNode().detachAllChildren(); // Entferne andere Szenenobjekte
 | 
			
		||||
 | 
			
		||||
        setSkyColor(); // Setze den Himmel auf hellblau
 | 
			
		||||
        createBoard(); // Erstelle das Spielfeld
 | 
			
		||||
        createCube();  // Füge den Würfel hinzu
 | 
			
		||||
 | 
			
		||||
        // Erstelle den CameraController
 | 
			
		||||
        cameraController = new CameraController(
 | 
			
		||||
                app.getCamera(),           // Die Kamera der App
 | 
			
		||||
                Vector3f.ZERO,            // Fokus auf die Mitte des Spielfelds
 | 
			
		||||
                5,                        // Radius des Kreises
 | 
			
		||||
                3,                        // Höhe der Kamera
 | 
			
		||||
                0.5f                      // Geschwindigkeit der Bewegung
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Füge die Toolbar hinzu
 | 
			
		||||
        new Toolbar(app, cube);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Aktualisiert die Kameraposition.
 | 
			
		||||
     *
 | 
			
		||||
     * @param tpf Zeit pro Frame
 | 
			
		||||
     */
 | 
			
		||||
    public void update(float tpf) {
 | 
			
		||||
        if (cameraController != null) {
 | 
			
		||||
            cameraController.update(tpf);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Setzt die Hintergrundfarbe der Szene auf hellblau.
 | 
			
		||||
     */
 | 
			
		||||
    private void setSkyColor() {
 | 
			
		||||
        app.getViewPort().setBackgroundColor(new ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f)); // Hellblauer Himmel
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstelle das Spielfeld.
 | 
			
		||||
     */
 | 
			
		||||
    private void createBoard() {
 | 
			
		||||
        // Erstelle ein Quadrat
 | 
			
		||||
        Box box = new Box(1, 0.01f, 1);  // Dünnes Quadrat für die Textur
 | 
			
		||||
        Geometry geom = new Geometry("Board", box);
 | 
			
		||||
 | 
			
		||||
        // Setze das Material mit Textur
 | 
			
		||||
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        Texture texture = app.getAssetManager().loadTexture("Pictures/board2.png");
 | 
			
		||||
        mat.setTexture("ColorMap", texture);
 | 
			
		||||
        geom.setMaterial(mat);
 | 
			
		||||
 | 
			
		||||
        app.getRootNode().attachChild(geom);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt den Würfel (Spielfigur) in der Szene.
 | 
			
		||||
     */
 | 
			
		||||
    private void createCube() {
 | 
			
		||||
        Box box = new Box(0.05f, 0.05f, 0.05f); // Kleinere Größe für Spielfigur
 | 
			
		||||
        cube = new Geometry("Cube", box);
 | 
			
		||||
 | 
			
		||||
        // Setze das Material für den Würfel
 | 
			
		||||
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        mat.setColor("Color", ColorRGBA.Blue); // Blau gefärbter Würfel
 | 
			
		||||
        cube.setMaterial(mat);
 | 
			
		||||
 | 
			
		||||
        // Setze den Startpunkt des Würfels
 | 
			
		||||
        cube.setLocalTranslation(0.8999999f, 0.1f, -0.9f);
 | 
			
		||||
 | 
			
		||||
        app.getRootNode().attachChild(cube);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,168 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
 | 
			
		||||
import com.jme3.font.BitmapText;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
 | 
			
		||||
 * Die Buttons bewegen den Würfel auf dem Spielfeld.
 | 
			
		||||
 */
 | 
			
		||||
public class Toolbar {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Container toolbarContainer;
 | 
			
		||||
    private final Geometry cube; // Referenz auf den Würfel
 | 
			
		||||
    private final BitmapText positionText; // Anzeige für die aktuelle Position
 | 
			
		||||
    private final float boardLimit = 0.95f; // Grenzen des Bretts
 | 
			
		||||
    private final float stepSize = 0.18f; // Schrittgröße pro Bewegung
 | 
			
		||||
    private int currentPosition = 0; // Aktuelle Position auf dem Spielfeld
 | 
			
		||||
    private final int positionsPerSide = 10; // Anzahl der Positionen pro Seite
 | 
			
		||||
    private final Random random = new Random(); // Zufallsgenerator für den Würfelwurf
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Konstruktor für die Toolbar.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app  Die Hauptanwendung (MonopolyApp)
 | 
			
		||||
     * @param cube Der Würfel, der bewegt werden soll
 | 
			
		||||
     */
 | 
			
		||||
    public Toolbar(MonopolyApp app, Geometry cube) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        this.cube = cube;
 | 
			
		||||
 | 
			
		||||
        // Erstelle die Toolbar
 | 
			
		||||
        toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
 | 
			
		||||
        // Setze die Position am unteren Rand und die Breite
 | 
			
		||||
        toolbarContainer.setLocalTranslation(
 | 
			
		||||
                0,                                 // Links bündig
 | 
			
		||||
                100,                               // Höhe über dem unteren Rand
 | 
			
		||||
                0                                  // Z-Ebene
 | 
			
		||||
        );
 | 
			
		||||
        toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 100, 0)); // Volle Breite
 | 
			
		||||
 | 
			
		||||
        // Füge Buttons zur Toolbar hinzu
 | 
			
		||||
        initializeButtons();
 | 
			
		||||
 | 
			
		||||
        // Füge die Toolbar zur GUI hinzu
 | 
			
		||||
        app.getGuiNode().attachChild(toolbarContainer);
 | 
			
		||||
 | 
			
		||||
        // Erstelle die Position-Anzeige
 | 
			
		||||
        positionText = createPositionDisplay();
 | 
			
		||||
        updatePositionDisplay(); // Initialisiere die Anzeige mit der Startposition
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialisiert die Buttons in der Toolbar.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeButtons() {
 | 
			
		||||
        addButton("Vorwärts", 1);  // Bewegung nach vorne
 | 
			
		||||
        addButton("Rückwärts", -1); // Bewegung nach hinten
 | 
			
		||||
        addDiceRollButton();       // Würfel-Button
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fügt einen Button mit einer Bewegung hinzu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param label   Der Text des Buttons
 | 
			
		||||
     * @param step    Schrittweite (+1 für vorwärts, -1 für rückwärts)
 | 
			
		||||
     */
 | 
			
		||||
    private void addButton(String label, int step) {
 | 
			
		||||
        Button button = new Button(label);
 | 
			
		||||
        button.setPreferredSize(new Vector3f(150, 50, 0)); // Größe der Buttons
 | 
			
		||||
        button.addClickCommands(source -> moveCube(step));
 | 
			
		||||
        toolbarContainer.addChild(button);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fügt den Würfel-Button hinzu, der die Figur entsprechend der gewürfelten Zahl bewegt.
 | 
			
		||||
     */
 | 
			
		||||
    private void addDiceRollButton() {
 | 
			
		||||
        Button diceButton = new Button("Würfeln");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
 | 
			
		||||
        diceButton.addClickCommands(source -> rollDice());
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Simuliert einen Würfelwurf und bewegt die Figur entsprechend.
 | 
			
		||||
     */
 | 
			
		||||
    private void rollDice() {
 | 
			
		||||
        int diceRoll = random.nextInt(6) + 1; // Zahl zwischen 1 und 6
 | 
			
		||||
        System.out.println("Gewürfelt: " + diceRoll);
 | 
			
		||||
        moveCube(diceRoll); // Bewege die Figur um die gewürfelte Zahl
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Bewegt den Würfel basierend auf der aktuellen Position auf dem Brett.
 | 
			
		||||
     *
 | 
			
		||||
     * @param step Schrittweite (+1 für vorwärts, -1 für rückwärts oder andere Werte)
 | 
			
		||||
     */
 | 
			
		||||
    private void moveCube(int step) {
 | 
			
		||||
        currentPosition = (currentPosition + step + 4 * positionsPerSide) % (4 * positionsPerSide);
 | 
			
		||||
        Vector3f newPosition = calculatePosition(currentPosition);
 | 
			
		||||
        cube.setLocalTranslation(newPosition);
 | 
			
		||||
        updatePositionDisplay(); // Aktualisiere die Positionsanzeige
 | 
			
		||||
        System.out.println("Würfelposition: " + newPosition + " (Feld-ID: " + currentPosition + ")");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Berechnet die neue Position des Würfels basierend auf der aktuellen Brettseite und Position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param position Aktuelle Position auf dem Spielfeld
 | 
			
		||||
     * @return Die berechnete Position als Vector3f
 | 
			
		||||
     */
 | 
			
		||||
    private Vector3f calculatePosition(int position) {
 | 
			
		||||
        int side = position / positionsPerSide; // Seite des Bretts (0 = unten, 1 = rechts, 2 = oben, 3 = links)
 | 
			
		||||
        int offset = position % positionsPerSide; // Position auf der aktuellen Seite
 | 
			
		||||
 | 
			
		||||
        switch (side) {
 | 
			
		||||
            case 0: // Unten (positive x-Achse)
 | 
			
		||||
                return new Vector3f(-boardLimit + offset * stepSize, 0.1f, -boardLimit + 0.05f);
 | 
			
		||||
            case 1: // Rechts (positive z-Achse)
 | 
			
		||||
                return new Vector3f(boardLimit - 0.05f, 0.1f, -boardLimit + offset * stepSize);
 | 
			
		||||
            case 2: // Oben (negative x-Achse)
 | 
			
		||||
                return new Vector3f(boardLimit - offset * stepSize, 0.1f, boardLimit - 0.05f);
 | 
			
		||||
            case 3: // Links (negative z-Achse)
 | 
			
		||||
                return new Vector3f(-boardLimit + 0.05f, 0.1f, boardLimit - offset * stepSize);
 | 
			
		||||
            default:
 | 
			
		||||
                throw new IllegalArgumentException("Ungültige Position: " + position);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt die Anzeige für die aktuelle Position.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Das BitmapText-Objekt für die Anzeige
 | 
			
		||||
     */
 | 
			
		||||
    private BitmapText createPositionDisplay() {
 | 
			
		||||
        BitmapText text = new BitmapText(app.getAssetManager().loadFont("Interface/Fonts/Default.fnt"), false);
 | 
			
		||||
        text.setSize(20); // Schriftgröße
 | 
			
		||||
        text.setLocalTranslation(10, app.getCamera().getHeight() - 10, 0); // Oben links
 | 
			
		||||
        app.getGuiNode().attachChild(text);
 | 
			
		||||
        return text;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Aktualisiert die Anzeige für die aktuelle Position.
 | 
			
		||||
     */
 | 
			
		||||
    private void updatePositionDisplay() {
 | 
			
		||||
        positionText.setText("Feld-ID: " + currentPosition);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Entfernt die Toolbar.
 | 
			
		||||
     */
 | 
			
		||||
    public void remove() {
 | 
			
		||||
        app.getGuiNode().detachChild(toolbarContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(positionText);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,168 +0,0 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
 | 
			
		||||
import com.jme3.font.BitmapText;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.simsilica.lemur.Axis;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
 | 
			
		||||
 * Die Buttons bewegen den Würfel auf dem Spielfeld.
 | 
			
		||||
 */
 | 
			
		||||
public class Toolbar2 {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Container toolbarContainer;
 | 
			
		||||
    private final Geometry cube; // Referenz auf den Würfel
 | 
			
		||||
    private final BitmapText positionText; // Anzeige für die aktuelle Position
 | 
			
		||||
    private final float boardLimit = 0.95f; // Grenzen des Bretts
 | 
			
		||||
    private final float stepSize = 0.18f; // Schrittgröße pro Bewegung
 | 
			
		||||
    private int currentPosition = 0; // Aktuelle Position auf dem Spielfeld
 | 
			
		||||
    private final int positionsPerSide = 10; // Anzahl der Positionen pro Seite
 | 
			
		||||
    private final Random random = new Random(); // Zufallsgenerator für den Würfelwurf
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Konstruktor für die Toolbar.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app  Die Hauptanwendung (MonopolyApp)
 | 
			
		||||
     * @param cube Der Würfel, der bewegt werden soll
 | 
			
		||||
     */
 | 
			
		||||
    public Toolbar2(MonopolyApp app, Geometry cube) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        this.cube = cube;
 | 
			
		||||
 | 
			
		||||
        // Erstelle die Toolbar
 | 
			
		||||
        toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
 | 
			
		||||
 | 
			
		||||
        // Setze die Position am unteren Rand und die Breite
 | 
			
		||||
        toolbarContainer.setLocalTranslation(
 | 
			
		||||
                0,                                 // Links bündig
 | 
			
		||||
                100,                               // Höhe über dem unteren Rand
 | 
			
		||||
                0                                  // Z-Ebene
 | 
			
		||||
        );
 | 
			
		||||
        toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 100, 0)); // Volle Breite
 | 
			
		||||
 | 
			
		||||
        // Füge Buttons zur Toolbar hinzu
 | 
			
		||||
        initializeButtons();
 | 
			
		||||
 | 
			
		||||
        // Füge die Toolbar zur GUI hinzu
 | 
			
		||||
        app.getGuiNode().attachChild(toolbarContainer);
 | 
			
		||||
 | 
			
		||||
        // Erstelle die Position-Anzeige
 | 
			
		||||
        positionText = createPositionDisplay();
 | 
			
		||||
        updatePositionDisplay(); // Initialisiere die Anzeige mit der Startposition
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialisiert die Buttons in der Toolbar.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeButtons() {
 | 
			
		||||
        addButton("Vorwärts", 1);  // Bewegung nach vorne
 | 
			
		||||
        addButton("Rückwärts", -1); // Bewegung nach hinten
 | 
			
		||||
        addDiceRollButton();       // Würfel-Button
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fügt einen Button mit einer Bewegung hinzu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param label   Der Text des Buttons
 | 
			
		||||
     * @param step    Schrittweite (+1 für vorwärts, -1 für rückwärts)
 | 
			
		||||
     */
 | 
			
		||||
    private void addButton(String label, int step) {
 | 
			
		||||
        Button button = new Button(label);
 | 
			
		||||
        button.setPreferredSize(new Vector3f(150, 50, 0)); // Größe der Buttons
 | 
			
		||||
        button.addClickCommands(source -> moveCube(step));
 | 
			
		||||
        toolbarContainer.addChild(button);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fügt den Würfel-Button hinzu, der die Figur entsprechend der gewürfelten Zahl bewegt.
 | 
			
		||||
     */
 | 
			
		||||
    private void addDiceRollButton() {
 | 
			
		||||
        Button diceButton = new Button("Würfeln");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
 | 
			
		||||
        diceButton.addClickCommands(source -> rollDice());
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Simuliert einen Würfelwurf und bewegt die Figur entsprechend.
 | 
			
		||||
     */
 | 
			
		||||
    private void rollDice() {
 | 
			
		||||
        int diceRoll = random.nextInt(6) + 1; // Zahl zwischen 1 und 6
 | 
			
		||||
        System.out.println("Gewürfelt: " + diceRoll);
 | 
			
		||||
        moveCube(diceRoll); // Bewege die Figur um die gewürfelte Zahl
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Bewegt den Würfel basierend auf der aktuellen Position auf dem Brett.
 | 
			
		||||
     *
 | 
			
		||||
     * @param step Schrittweite (+1 für vorwärts, -1 für rückwärts oder andere Werte)
 | 
			
		||||
     */
 | 
			
		||||
    private void moveCube(int step) {
 | 
			
		||||
        currentPosition = (currentPosition + step + 4 * positionsPerSide) % (4 * positionsPerSide);
 | 
			
		||||
        Vector3f newPosition = calculatePosition(currentPosition);
 | 
			
		||||
        cube.setLocalTranslation(newPosition);
 | 
			
		||||
        updatePositionDisplay(); // Aktualisiere die Positionsanzeige
 | 
			
		||||
        System.out.println("Würfelposition: " + newPosition + " (Feld-ID: " + currentPosition + ")");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Berechnet die neue Position des Würfels basierend auf der aktuellen Brettseite und Position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param position Aktuelle Position auf dem Spielfeld
 | 
			
		||||
     * @return Die berechnete Position als Vector3f
 | 
			
		||||
     */
 | 
			
		||||
    private Vector3f calculatePosition(int position) {
 | 
			
		||||
        int side = position / positionsPerSide; // Seite des Bretts (0 = unten, 1 = rechts, 2 = oben, 3 = links)
 | 
			
		||||
        int offset = position % positionsPerSide; // Position auf der aktuellen Seite
 | 
			
		||||
 | 
			
		||||
        switch (side) {
 | 
			
		||||
            case 0: // Unten (positive x-Achse)
 | 
			
		||||
                return new Vector3f(-boardLimit + offset * stepSize, 0.1f, -boardLimit + 0.05f);
 | 
			
		||||
            case 1: // Rechts (positive z-Achse)
 | 
			
		||||
                return new Vector3f(boardLimit - 0.05f, 0.1f, -boardLimit + offset * stepSize);
 | 
			
		||||
            case 2: // Oben (negative x-Achse)
 | 
			
		||||
                return new Vector3f(boardLimit - offset * stepSize, 0.1f, boardLimit - 0.05f);
 | 
			
		||||
            case 3: // Links (negative z-Achse)
 | 
			
		||||
                return new Vector3f(-boardLimit + 0.05f, 0.1f, boardLimit - offset * stepSize);
 | 
			
		||||
            default:
 | 
			
		||||
                throw new IllegalArgumentException("Ungültige Position: " + position);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Erstellt die Anzeige für die aktuelle Position.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Das BitmapText-Objekt für die Anzeige
 | 
			
		||||
     */
 | 
			
		||||
    private BitmapText createPositionDisplay() {
 | 
			
		||||
        BitmapText text = new BitmapText(app.getAssetManager().loadFont("Interface/Fonts/Default.fnt"), false);
 | 
			
		||||
        text.setSize(20); // Schriftgröße
 | 
			
		||||
        text.setLocalTranslation(10, app.getCamera().getHeight() - 10, 0); // Oben links
 | 
			
		||||
        app.getGuiNode().attachChild(text);
 | 
			
		||||
        return text;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Aktualisiert die Anzeige für die aktuelle Position.
 | 
			
		||||
     */
 | 
			
		||||
    private void updatePositionDisplay() {
 | 
			
		||||
        positionText.setText("Feld-ID: " + currentPosition);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Entfernt die Toolbar.
 | 
			
		||||
     */
 | 
			
		||||
    public void remove() {
 | 
			
		||||
        app.getGuiNode().detachChild(toolbarContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(positionText);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1,10 +0,0 @@
 | 
			
		||||
plugins {
 | 
			
		||||
    id 'buildlogic.java-library-conventions'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
description = 'Monopoly common model'
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    api project(":common")
 | 
			
		||||
    api libs.jme3.networking
 | 
			
		||||
}
 | 
			
		||||
@@ -1,79 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly;
 | 
			
		||||
 | 
			
		||||
import static java.lang.Math.max;
 | 
			
		||||
 | 
			
		||||
import pp.util.config.Config;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides access to the configuration settings for the Monopoly game.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * This class allows for loading configuration settings from a properties file,
 | 
			
		||||
 * including the server port, map dimensions
 | 
			
		||||
 * </p>
 | 
			
		||||
 * <p>
 | 
			
		||||
 * <b>Note:</b> Attributes of this class are not marked as {@code final} to allow
 | 
			
		||||
 * for proper initialization when reading from a properties file.
 | 
			
		||||
 * </p>
 | 
			
		||||
 */
 | 
			
		||||
public class MonopolyConfig extends Config {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The default port number for the Monopoly server.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("port")
 | 
			
		||||
    private int port = 42069;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The width of the game map in terms of grid units.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("map.width")
 | 
			
		||||
    private int mapWidth = 11;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The height of the game map in terms of grid units.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("map.height")
 | 
			
		||||
    private int mapHeight = 11;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates an instance of {@code MonopolyConfig} with default settings.
 | 
			
		||||
     */
 | 
			
		||||
    public MonopolyConfig() {
 | 
			
		||||
        // Default constructor
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the port number configured for the Monopoly server.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the port number
 | 
			
		||||
     */
 | 
			
		||||
    public int getPort() {
 | 
			
		||||
        return port;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the width of the game map. The width is guaranteed to be at least 2 units.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the width of the game map
 | 
			
		||||
     */
 | 
			
		||||
    public int getMapWidth() {
 | 
			
		||||
        return max(mapWidth, 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the height of the game map. The height is guaranteed to be at least 2 units.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the height of the game map
 | 
			
		||||
     */
 | 
			
		||||
    public int getMapHeight() {
 | 
			
		||||
        return max(mapHeight, 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly;
 | 
			
		||||
 | 
			
		||||
import java.util.ResourceBundle;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides access to the resource bundle of the game.
 | 
			
		||||
 *
 | 
			
		||||
 * @see #BUNDLE
 | 
			
		||||
 */
 | 
			
		||||
public class Resources {
 | 
			
		||||
    /**
 | 
			
		||||
     * The resource bundle for the Monopoly game.
 | 
			
		||||
     */
 | 
			
		||||
    public static final ResourceBundle BUNDLE = ResourceBundle.getBundle("monopoly"); //NON-NLS
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a string for the given key from the resource bundle in {@linkplain #BUNDLE}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param key the key for the desired string
 | 
			
		||||
     * @return the string for the given key
 | 
			
		||||
     * @throws NullPointerException               if {@code key} is {@code null}
 | 
			
		||||
     * @throws java.util.MissingResourceException if no object for the given key can be found
 | 
			
		||||
     * @throws ClassCastException                 if the object found for the given key is not a string
 | 
			
		||||
     */
 | 
			
		||||
    public static String lookup(String key) {
 | 
			
		||||
        return BUNDLE.getString(key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Private constructor to prevent instantiation.
 | 
			
		||||
     */
 | 
			
		||||
    private Resources() { /* do not instantiate */ }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,260 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.client;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.message.client.ClientMessage;
 | 
			
		||||
import pp.monopoly.message.server.BuyPropertyResponse;
 | 
			
		||||
import pp.monopoly.message.server.DiceResult;
 | 
			
		||||
import pp.monopoly.message.server.EventDrawCard;
 | 
			
		||||
import pp.monopoly.message.server.GameOver;
 | 
			
		||||
import pp.monopoly.message.server.GameStart;
 | 
			
		||||
import pp.monopoly.message.server.JailEvent;
 | 
			
		||||
import pp.monopoly.message.server.PlayerStatusUpdate;
 | 
			
		||||
import pp.monopoly.message.server.ServerInterpreter;
 | 
			
		||||
import pp.monopoly.message.server.TimeOutWarning;
 | 
			
		||||
import pp.monopoly.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.message.server.TradeRequest;
 | 
			
		||||
import pp.monopoly.message.server.ViewAssetsResponse;
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.model.IntPoint;
 | 
			
		||||
import pp.monopoly.notification.ClientStateEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEventBroker;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.InfoTextEvent;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
import pp.monopoly.notification.SoundEvent;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Controls the client-side game logic for Monopoly.
 | 
			
		||||
 * Manages the player's placement, interactions with the map, and response to server messages.
 | 
			
		||||
 */
 | 
			
		||||
public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
    static final Logger LOGGER = System.getLogger(ClientGameLogic.class.getName());
 | 
			
		||||
    private final ClientSender clientSender;
 | 
			
		||||
    private final List<GameEventListener> listeners = new ArrayList<>();
 | 
			
		||||
    private Board board;
 | 
			
		||||
 | 
			
		||||
    private ClientState state = new ClientState(this) {
 | 
			
		||||
        
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a ClientGameLogic with the specified sender object.
 | 
			
		||||
     *
 | 
			
		||||
     * @param clientSender the object used to send messages to the server
 | 
			
		||||
     */
 | 
			
		||||
    public ClientGameLogic(ClientSender clientSender) {
 | 
			
		||||
        this.clientSender = clientSender;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current state of the game logic.
 | 
			
		||||
     */
 | 
			
		||||
    ClientState getState() {
 | 
			
		||||
        return state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the current state of the game logic.
 | 
			
		||||
     *
 | 
			
		||||
     * @param newState the new state to be set
 | 
			
		||||
     */
 | 
			
		||||
    void setState(ClientState newState) {
 | 
			
		||||
        LOGGER.log(Level.DEBUG, "state transition {0} --> {1}", state.getName(), newState.getName()); //NON-NLS
 | 
			
		||||
        state = newState;
 | 
			
		||||
        notifyListeners(new ClientStateEvent());
 | 
			
		||||
        state.entry();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the player's own map.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the player's own map
 | 
			
		||||
     */
 | 
			
		||||
    public Board getBoard() {
 | 
			
		||||
        return board;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves the preview figure to the specified position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos the new position for the preview figure
 | 
			
		||||
     */
 | 
			
		||||
    public void movePreview(IntPoint pos) {
 | 
			
		||||
        state.movePreview(pos);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the informational text to be displayed to the player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param key the key for the info text
 | 
			
		||||
     */
 | 
			
		||||
    void setInfoText(String key) {
 | 
			
		||||
        notifyListeners(new InfoTextEvent(key));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Emits an event to play the specified sound.
 | 
			
		||||
     *
 | 
			
		||||
     * @param sound the sound to be played.
 | 
			
		||||
     */
 | 
			
		||||
    public void playSound(Sound sound) {
 | 
			
		||||
        notifyListeners(new SoundEvent(sound));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a map from the specified file.
 | 
			
		||||
     *
 | 
			
		||||
     * @param file the file to load the map from
 | 
			
		||||
     * @throws IOException if an I/O error occurs
 | 
			
		||||
     */
 | 
			
		||||
    public void loadMap(File file) throws IOException {
 | 
			
		||||
        state.loadMap(file);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a message to the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the message to be sent
 | 
			
		||||
     */
 | 
			
		||||
    void send(ClientMessage msg) {
 | 
			
		||||
        if (clientSender == null)
 | 
			
		||||
            LOGGER.log(Level.ERROR, "trying to send {0} with sender==null", msg); //NON-NLS
 | 
			
		||||
        else
 | 
			
		||||
            clientSender.send(msg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a listener to receive game events.
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener the listener to add
 | 
			
		||||
     */
 | 
			
		||||
    public synchronized void addListener(GameEventListener listener) {
 | 
			
		||||
        listeners.add(listener);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes a listener from receiving game events.
 | 
			
		||||
     *
 | 
			
		||||
     * @param listener the listener to remove
 | 
			
		||||
     */
 | 
			
		||||
    public synchronized void removeListener(GameEventListener listener) {
 | 
			
		||||
        listeners.remove(listener);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Notifies all listeners of a game event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event the game event to notify listeners of
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void notifyListeners(GameEvent event) {
 | 
			
		||||
        final List<GameEventListener> copy;
 | 
			
		||||
        synchronized (this) {
 | 
			
		||||
            copy = new ArrayList<>(listeners);
 | 
			
		||||
        }
 | 
			
		||||
        for (GameEventListener listener : copy)
 | 
			
		||||
            event.notifyListener(listener);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called once per frame by the update loop.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta time in seconds since the last update call
 | 
			
		||||
     */
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        state.update(delta);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(BuyPropertyResponse msg) {
 | 
			
		||||
        if (msg.isSuccessful()) {
 | 
			
		||||
            setInfoText("You successfully bought " + msg.getPropertyName() + "!");
 | 
			
		||||
            playSound(Sound.MONEY_LOST);
 | 
			
		||||
        } else {
 | 
			
		||||
            setInfoText("Unable to buy " + msg.getPropertyName() + ". Reason: " + msg.getReason());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(DiceResult msg) {
 | 
			
		||||
        setInfoText("You rolled a " + msg.calcTotal() + "!");
 | 
			
		||||
        playSound(Sound.DICE_ROLL);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(EventDrawCard msg) {
 | 
			
		||||
        setInfoText("Event card drawn: " + msg.getCardDescription());
 | 
			
		||||
        playSound(Sound.EVENT_CARD);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(GameOver msg) {
 | 
			
		||||
        if (msg.isWinner()) {
 | 
			
		||||
            setInfoText("Congratulations! You have won the game!");
 | 
			
		||||
            playSound(Sound.WINNER);
 | 
			
		||||
        } else {
 | 
			
		||||
            setInfoText("Game over. Better luck next time!");
 | 
			
		||||
            playSound(Sound.LOSER);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(GameStart msg) {
 | 
			
		||||
        setInfoText("The game has started! Good luck!");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(JailEvent msg) {
 | 
			
		||||
        if (msg.isGoingToJail()) {
 | 
			
		||||
            setInfoText("You are sent to jail!");
 | 
			
		||||
            playSound(Sound.GULAG);
 | 
			
		||||
        } else {
 | 
			
		||||
            setInfoText("You are out of jail!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(PlayerStatusUpdate msg) {
 | 
			
		||||
        setInfoText("Player " + msg.getPlayerName() + " status updated: " + msg.getStatus());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TimeOutWarning msg) {
 | 
			
		||||
        setInfoText("Warning! Time is running out. You have " + msg.getRemainingTime() + " seconds left.");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(ViewAssetsResponse msg) {
 | 
			
		||||
        setInfoText("Your current assets are being displayed.");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TradeReply msg) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TradeRequest msg) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.client;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.message.client.ClientMessage;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface for sending messages to the server.
 | 
			
		||||
 */
 | 
			
		||||
public interface ClientSender {
 | 
			
		||||
    /**
 | 
			
		||||
     * Send the specified message to the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param message the message
 | 
			
		||||
     */
 | 
			
		||||
    void send(ClientMessage message);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,85 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.client;
 | 
			
		||||
import pp.monopoly.model.IntPoint;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Defines the behavior and state transitions for the client-side game logic.
 | 
			
		||||
 * Different states of the game logic implement this interface to handle various game events and actions.
 | 
			
		||||
 */
 | 
			
		||||
abstract class ClientState {
 | 
			
		||||
    /**
 | 
			
		||||
     * The game logic object.
 | 
			
		||||
     */
 | 
			
		||||
    final ClientGameLogic logic;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a client state of the specified game logic.
 | 
			
		||||
     *
 | 
			
		||||
     * @param logic the game logic
 | 
			
		||||
     */
 | 
			
		||||
    ClientState(ClientGameLogic logic) {
 | 
			
		||||
        this.logic = logic;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Method to be overridden by subclasses for post-transition initialization.
 | 
			
		||||
     * By default, it does nothing, but it can be overridden in derived states.
 | 
			
		||||
     */
 | 
			
		||||
    void entry() {
 | 
			
		||||
        // Default implementation does nothing
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the name of the current state.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the name of the current state
 | 
			
		||||
     */
 | 
			
		||||
    String getName() {
 | 
			
		||||
        return getClass().getSimpleName();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the battle state should be shown.
 | 
			
		||||
     *
 | 
			
		||||
     * @return true if the battle state should be shown, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    boolean showTurn() {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves the preview figure to the specified position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos the new position for the preview figure
 | 
			
		||||
     */
 | 
			
		||||
    void movePreview(IntPoint pos) {
 | 
			
		||||
        ClientGameLogic.LOGGER.log(Level.DEBUG, "movePreview has no effect in {0}", getName()); //NON-NLS
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a map from the specified file.
 | 
			
		||||
     *
 | 
			
		||||
     * @param file the file to load the map from
 | 
			
		||||
     * @throws IOException if the map cannot be loaded in the current state
 | 
			
		||||
     */
 | 
			
		||||
    void loadMap(File file) throws IOException {
 | 
			
		||||
        throw new IOException("You are not allowed to load a map in this state of the game");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called once per frame by the update loop if this state is active.
 | 
			
		||||
     *
 | 
			
		||||
     * @param delta time in seconds since the last update call
 | 
			
		||||
     */
 | 
			
		||||
    void update(float delta) { /* do nothing by default */ }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,36 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.client;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface representing a Monopoly client.
 | 
			
		||||
 * Provides methods to access game logic, configuration, and to enqueue tasks.
 | 
			
		||||
 */
 | 
			
		||||
public interface MonopolyClient {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the game logic associated with this client.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the ClientGameLogic instance
 | 
			
		||||
     */
 | 
			
		||||
    ClientGameLogic getGameLogic();
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
     * Returns the configuration associated with this client.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the MonopolyConfig instance
 | 
			
		||||
     */
 | 
			
		||||
    MonopolyClientConfig getConfig();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Enqueues a task to be executed by the client.
 | 
			
		||||
     *
 | 
			
		||||
     * @param runnable the task to be executed
 | 
			
		||||
     */
 | 
			
		||||
    void enqueue(Runnable runnable);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,48 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.client;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.MonopolyConfig;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class providing access to the Monopoly client configuration.
 | 
			
		||||
 * Extends {@link MonopolyConfig} to include additional properties specific to the client.
 | 
			
		||||
 * This class manages configuration settings related to the RobotClient's behavior
 | 
			
		||||
 * and the game maps used in single mode.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * <b>Note:</b> Attributes of this class should not be marked as {@code final}
 | 
			
		||||
 * to ensure proper functionality when reading from a properties file.
 | 
			
		||||
 * </p>
 | 
			
		||||
 */
 | 
			
		||||
public class MonopolyClientConfig extends MonopolyConfig {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Path to the file representing the map.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("map")
 | 
			
		||||
    private String map;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a default {@code MonopolyClientConfig} with predefined values.
 | 
			
		||||
     */
 | 
			
		||||
    public MonopolyClientConfig() {
 | 
			
		||||
        // Default constructor
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the file representing the opponent's map.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the opponent's map file, or {@code null} if not set.
 | 
			
		||||
     */
 | 
			
		||||
    public File getMap() {
 | 
			
		||||
        return map == null ? null : new File(map);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.client;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface representing a connection to the server.
 | 
			
		||||
 * Extends ClientSender to allow sending messages to the server.
 | 
			
		||||
 */
 | 
			
		||||
public interface ServerConnection extends ClientSender {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the client is currently connected to the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @return true if connected, false otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    boolean isConnected();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Establishes a connection to the server.
 | 
			
		||||
     */
 | 
			
		||||
    void connect();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Disconnects from the server.
 | 
			
		||||
     */
 | 
			
		||||
    void disconnect();
 | 
			
		||||
}
 | 
			
		||||
@@ -1,487 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.message.server.DiceResult;
 | 
			
		||||
import pp.monopoly.model.FieldVisitor;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.model.card.DeckHelper;
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
import pp.monopoly.model.fields.EventField;
 | 
			
		||||
import pp.monopoly.model.fields.FineField;
 | 
			
		||||
import pp.monopoly.model.fields.FoodField;
 | 
			
		||||
import pp.monopoly.model.fields.GateField;
 | 
			
		||||
import pp.monopoly.model.fields.GoField;
 | 
			
		||||
import pp.monopoly.model.fields.GulagField;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
import pp.monopoly.model.fields.TestStreckeField;
 | 
			
		||||
import pp.monopoly.model.fields.WacheField;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class representing a player
 | 
			
		||||
 */
 | 
			
		||||
public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    private final int id;
 | 
			
		||||
    private String name;
 | 
			
		||||
    private PlayerColor color;
 | 
			
		||||
    private int accountBalance = 0;
 | 
			
		||||
    private Figure figure;
 | 
			
		||||
    private List<PropertyField> properties;
 | 
			
		||||
    private int getOutOfJailCard;
 | 
			
		||||
    private int fieldID;
 | 
			
		||||
    private DiceResult rollResult;
 | 
			
		||||
    private final PlayerHandler handler;
 | 
			
		||||
    private PlayerState state = new LobbyState();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a player with the speciefied params
 | 
			
		||||
     * @param id the id of the player
 | 
			
		||||
     * @param name the name of the player
 | 
			
		||||
     * @param handler the PlayerHandler thispalyer is a part of
 | 
			
		||||
     */
 | 
			
		||||
    public Player(int id, String name, PlayerHandler handler) {
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.id = id;
 | 
			
		||||
        this.handler = handler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a player with the specified id
 | 
			
		||||
     * @param id the id of the player
 | 
			
		||||
     * @param handler the PlayerHandler this player is a part of
 | 
			
		||||
     */
 | 
			
		||||
    public Player(int id, PlayerHandler handler) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
        this.handler = handler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the name of the Player
 | 
			
		||||
     * @param name the new name
 | 
			
		||||
     */
 | 
			
		||||
    void setName(String name) {
 | 
			
		||||
        this.name = name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the PlayerColor
 | 
			
		||||
     * @param color the color to be set to
 | 
			
		||||
     */
 | 
			
		||||
    void setColor(PlayerColor color) {
 | 
			
		||||
        this.color = color;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns this players id
 | 
			
		||||
     * @return th eid of this player
 | 
			
		||||
     */
 | 
			
		||||
    public int getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current position of the player
 | 
			
		||||
     * @return the current position of this player
 | 
			
		||||
     */
 | 
			
		||||
    public int getFieldID() {
 | 
			
		||||
        return fieldID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves by the specified amount of steps
 | 
			
		||||
     * @param steps the number of steps to move
 | 
			
		||||
     * @return the new position
 | 
			
		||||
     */
 | 
			
		||||
    public int move(int steps){
 | 
			
		||||
        return movePos(fieldID+steps);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves the player to the specified Position on the board
 | 
			
		||||
     * @param position the position to move to
 | 
			
		||||
     * @return the new position
 | 
			
		||||
     */
 | 
			
		||||
    public int movePos(int position){
 | 
			
		||||
        fieldID = fieldID+position;
 | 
			
		||||
        if(fieldID >= 40) {
 | 
			
		||||
            fieldID = fieldID%40;
 | 
			
		||||
            earnMoney(2000);
 | 
			
		||||
        }
 | 
			
		||||
        return fieldID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all the properties owned by this player
 | 
			
		||||
     * @return List of all properties owned by this player
 | 
			
		||||
     */
 | 
			
		||||
    public List<PropertyField> getProperties() {
 | 
			
		||||
        return properties;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Buy the speciefied property.
 | 
			
		||||
     * Properties can olny be bought when they are not sold yet and you have enough money left to buy
 | 
			
		||||
     * @param property to property to be bought
 | 
			
		||||
     */
 | 
			
		||||
    public void buyProperty(PropertyField property) {
 | 
			
		||||
        if (property.getOwner() == null && accountBalance >= property.getPrice()) {
 | 
			
		||||
            properties.add(property);
 | 
			
		||||
            pay(property.getPrice());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sell the property
 | 
			
		||||
     * @param property the property to be sold
 | 
			
		||||
     */
 | 
			
		||||
    public void sellProperty(PropertyField property) {
 | 
			
		||||
        if (property.getOwner() == this) {
 | 
			
		||||
            properties.remove(property);
 | 
			
		||||
            property.setOwner(null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets this players current accountBalanece
 | 
			
		||||
     * @return the amount of money currently owned by this player
 | 
			
		||||
     */
 | 
			
		||||
    public int getAccountBalance() {
 | 
			
		||||
        return accountBalance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removed the speciefied amount of money to this players accountabalance
 | 
			
		||||
     * @param amount the amount to be removed
 | 
			
		||||
     */
 | 
			
		||||
    public void pay(int amount) {
 | 
			
		||||
        accountBalance -= amount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add the speciefied amount of money to this players accountabalance
 | 
			
		||||
     * @param amount the amount to be added
 | 
			
		||||
     */
 | 
			
		||||
    public void earnMoney(int amount) {
 | 
			
		||||
        accountBalance += amount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the players name
 | 
			
		||||
     * @return the name of this player
 | 
			
		||||
     */
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of GEtOutOfJailCards owned by this player
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    public int getNumJailCard() {
 | 
			
		||||
        return getOutOfJailCard;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a GetOutOfJailCard
 | 
			
		||||
     */
 | 
			
		||||
    public void addJailCard() {
 | 
			
		||||
        getOutOfJailCard++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes a GetOutOfJailCard.
 | 
			
		||||
     * Removes one single card per call, to a minimum of 0 cards
 | 
			
		||||
     */
 | 
			
		||||
    public void removeJailCard() {
 | 
			
		||||
        if (getOutOfJailCard ==0) {
 | 
			
		||||
            throw new IllegalStateException("Has no JailCard to remove");
 | 
			
		||||
        }
 | 
			
		||||
        getOutOfJailCard--;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the logic of paying the jail bail
 | 
			
		||||
     */
 | 
			
		||||
    public void payBail() {
 | 
			
		||||
        state.payBail();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the logic of using a GetOutOfJailCard
 | 
			
		||||
     */
 | 
			
		||||
    public void useJailCard() {
 | 
			
		||||
        state.useJailCard();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(BuildingProperty field) {
 | 
			
		||||
        int rent = field.calcRent();
 | 
			
		||||
 | 
			
		||||
        field.getOwner().earnMoney(rent);
 | 
			
		||||
        pay(rent);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(FoodField field) {
 | 
			
		||||
        int factor = 4;
 | 
			
		||||
        if (field.getOwner().getNumProp(field) == 2) {
 | 
			
		||||
            factor = 10;
 | 
			
		||||
        }
 | 
			
		||||
        field.getOwner().earnMoney(rollResult.calcTotal()*factor);
 | 
			
		||||
        pay(rollResult.calcTotal()*factor);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(GateField field) {
 | 
			
		||||
        int rent = field.calcRent() * field.getOwner().getNumProp(field);
 | 
			
		||||
 | 
			
		||||
        field.getOwner().earnMoney(rent);
 | 
			
		||||
        pay(rent);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(GulagField field) {
 | 
			
		||||
        state = new JailState();
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(TestStreckeField field) {
 | 
			
		||||
        earnMoney(field.collectMoney());
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(EventField field) {
 | 
			
		||||
        DeckHelper.drawCard();
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(WacheField field) {
 | 
			
		||||
        movePos(10);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(GoField field) {
 | 
			
		||||
        earnMoney(2000);
 | 
			
		||||
        GulagField res = (GulagField) handler.getLogic().getBoardManager().getFieldAtIndex(10);
 | 
			
		||||
        res.accept(this);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(FineField field) {
 | 
			
		||||
        int amount = field.getFine();
 | 
			
		||||
        pay(amount);
 | 
			
		||||
        TestStreckeField res =(TestStreckeField) handler.getLogic().getBoardManager().getFieldAtIndex(20);
 | 
			
		||||
        res.addMoney(amount);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of Properties of the speciefied fild type
 | 
			
		||||
     * @param field the type of field to search for
 | 
			
		||||
     * @return the number of the fields owned with the specified type
 | 
			
		||||
     */
 | 
			
		||||
    public int getNumProp(PropertyField field) {
 | 
			
		||||
        int count = 0;
 | 
			
		||||
        for (PropertyField propertyField : properties) {
 | 
			
		||||
            if (propertyField.getClass() == field.getClass()) {
 | 
			
		||||
                count++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
     * Inner class for dice functionality in the game.
 | 
			
		||||
     * Rolls random dice values.
 | 
			
		||||
     */
 | 
			
		||||
    private class Dice {
 | 
			
		||||
        private static Random random = new Random();
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Rolls a single die and returns a random value from 1 to 6.
 | 
			
		||||
         *
 | 
			
		||||
         * @return the result of a dice roll (1 to 6)
 | 
			
		||||
         */
 | 
			
		||||
        private static int rollDice() {
 | 
			
		||||
            return random.nextInt(6) + 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rolls two dice and returns a list with the results.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a List of two integers representing the dice roll results
 | 
			
		||||
     */
 | 
			
		||||
    DiceResult rollDice() {
 | 
			
		||||
        return state.rollDice();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A interface representing the PlayerStates
 | 
			
		||||
     */
 | 
			
		||||
    private interface PlayerState {
 | 
			
		||||
        /**
 | 
			
		||||
         * Handles the logic for rolling Dice
 | 
			
		||||
         * @return the {@link DiceResult} of this the DiceRoll
 | 
			
		||||
         */
 | 
			
		||||
        DiceResult rollDice();
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Handles the logic for paying the Jail Bail
 | 
			
		||||
         */
 | 
			
		||||
        void payBail();
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Handles the action of using a GetOutOfJail Card
 | 
			
		||||
         */
 | 
			
		||||
        void useJailCard();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Class to represent the Active PlayerState
 | 
			
		||||
     * This class is set when it is the Players turn to do actions
 | 
			
		||||
     */
 | 
			
		||||
    private class ActiveState implements PlayerState {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public DiceResult rollDice() {
 | 
			
		||||
            List<Integer> roll = List.of(Dice.rollDice(), Dice.rollDice());
 | 
			
		||||
            rollResult = new DiceResult(roll);
 | 
			
		||||
            return rollResult;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void payBail() {
 | 
			
		||||
            // do nothing
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void useJailCard() {
 | 
			
		||||
            // do nothings
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A class to represent the Lobby PlayerState
 | 
			
		||||
     * Set when in Lobby
 | 
			
		||||
     */
 | 
			
		||||
    private class LobbyState implements PlayerState{
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public DiceResult rollDice() {
 | 
			
		||||
            //do nothing
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void payBail() {
 | 
			
		||||
            //do nothing
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void useJailCard() {
 | 
			
		||||
            // do nothing
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A class to represent the Jailed PlayerState
 | 
			
		||||
     * Set when in Gulag
 | 
			
		||||
     */
 | 
			
		||||
    private class JailState implements PlayerState {
 | 
			
		||||
 | 
			
		||||
        private int DoubletsCounter = 3;
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public DiceResult rollDice() {
 | 
			
		||||
            List<Integer> roll = List.of(Dice.rollDice(), Dice.rollDice());
 | 
			
		||||
            rollResult = new DiceResult(roll);
 | 
			
		||||
            if (rollResult.isDoublets()) {
 | 
			
		||||
                state = new ActiveState();
 | 
			
		||||
            } else if (DoubletsCounter == 0) {
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
                DoubletsCounter--;
 | 
			
		||||
            }
 | 
			
		||||
            return rollResult;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void payBail() {
 | 
			
		||||
            pay(500);
 | 
			
		||||
            state = new ActiveState();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void useJailCard() {
 | 
			
		||||
            getOutOfJailCard--;
 | 
			
		||||
            state = new ActiveState();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class BankruptState implements PlayerState {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public DiceResult rollDice() {
 | 
			
		||||
            // TODO Auto-generated method stub
 | 
			
		||||
            throw new UnsupportedOperationException("Unimplemented method 'rollDice'");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void payBail() {
 | 
			
		||||
            // TODO Auto-generated method stub
 | 
			
		||||
            throw new UnsupportedOperationException("Unimplemented method 'payBail'");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void useJailCard() {
 | 
			
		||||
            // TODO Auto-generated method stub
 | 
			
		||||
            throw new UnsupportedOperationException("Unimplemented method 'useJailCard'");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class WaitForTurnState implements PlayerState {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public DiceResult rollDice() {
 | 
			
		||||
            // TODO Auto-generated method stub
 | 
			
		||||
            throw new UnsupportedOperationException("Unimplemented method 'rollDice'");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void payBail() {
 | 
			
		||||
            // TODO Auto-generated method stub
 | 
			
		||||
            throw new UnsupportedOperationException("Unimplemented method 'payBail'");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void useJailCard() {
 | 
			
		||||
            // TODO Auto-generated method stub
 | 
			
		||||
            throw new UnsupportedOperationException("Unimplemented method 'useJailCard'");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Enum representing six distinct colors for players in the game.
 | 
			
		||||
 */
 | 
			
		||||
public enum PlayerColor {
 | 
			
		||||
    GREEN_LIGHT(new ColorRGBA(0 / 255f, 204 / 255f, 0 / 255f, 1)),   // Hex: 00cc00
 | 
			
		||||
    RED(new ColorRGBA(255 / 255f, 0 / 255f, 0 / 255f, 1)),           // Hex: ff0000
 | 
			
		||||
    BLUE(new ColorRGBA(0 / 255f, 0 / 255f, 204 / 255f, 1)),          // Hex: 0000cc
 | 
			
		||||
    PINK(new ColorRGBA(255 / 255f, 77 / 255f, 166 / 255f, 1)),       // Hex: ff4da6
 | 
			
		||||
    GREEN_DARK(new ColorRGBA(0 / 255f, 102 / 255f, 0 / 255f, 1)),    // Hex: 006600
 | 
			
		||||
    YELLOW(new ColorRGBA(255 / 255f, 255 / 255f, 0 / 255f, 1));      // Hex: ffff00
 | 
			
		||||
 | 
			
		||||
    private final ColorRGBA color;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a PlayerColor with the specified ColorRGBA value.
 | 
			
		||||
     *
 | 
			
		||||
     * @param color the ColorRGBA value associated with the player color
 | 
			
		||||
     */
 | 
			
		||||
    PlayerColor(ColorRGBA color) {
 | 
			
		||||
        this.color = color;
 | 
			
		||||
    } 
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the ColorRGBA value of the player color.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the ColorRGBA value
 | 
			
		||||
     */
 | 
			
		||||
    public ColorRGBA getColor() {
 | 
			
		||||
        return color;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,137 +0,0 @@
 | 
			
		||||
package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.NoSuchElementException;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
/**
 | 
			
		||||
 * A class for helping with player actions and managing thier turns
 | 
			
		||||
 */
 | 
			
		||||
public class PlayerHandler {
 | 
			
		||||
    private List<Player> players = new LinkedList<>();
 | 
			
		||||
    private Set<Player> readyPlayers = new HashSet<>();
 | 
			
		||||
    private ServerGameLogic logic;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Contructs a PlayerHandler
 | 
			
		||||
     * @param logic the {@link ServerGameLogic} this PlayerHandler is a part of
 | 
			
		||||
     */
 | 
			
		||||
    PlayerHandler(ServerGameLogic logic) {
 | 
			
		||||
        this.logic = logic;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Contructs a PlayerHandler
 | 
			
		||||
     * @param logic the {@link ServerGameLogic} this PlayerHandler is a part of
 | 
			
		||||
     * @param p1 a Player to be added
 | 
			
		||||
     */
 | 
			
		||||
    PlayerHandler(ServerGameLogic logic, Player p1) {
 | 
			
		||||
        this(logic);
 | 
			
		||||
        players.add(p1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Contructs a PlayerHandler
 | 
			
		||||
     * @param logic the {@link ServerGameLogic} this PlayerHandler is a part of
 | 
			
		||||
     * @param players a Collection of Players to be added
 | 
			
		||||
     */
 | 
			
		||||
    PlayerHandler(ServerGameLogic logic, Collection<Player> players) {
 | 
			
		||||
        this(logic);
 | 
			
		||||
        players.addAll(players);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of players
 | 
			
		||||
     * @return number of players in the game
 | 
			
		||||
     */
 | 
			
		||||
    public int getPlayerCount() {
 | 
			
		||||
        return players.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Chechs if all players are ready to start the game
 | 
			
		||||
     * @return {@code true} if all players are ready, otherwise {@code false}
 | 
			
		||||
     */
 | 
			
		||||
    public boolean allPlayersReady() {
 | 
			
		||||
        if (readyPlayers.size() == players.size()) return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a players Ready status
 | 
			
		||||
     * @param player the player to alter
 | 
			
		||||
     * @param ready the new Status
 | 
			
		||||
     */
 | 
			
		||||
    void setPlayerReady(Player player, boolean ready) {
 | 
			
		||||
        if (!players.contains(player)) {
 | 
			
		||||
            throw new IllegalArgumentException("Player does not belong to this PlayerHandler");
 | 
			
		||||
        } else {
 | 
			
		||||
            if (ready) {
 | 
			
		||||
                readyPlayers.add(player);
 | 
			
		||||
            } else {
 | 
			
		||||
                readyPlayers.remove(player);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a player to the Queue
 | 
			
		||||
     * @param player the player to be added to the queue
 | 
			
		||||
     */
 | 
			
		||||
    void addPlayer(Player player) {
 | 
			
		||||
        if (players.contains(player)) {
 | 
			
		||||
            throw new IllegalArgumentException("Player already registered");
 | 
			
		||||
        }
 | 
			
		||||
        players.add(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes the specified Player from the Queue
 | 
			
		||||
     * @param player the player to be removed
 | 
			
		||||
     */
 | 
			
		||||
    void removePlayer(Player player) {
 | 
			
		||||
        players.remove(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets Player based on their id in the Queue
 | 
			
		||||
     * @param index the index of the queue
 | 
			
		||||
     * @return the Player at the required index
 | 
			
		||||
     */
 | 
			
		||||
    Player getPlayerAtIndex(int index) {
 | 
			
		||||
        return players.get(index);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Completes a player turn and return the next player
 | 
			
		||||
     * @return the next players who is active
 | 
			
		||||
     */
 | 
			
		||||
    Player nextPlayer() {
 | 
			
		||||
        Player tmp = players.get(0);
 | 
			
		||||
        players.remove(0);
 | 
			
		||||
        players.add(tmp);
 | 
			
		||||
        return players.get(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the {@link ServerGameLogic} of this PlayerHandler
 | 
			
		||||
     * @return the {@link ServerGameLogic} of this PlayerHandler
 | 
			
		||||
     */
 | 
			
		||||
    ServerGameLogic getLogic() {
 | 
			
		||||
        return logic;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a player based on their id
 | 
			
		||||
     * @param id the id to be searched for
 | 
			
		||||
     * @return the player with the required id
 | 
			
		||||
     */
 | 
			
		||||
    Player getPlayerById(int id) {
 | 
			
		||||
        for (Player player : players) {
 | 
			
		||||
            if (player.getId() == id) return player;
 | 
			
		||||
        }
 | 
			
		||||
        throw new NoSuchElementException("Player mit id "+id+" existiert nicht");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,259 +0,0 @@
 | 
			
		||||
package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.MonopolyConfig;
 | 
			
		||||
import pp.monopoly.message.client.*;
 | 
			
		||||
import pp.monopoly.message.server.ServerMessage;
 | 
			
		||||
import pp.monopoly.message.server.TradeReply;
 | 
			
		||||
import pp.monopoly.message.server.TradeRequest;
 | 
			
		||||
import pp.monopoly.message.server.ViewAssetsResponse;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.MonopolyConfig;
 | 
			
		||||
import pp.monopoly.message.client.ClientInterpreter;
 | 
			
		||||
import pp.monopoly.message.server.ServerMessage;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Controls the server-side game logic for Monopoly.
 | 
			
		||||
 * Manages game states, player interactions, and message handling.
 | 
			
		||||
 */
 | 
			
		||||
public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(ServerGameLogic.class.getName());
 | 
			
		||||
 | 
			
		||||
    private final MonopolyConfig config;
 | 
			
		||||
    private final PlayerHandler playerHandler = new PlayerHandler(this);
 | 
			
		||||
    private final ServerSender serverSender;
 | 
			
		||||
    private ServerState state = ServerState.CREATEGAME;
 | 
			
		||||
    private static final int MAX_PLAYERS = 6;
 | 
			
		||||
    private BoardManager boardManager = new BoardManager();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a ServerGameLogic instance with the specified sender and configuration.
 | 
			
		||||
     *
 | 
			
		||||
     * @param serverSender the sender used to send messages to clients
 | 
			
		||||
     * @param config       the game configuration
 | 
			
		||||
     */
 | 
			
		||||
    public ServerGameLogic(ServerSender serverSender, MonopolyConfig config) {
 | 
			
		||||
        this.serverSender = serverSender;
 | 
			
		||||
        this.config = config;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the current state of the game.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the current ServerState
 | 
			
		||||
     */
 | 
			
		||||
    ServerState getState() {
 | 
			
		||||
        return state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a new state for the game and logs the state transition.
 | 
			
		||||
     *
 | 
			
		||||
     * @param newState the new ServerState to transition to
 | 
			
		||||
     */
 | 
			
		||||
    void setState(ServerState newState) {
 | 
			
		||||
        LOGGER.log(Level.DEBUG, "State transition {0} --> {1}", state, newState);
 | 
			
		||||
        state = newState;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sends a message to a specified player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param player the Player to whom the message is sent
 | 
			
		||||
     * @param msg    the ServerMessage to send
 | 
			
		||||
     */
 | 
			
		||||
    void send(Player player, ServerMessage msg) {
 | 
			
		||||
        if (player != null && msg != null) {
 | 
			
		||||
            serverSender.send(player.getId(), msg);
 | 
			
		||||
            LOGGER.log(Level.DEBUG, "Message sent to player {0}: {1}", player.getName(), msg.getClass().getSimpleName());
 | 
			
		||||
        } else {
 | 
			
		||||
            LOGGER.log(Level.WARNING, "Attempted to send a null message or to a null player");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a new player to the game if the game is in the LOBBY state and the maximum
 | 
			
		||||
     * player limit has not been reached.
 | 
			
		||||
     *
 | 
			
		||||
     * @param player the Player to add to the game
 | 
			
		||||
     * @return the added Player, or null if the player could not be added
 | 
			
		||||
     */
 | 
			
		||||
    public Player addPlayer(Player player) {
 | 
			
		||||
        if (state != ServerState.LOBBY) {
 | 
			
		||||
            LOGGER.log(Level.WARNING, "Cannot add player; game is not in LOBBY state.");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (playerHandler.getPlayerCount() >= MAX_PLAYERS) {
 | 
			
		||||
            LOGGER.log(Level.WARNING, "Cannot add player; maximum player limit reached.");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        playerHandler.addPlayer(player);
 | 
			
		||||
        LOGGER.log(Level.DEBUG, "Player added: {0}", player.getId());
 | 
			
		||||
 | 
			
		||||
        return player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds a new player to the game if the game is in the LOBBY state and the maximum
 | 
			
		||||
     * player limit has not been reached.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id the id of the player to add to the game
 | 
			
		||||
     * @return the added Player, or null if the player could not be added
 | 
			
		||||
     */
 | 
			
		||||
    public Player addPlayer(int id) {
 | 
			
		||||
        Player player = new Player(id, playerHandler);
 | 
			
		||||
        if (state != ServerState.LOBBY) {
 | 
			
		||||
            LOGGER.log(Level.WARNING, "Cannot add player; game is not in LOBBY state.");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (playerHandler.getPlayerCount() >= MAX_PLAYERS) {
 | 
			
		||||
            LOGGER.log(Level.WARNING, "Cannot add player; maximum player limit reached.");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        playerHandler.addPlayer(player);
 | 
			
		||||
        LOGGER.log(Level.DEBUG, "Player added: {0}", player.getId());
 | 
			
		||||
 | 
			
		||||
        return player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a BuyPropertyRequest from a player, allowing the player to purchase a property
 | 
			
		||||
     * if it is unowned and they have sufficient funds.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the BuyPropertyRequest received from the player
 | 
			
		||||
     * @param from the connection ID of the player who sent the request
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(BuyPropertyRequest msg, int from) {
 | 
			
		||||
        Player player = playerHandler.getPlayerById(from);
 | 
			
		||||
        if (player != null && state == ServerState.INGAME) {
 | 
			
		||||
            PropertyField property = (PropertyField) boardManager.getFieldAtIndex(player.move(0)); // Assuming player position for property
 | 
			
		||||
            
 | 
			
		||||
            if (property.getOwner() == null && player.getAccountBalance() >= property.getPrice()) {
 | 
			
		||||
                player.buyProperty(property);
 | 
			
		||||
                property.setOwner(player);
 | 
			
		||||
                player.earnMoney(-property.getPrice());
 | 
			
		||||
                LOGGER.log(Level.INFO, "Player {0} bought property {1}", player.getName(), property.getName());
 | 
			
		||||
            } else {
 | 
			
		||||
                LOGGER.log(Level.WARNING, "Player {0} cannot buy property {1}", player.getName(), property.getName());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles an EndTurn request, ending the player's turn and advancing to the next player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the EndTurn message received from the player
 | 
			
		||||
     * @param from the connection ID of the player who sent the request
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(EndTurn msg, int from) {
 | 
			
		||||
        Player player = playerHandler.getPlayerById(from);
 | 
			
		||||
        if (player != null && state == ServerState.INGAME) {
 | 
			
		||||
            LOGGER.log(Level.DEBUG, "Ending turn for player {0}", player.getName());
 | 
			
		||||
            playerHandler.nextPlayer();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a PlayerReady message, marking the player as ready.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the PlayerReady message received from the player
 | 
			
		||||
     * @param from the connection ID of the player who sent the request
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(PlayerReady msg, int from) {
 | 
			
		||||
        Player player = playerHandler.getPlayerById(from);
 | 
			
		||||
        if (player != null) {
 | 
			
		||||
            player.setName(msg.getName());
 | 
			
		||||
            player.setColor(msg.getColor());
 | 
			
		||||
            player.setName(msg.getName());
 | 
			
		||||
            LOGGER.log(Level.DEBUG, "Player {0} is ready", player.getName());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a RollDice message, rolling dice for the player and moving them on the board.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the RollDice message received from the player
 | 
			
		||||
     * @param from the connection ID of the player who sent the request
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(RollDice msg, int from) {
 | 
			
		||||
        Player player = playerHandler.getPlayerById(from);
 | 
			
		||||
        if (player != null && state == ServerState.INGAME) {
 | 
			
		||||
            send(player, player.rollDice());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a TradeOffer message by forwarding the trade offer to the receiving player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the TradeOffer message received from the initiating player
 | 
			
		||||
     * @param from the connection ID of the player who sent the offer
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TradeOffer msg, int from) {
 | 
			
		||||
        Player sender = playerHandler.getPlayerById(from);
 | 
			
		||||
        Player receiver = playerHandler.getPlayerById(msg.getReceiverId());
 | 
			
		||||
        
 | 
			
		||||
        if (sender != null && receiver != null) {
 | 
			
		||||
            LOGGER.log(Level.INFO, "Player {0} offers a trade to player {1}", sender.getName(), receiver.getName());
 | 
			
		||||
            send(playerHandler.getPlayerById(msg.getReceiverId()), new TradeRequest(msg.getReceiverId(), msg.getTradeHandler()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a TradeResponse message by forwarding the response back to the initiating player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the TradeResponse message received from the receiving player
 | 
			
		||||
     * @param from the connection ID of the player who sent the response
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(TradeResponse msg, int from) {
 | 
			
		||||
        Player responder = playerHandler.getPlayerById(from);
 | 
			
		||||
        Player initiator = playerHandler.getPlayerById(msg.getInitiatorId());
 | 
			
		||||
        
 | 
			
		||||
        if (responder != null && initiator != null) {
 | 
			
		||||
            LOGGER.log(Level.INFO, "Player {0} responded to trade with player {1}", responder.getName(), initiator.getName());
 | 
			
		||||
            send(initiator, new TradeReply(msg.getInitiatorId(), msg.getTradeHandler()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a ViewAssetsRequest message, sending the player a response containing their assets.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the ViewAssetsRequest message received from the player
 | 
			
		||||
     * @param from the connection ID of the player who sent the request
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(ViewAssetsRequest msg, int from) {
 | 
			
		||||
        Player player = playerHandler.getPlayerById(from);
 | 
			
		||||
        if (player != null) {
 | 
			
		||||
            LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", player.getName());
 | 
			
		||||
            
 | 
			
		||||
            send(player, new ViewAssetsResponse(player.getProperties(), player.getAccountBalance(), player.getNumJailCard()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the board manager, which manages the game board.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the BoardManager instance managing the game board
 | 
			
		||||
     */
 | 
			
		||||
    public BoardManager getBoardManager() {
 | 
			
		||||
        return boardManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Player getPlayerById(int id) {
 | 
			
		||||
        return playerHandler.getPlayerById(id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.message.server.ServerMessage;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface for sending messages to a client.
 | 
			
		||||
 */
 | 
			
		||||
public interface ServerSender {
 | 
			
		||||
    /**
 | 
			
		||||
     * Send the specified message to the client.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id      the id of the client that shall receive the message
 | 
			
		||||
     * @param message the message
 | 
			
		||||
     */
 | 
			
		||||
    void send(int id, ServerMessage message);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.game.server;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the different states of the Monopoly server during the game lifecycle.
 | 
			
		||||
 */
 | 
			
		||||
enum ServerState {
 | 
			
		||||
    /**
 | 
			
		||||
     * The server is waiting for clients to connect.
 | 
			
		||||
     */
 | 
			
		||||
    CREATEGAME,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The server is waiting for clients to set up their status to ready
 | 
			
		||||
     */
 | 
			
		||||
    LOBBY,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The battle of the game where players take turns
 | 
			
		||||
     */
 | 
			
		||||
    INGAME,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The game has ended because all the players went bankrupt
 | 
			
		||||
     */
 | 
			
		||||
    GAMEOVER
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a request from a player to buy a property.
 | 
			
		||||
 */
 | 
			
		||||
public class BuyPropertyRequest extends ClientMessage{
 | 
			
		||||
    private int propertyId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a BuyPropertyRequest with the specified property ID.
 | 
			
		||||
     *
 | 
			
		||||
     * @param propertyId the ID of the property to buy
 | 
			
		||||
     */
 | 
			
		||||
    public BuyPropertyRequest(int propertyId) {
 | 
			
		||||
        this.propertyId = propertyId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the ID of the property to buy.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the property ID
 | 
			
		||||
     */
 | 
			
		||||
    public int getPropertyId() {
 | 
			
		||||
        return propertyId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,69 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Visitor interface for processing all client messages.
 | 
			
		||||
 */
 | 
			
		||||
public interface ClientInterpreter {
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received BuyPropertyRequest.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the BuyPropertyRequest to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(BuyPropertyRequest msg, int from);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received EndTurn.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the EndTurn to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(EndTurn msg, int from);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received PlayerReady.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the PlayerReady to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(PlayerReady msg, int from);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received RollDice.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the RollDice to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(RollDice msg, int from);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received TradeOffer.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the TradeOffer to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(TradeOffer msg, int from);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received TradeResponse.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the TradeResponse to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(TradeResponse msg, int from);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Processes a received ViewAssetsRequest.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg  the ViewAssetsRequest to be processed
 | 
			
		||||
     * @param from the connection ID from which the message was received
 | 
			
		||||
     */
 | 
			
		||||
    void received(ViewAssetsRequest msg, int from);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.AbstractMessage;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An abstract base class for client messages used in network transfer.
 | 
			
		||||
 * It extends the AbstractMessage class provided by the jme3-network library.
 | 
			
		||||
 */
 | 
			
		||||
public abstract class ClientMessage extends AbstractMessage {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new ClientMessage instance.
 | 
			
		||||
     */
 | 
			
		||||
    protected ClientMessage() {
 | 
			
		||||
        super(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Accepts a visitor for processing this message.
 | 
			
		||||
     *
 | 
			
		||||
     * @param interpreter the visitor to be used for processing
 | 
			
		||||
     * @param from        the connection ID of the sender
 | 
			
		||||
     */
 | 
			
		||||
    public abstract void accept(ClientInterpreter interpreter, int from);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a message indicating the player wants to end their turn.
 | 
			
		||||
 */
 | 
			
		||||
public class EndTurn extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,52 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.PlayerColor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a message indicating the player is ready to play.
 | 
			
		||||
 */
 | 
			
		||||
public class PlayerReady extends ClientMessage{
 | 
			
		||||
    private boolean isReady;
 | 
			
		||||
    private String name;
 | 
			
		||||
    private PlayerColor color;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a PlayerReady message.
 | 
			
		||||
     *
 | 
			
		||||
     * @param isReady true if the player is ready, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public PlayerReady(boolean isReady) {
 | 
			
		||||
        this.isReady = isReady;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Getter for the Name
 | 
			
		||||
     * @return the Name
 | 
			
		||||
     */
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Getter for the Playercolor
 | 
			
		||||
     * @return the Playercolor
 | 
			
		||||
     */
 | 
			
		||||
    public PlayerColor getColor() {
 | 
			
		||||
        return color;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the player is ready.
 | 
			
		||||
     *
 | 
			
		||||
     * @return true if ready, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isReady() {
 | 
			
		||||
        return isReady;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a message requesting to roll the dice.
 | 
			
		||||
 */
 | 
			
		||||
public class RollDice extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a trade Request message from one player to another.
 | 
			
		||||
 */
 | 
			
		||||
public class TradeOffer extends ClientMessage{
 | 
			
		||||
    private int receiverId;
 | 
			
		||||
    private TradeHandler tradehandler;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeOffer with the specified details.
 | 
			
		||||
     *
 | 
			
		||||
     * @param receiverId the ID of the player receiving the Request
 | 
			
		||||
     * @param tradehandler the tradehandler
 | 
			
		||||
     */
 | 
			
		||||
    public TradeOffer(int receiverId, TradeHandler tradehandler) {
 | 
			
		||||
        this.receiverId = receiverId;
 | 
			
		||||
        this.tradehandler = tradehandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getReceiverId() { return receiverId; }
 | 
			
		||||
    public TradeHandler getTradeHandler() { return tradehandler; }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a response to a trade offer.
 | 
			
		||||
 */
 | 
			
		||||
public class TradeResponse extends ClientMessage{
 | 
			
		||||
    private int initiatorId;
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeResponse with the specified response details.
 | 
			
		||||
     *
 | 
			
		||||
     * @param initiatorId the ID of the player who initiated the trade
 | 
			
		||||
     * @param accepted true if the offer is accepted, false if declined
 | 
			
		||||
     */
 | 
			
		||||
    public TradeResponse(int initiatorId, TradeHandler tradeHandler) {
 | 
			
		||||
        this.initiatorId = initiatorId;
 | 
			
		||||
        this.tradeHandler = tradeHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getInitiatorId() { return initiatorId; }
 | 
			
		||||
    public TradeHandler getTradeHandler() {
 | 
			
		||||
        return tradeHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a request from a player to view their assets.
 | 
			
		||||
 */
 | 
			
		||||
public class ViewAssetsRequest extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the server's response to a player's request to buy a property.
 | 
			
		||||
 */
 | 
			
		||||
public class BuyPropertyResponse extends ServerMessage{
 | 
			
		||||
    private final boolean successful;
 | 
			
		||||
    private final String propertyName;
 | 
			
		||||
    private final String reason; // Reason for failure, if any
 | 
			
		||||
 | 
			
		||||
    public BuyPropertyResponse(boolean successful, String propertyName, String reason) {
 | 
			
		||||
        this.successful = successful;
 | 
			
		||||
        this.propertyName = propertyName;
 | 
			
		||||
        this.reason = reason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isSuccessful() {
 | 
			
		||||
        return successful;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getPropertyName() {
 | 
			
		||||
        return propertyName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getReason() {
 | 
			
		||||
        return reason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class DiceResult extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private List<Integer> rollResult;
 | 
			
		||||
 | 
			
		||||
    public DiceResult(List<Integer> rollResult) {
 | 
			
		||||
        this.rollResult = rollResult;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<Integer> getRollResult() {
 | 
			
		||||
        return rollResult;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isDoublets() {
 | 
			
		||||
        return rollResult.get(0) == rollResult.get(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int calcTotal() {
 | 
			
		||||
        return rollResult.get(0)+rollResult.get(1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,25 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
public class EventDrawCard extends ServerMessage{
 | 
			
		||||
    private final String cardDescription;
 | 
			
		||||
 | 
			
		||||
    public EventDrawCard(String cardDescription) {
 | 
			
		||||
        this.cardDescription = cardDescription;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getCardDescription() {
 | 
			
		||||
        return cardDescription;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,25 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
public class GameOver extends ServerMessage{
 | 
			
		||||
    private final boolean isWinner;
 | 
			
		||||
 | 
			
		||||
    public GameOver(boolean isWinner) {
 | 
			
		||||
        this.isWinner = isWinner;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isWinner() {
 | 
			
		||||
        return isWinner;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,16 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
public class GameStart extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
public class JailEvent extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final boolean goingToJail;
 | 
			
		||||
 | 
			
		||||
    public JailEvent(boolean goingToJail) {
 | 
			
		||||
        this.goingToJail = goingToJail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isGoingToJail() {
 | 
			
		||||
        return goingToJail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.PlayerColor;
 | 
			
		||||
 | 
			
		||||
public class PlayerStatusUpdate extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final String playerName;
 | 
			
		||||
    private final String status;
 | 
			
		||||
    private final PlayerColor color;
 | 
			
		||||
 | 
			
		||||
    public PlayerStatusUpdate(String playerName, String status, PlayerColor color) {
 | 
			
		||||
        this.playerName = playerName;
 | 
			
		||||
        this.status = status;
 | 
			
		||||
        this.color = color;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getPlayerName() {
 | 
			
		||||
        return playerName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getStatus() {
 | 
			
		||||
        return status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public PlayerColor getColor() {
 | 
			
		||||
        return color;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,92 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An interface for processing server messages.
 | 
			
		||||
 * Implementations of this interface can be used to handle different types of server messages.
 | 
			
		||||
 */
 | 
			
		||||
public interface ServerInterpreter {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a BuyPropertyResponse message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the BuyPropertyResponse message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(BuyPropertyResponse msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a DiceResult message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the DiceResult message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(DiceResult msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a EventDrawCard message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the EventDrawCard message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(EventDrawCard msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a GameOver message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the GameOver message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(GameOver msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a GameStart message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the GameStart message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(GameStart msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a JailEvent message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the JailEvent message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(JailEvent msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a PlayerStatusUpdate message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the PlayerStatusUpdate message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(PlayerStatusUpdate msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a TimeOutWarning message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the TimeOutWarning message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(TimeOutWarning msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a ViewAssetsResponse message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the ViewAssetsResponse message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(ViewAssetsResponse msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a TradeReply message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the TradeReply message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(TradeReply msg);
 | 
			
		||||
            
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a TradeRequest message received from the server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the TradeRequest message received
 | 
			
		||||
     */
 | 
			
		||||
    void received(TradeRequest msg);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.AbstractMessage;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An abstract base class for server messages used in network transfer.
 | 
			
		||||
 * It extends the AbstractMessage class provided by the jme3-network library.
 | 
			
		||||
 */
 | 
			
		||||
public abstract class ServerMessage extends AbstractMessage {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new ServerMessage instance.
 | 
			
		||||
     */
 | 
			
		||||
    protected ServerMessage() {
 | 
			
		||||
        super(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Accepts a visitor for processing this message.
 | 
			
		||||
     *
 | 
			
		||||
     * @param interpreter the visitor to be used for processing
 | 
			
		||||
     */
 | 
			
		||||
    public abstract void accept(ServerInterpreter interpreter);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the bundle key of the informational text to be shown at the client.
 | 
			
		||||
     * This key is used to retrieve the appropriate localized text for display.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the bundle key of the informational text
 | 
			
		||||
     */
 | 
			
		||||
    public abstract String getInfoTextKey();
 | 
			
		||||
}
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
public class TimeOutWarning extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final int remainingTime;
 | 
			
		||||
 | 
			
		||||
    public TimeOutWarning(int remainingTime) {
 | 
			
		||||
        this.remainingTime = remainingTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getRemainingTime() {
 | 
			
		||||
        return remainingTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a response to a trade offer.
 | 
			
		||||
 */
 | 
			
		||||
public class TradeReply extends ServerMessage{
 | 
			
		||||
    private int initiatorId;
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeResponse with the specified response details.
 | 
			
		||||
     *
 | 
			
		||||
     * @param initiatorId the ID of the player who initiated the trade
 | 
			
		||||
     * @param accepted true if the offer is accepted, false if declined
 | 
			
		||||
     */
 | 
			
		||||
    public TradeReply(int initiatorId, TradeHandler tradeHandler) {
 | 
			
		||||
        this.initiatorId = initiatorId;
 | 
			
		||||
        this.tradeHandler = tradeHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getInitiatorId() { return initiatorId; }
 | 
			
		||||
    public TradeHandler getTradeHandler() {
 | 
			
		||||
        return tradeHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a trade Request message from one player to another.
 | 
			
		||||
 */
 | 
			
		||||
public class TradeRequest extends ServerMessage{
 | 
			
		||||
    private int receiverId;
 | 
			
		||||
    private TradeHandler tradehandler;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeRequest with the specified details.
 | 
			
		||||
     *
 | 
			
		||||
     * @param receiverId the ID of the player receiving the Request
 | 
			
		||||
     * @param tradehandler the tradehandler
 | 
			
		||||
     */
 | 
			
		||||
    public TradeRequest(int receiverId, TradeHandler tradehandler) {
 | 
			
		||||
        this.receiverId = receiverId;
 | 
			
		||||
        this.tradehandler = tradehandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getReceiverId() { return receiverId; }
 | 
			
		||||
    public TradeHandler getTradeHandler() { return tradehandler; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,50 +0,0 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a response containing the player's assets.
 | 
			
		||||
 */
 | 
			
		||||
public class ViewAssetsResponse extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final List<PropertyField> properties;
 | 
			
		||||
    private final int accountBalance;
 | 
			
		||||
    private final int jailCards;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a ViewAssetsResponse with the specified properties and account balance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param properties    a List of PropertyField objects representing the player's properties
 | 
			
		||||
     * @param accountBalance the player's current account balance
 | 
			
		||||
     */
 | 
			
		||||
    public ViewAssetsResponse(List<PropertyField> properties, int accountBalance, int jailCards) {
 | 
			
		||||
        this.properties = properties;
 | 
			
		||||
        this.accountBalance = accountBalance;
 | 
			
		||||
        this.jailCards = jailCards;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ServerInterpreter interpreter) {
 | 
			
		||||
        interpreter.received(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getInfoTextKey() {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<PropertyField> getProperties() {
 | 
			
		||||
        return properties;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getAccountBalance() {
 | 
			
		||||
        return accountBalance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getJailCards() {
 | 
			
		||||
        return jailCards;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,169 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.notification.GameEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEventBroker;
 | 
			
		||||
import pp.monopoly.notification.ItemAddedEvent;
 | 
			
		||||
import pp.monopoly.notification.ItemRemovedEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a rectangular map that holds figures and registers houses, hotels
 | 
			
		||||
 * It also supports event notification for game state changes such as item addition or removal.
 | 
			
		||||
 * Valid positions on this map have x-coordinates in the range of 0 to width-1 and y-coordinates
 | 
			
		||||
 * in the range of 0 to height-1.
 | 
			
		||||
 *
 | 
			
		||||
 * @see #getWidth()
 | 
			
		||||
 * @see #getHeight()
 | 
			
		||||
 */
 | 
			
		||||
public class Board {
 | 
			
		||||
    /**
 | 
			
		||||
     * A list of items (figure, house, etc.) placed on the map.
 | 
			
		||||
     */
 | 
			
		||||
    private final List<Item> items = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The broker responsible for notifying registered listeners of events
 | 
			
		||||
     * (such as when an item is added or removed from the map).
 | 
			
		||||
     * Can be null, in which case no notifications will be sent.
 | 
			
		||||
     */
 | 
			
		||||
    private final GameEventBroker eventBroker;
 | 
			
		||||
 | 
			
		||||
    private final int width;
 | 
			
		||||
    private final int height;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs an empty map with the given dimensions. The specified event broker
 | 
			
		||||
     * will handle the notification of changes in the map state, such as adding or removing items.
 | 
			
		||||
     * Passing null as the event broker is allowed, but in that case, no notifications will occur.
 | 
			
		||||
     *
 | 
			
		||||
     * @param width       the number of columns (width) of the map
 | 
			
		||||
     * @param height      the number of rows (height) of the map
 | 
			
		||||
     * @param eventBroker the event broker used for notifying listeners, or null if event distribution is not needed
 | 
			
		||||
     */
 | 
			
		||||
    public Board(int width, int height, GameEventBroker eventBroker) {
 | 
			
		||||
        if (width < 1 || height < 1)
 | 
			
		||||
            throw new IllegalArgumentException("Invalid map size");
 | 
			
		||||
        this.width = width;
 | 
			
		||||
        this.height = height;
 | 
			
		||||
        this.eventBroker = eventBroker;
 | 
			
		||||
        addItem(new Figure(5, 5, 5, Rotation.LEFT));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds an item (e.g., a figure or a house) to the map and triggers the appropriate event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param item the item to be added to the map
 | 
			
		||||
     */
 | 
			
		||||
    private void addItem(Item item) {
 | 
			
		||||
        items.add(item);
 | 
			
		||||
        notifyListeners((GameEvent) new ItemAddedEvent(item, null));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes an item from the map and triggers an item removal event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param item the item to be removed from the map
 | 
			
		||||
     */
 | 
			
		||||
    public void remove(Item item) {
 | 
			
		||||
        items.remove(item);
 | 
			
		||||
        notifyListeners((GameEvent) new ItemRemovedEvent(item, null)); // Falls es ein entsprechendes ItemRemovedEvent gibt
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Removes all items from the map and triggers corresponding removal events for each.
 | 
			
		||||
     */
 | 
			
		||||
    public void clear() {
 | 
			
		||||
        new ArrayList<>(items).forEach(this::remove);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a stream of items of a specified type (class).
 | 
			
		||||
     *
 | 
			
		||||
     * @param clazz the class type to filter items by
 | 
			
		||||
     * @param <T>   the type of items to return
 | 
			
		||||
     * @return a stream of items matching the specified class type
 | 
			
		||||
     */
 | 
			
		||||
    private <T extends Item> Stream<T> getItems(Class<T> clazz) {
 | 
			
		||||
        return items.stream().filter(clazz::isInstance).map(clazz::cast);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns an unmodifiable list of all items currently on the map.
 | 
			
		||||
     *
 | 
			
		||||
     * @return an unmodifiable list of all items
 | 
			
		||||
     */
 | 
			
		||||
    public List<Item> getItems() {
 | 
			
		||||
        return Collections.unmodifiableList(items);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the width (number of columns) of the map.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the width of the map
 | 
			
		||||
     */
 | 
			
		||||
    public int getWidth() {
 | 
			
		||||
        return width;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the height (number of rows) of the map.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the height of the map
 | 
			
		||||
     */
 | 
			
		||||
    public int getHeight() {
 | 
			
		||||
        return height;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Validates whether the specified position is within the map boundaries.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos the position to validate
 | 
			
		||||
     * @return true if the position is within the map, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isValid(IntPosition pos) {
 | 
			
		||||
        return isValid(pos.getX(), pos.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the specified coordinates are within the map boundaries.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x the x-coordinate to validate
 | 
			
		||||
     * @param y the y-coordinate to validate
 | 
			
		||||
     * @return true if the coordinates are valid, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isValid(int x, int y) {
 | 
			
		||||
        return x >= 0 && x < width &&
 | 
			
		||||
               y >= 0 && y < height;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a string representation of the map.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a string representation of the map
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return "Board:{" + items + '}'; //NON-NLS
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Notifies all registered listeners about a game event if the event broker is available.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event the event to be distributed to listeners
 | 
			
		||||
     */
 | 
			
		||||
    private void notifyListeners(GameEvent event) {
 | 
			
		||||
        if (eventBroker != null)
 | 
			
		||||
            eventBroker.notifyListeners(event);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.card.Card;
 | 
			
		||||
 | 
			
		||||
public interface CardVisitor<T> {
 | 
			
		||||
    T visit(Card c);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
import pp.monopoly.model.fields.EventField;
 | 
			
		||||
import pp.monopoly.model.fields.FineField;
 | 
			
		||||
import pp.monopoly.model.fields.FoodField;
 | 
			
		||||
import pp.monopoly.model.fields.GateField;
 | 
			
		||||
import pp.monopoly.model.fields.GoField;
 | 
			
		||||
import pp.monopoly.model.fields.GulagField;
 | 
			
		||||
import pp.monopoly.model.fields.TestStreckeField;
 | 
			
		||||
import pp.monopoly.model.fields.WacheField;
 | 
			
		||||
 | 
			
		||||
public interface FieldVisitor<T> {
 | 
			
		||||
    T visit(BuildingProperty field);
 | 
			
		||||
    T visit(FoodField field);
 | 
			
		||||
    T visit(GateField field);
 | 
			
		||||
    T visit(GulagField field);
 | 
			
		||||
    T visit(TestStreckeField field);
 | 
			
		||||
    T visit(EventField field);
 | 
			
		||||
    T visit(WacheField field);
 | 
			
		||||
    T visit(GoField field);
 | 
			
		||||
    T visit(FineField field);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,309 +0,0 @@
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static java.lang.Math.max;
 | 
			
		||||
import static java.lang.Math.min;
 | 
			
		||||
 | 
			
		||||
public class Figure implements Item{
 | 
			
		||||
    /**
 | 
			
		||||
     * Enumeration representing the different statuses a Figure can have during the game.
 | 
			
		||||
     */
 | 
			
		||||
    public enum Status {
 | 
			
		||||
        /**
 | 
			
		||||
         * The ship is in its normal state, not being previewed for placement.
 | 
			
		||||
         */
 | 
			
		||||
        NORMAL,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The ship is being previewed in a valid position for placement.
 | 
			
		||||
         */
 | 
			
		||||
        VALID_PREVIEW,
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The ship is being previewed in an invalid position for placement.
 | 
			
		||||
         */
 | 
			
		||||
        INVALID_PREVIEW
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final int length; // The length of the Figure
 | 
			
		||||
    private int x;            // The x-coordinate of the Figure's position
 | 
			
		||||
    private int y;            // The y-coordinate of the Figure's position
 | 
			
		||||
    private Rotation rot;     // The rotation of the Figure
 | 
			
		||||
    private Status status;    // The current status of the Figure
 | 
			
		||||
    private final Set<IntPoint> damaged = new HashSet<>(); // The set of positions that have been hit on this ship
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization. Initializes a Figure with length 0,
 | 
			
		||||
     * at position (0, 0), with a default rotation of RIGHT.
 | 
			
		||||
     */
 | 
			
		||||
    private Figure() {
 | 
			
		||||
        this(0, 0, 0, Rotation.RIGHT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new Figure with the specified length, position, and rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @param length the length of the Figure
 | 
			
		||||
     * @param x      the x-coordinate of the Figure's initial position
 | 
			
		||||
     * @param y      the y-coordinate of the Figure's initial position
 | 
			
		||||
     * @param rot    the rotation of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public Figure(int length, int x, int y, Rotation rot) {
 | 
			
		||||
        this.x = x;
 | 
			
		||||
        this.y = y;
 | 
			
		||||
        this.rot = rot;
 | 
			
		||||
        this.length = length;
 | 
			
		||||
        this.status = Status.NORMAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current x-coordinate of the Figure's position.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the x-coordinate of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public int getX() {
 | 
			
		||||
        return x;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current y-coordinate of the Figure's position.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the y-coordinate of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public int getY() {
 | 
			
		||||
        return y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves the Figure to the specified coordinates.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x the new x-coordinate of the Figure's position
 | 
			
		||||
     * @param y the new y-coordinate of the Figure's position
 | 
			
		||||
     */
 | 
			
		||||
    public void moveTo(int x, int y) {
 | 
			
		||||
        this.x = x;
 | 
			
		||||
        this.y = y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves the Figure to the specified position.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos the new position of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public void moveTo(IntPosition pos) {
 | 
			
		||||
        moveTo(pos.getX(), pos.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current status of the Figure.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the status of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public Status getStatus() {
 | 
			
		||||
        return status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the status of the Figure.
 | 
			
		||||
     *
 | 
			
		||||
     * @param status the new status to be set for the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public void setStatus(Status status) {
 | 
			
		||||
        this.status = status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the length of the Figure.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the length of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public int getLength() {
 | 
			
		||||
        return length;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the minimum x-coordinate that the Figure occupies based on its current position and rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the minimum x-coordinate of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public int getMinX() {
 | 
			
		||||
        return x + min(0, (length - 1) * rot.dx());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the maximum x-coordinate that the Figure occupies based on its current position and rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the maximum x-coordinate of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public int getMaxX() {
 | 
			
		||||
        return x + max(0, (length - 1) * rot.dx());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the minimum y-coordinate that the Figure occupies based on its current position and rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the minimum y-coordinate of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public int getMinY() {
 | 
			
		||||
        return y + min(0, (length - 1) * rot.dy());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the maximum y-coordinate that the Figure occupies based on its current position and rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the maximum y-coordinate of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public int getMaxY() {
 | 
			
		||||
        return y + max(0, (length - 1) * rot.dy());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current rotation of the Figure.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the rotation of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public Rotation getRot() {
 | 
			
		||||
        return rot;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the rotation of the Figure.
 | 
			
		||||
     *
 | 
			
		||||
     * @param rot the new rotation to be set for the Figure
 | 
			
		||||
     */
 | 
			
		||||
    public void setRotation(Rotation rot) {
 | 
			
		||||
        this.rot = rot;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rotates the Figure by 90 degrees clockwise.
 | 
			
		||||
     */
 | 
			
		||||
    public void rotated() {
 | 
			
		||||
        setRotation(rot.rotate());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Attempts to hit the Figure at the specified position.
 | 
			
		||||
     * If the position is part of the Figure, the hit is recorded.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x the x-coordinate of the position to hit
 | 
			
		||||
     * @param y the y-coordinate of the position to hit
 | 
			
		||||
     * @return true if the position is part of the Figure, false otherwise
 | 
			
		||||
     * @see #contains(int, int)
 | 
			
		||||
     */
 | 
			
		||||
    public boolean hit(int x, int y) {
 | 
			
		||||
        if (!contains(x, y))
 | 
			
		||||
            return false;
 | 
			
		||||
        damaged.add(new IntPoint(x, y));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Attempts to hit the Figure at the specified position.
 | 
			
		||||
     * If the position is part of the Figure, the hit is recorded.
 | 
			
		||||
     * This is a convenience method for {@linkplain #hit(int, int)}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param position the position to hit
 | 
			
		||||
     * @return true if the position is part of the Figure, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean hit(IntPosition position) {
 | 
			
		||||
        return hit(position.getX(), position.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the positions of this Figure that have been hit.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a set of positions that have been hit
 | 
			
		||||
     * @see #hit(int, int)
 | 
			
		||||
     */
 | 
			
		||||
    public Set<IntPoint> getDamaged() {
 | 
			
		||||
        return Collections.unmodifiableSet(damaged);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the specified position is covered by the Figure. This method does
 | 
			
		||||
     * not record a hit, only checks coverage.
 | 
			
		||||
     * This is a convenience method for {@linkplain #contains(int, int)}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param pos the position to check
 | 
			
		||||
     * @return true if the position is covered by the Figure, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean contains(IntPosition pos) {
 | 
			
		||||
        return contains(pos.getX(), pos.getY());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the specified position is covered by the Figure. This method does
 | 
			
		||||
     * not record a hit, only checks coverage.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x the x-coordinate of the position to check
 | 
			
		||||
     * @param y the y-coordinate of the position to check
 | 
			
		||||
     * @return true if the position is covered by the Figure, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean contains(int x, int y) {
 | 
			
		||||
        return getMinX() <= x && x <= getMaxX() &&
 | 
			
		||||
               getMinY() <= y && y <= getMaxY();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determines if the Figure has been completely destroyed. A Figure is considered
 | 
			
		||||
     * destroyed if all of its positions have been hit.
 | 
			
		||||
     *
 | 
			
		||||
     * @return true if the Figure is destroyed, false otherwise
 | 
			
		||||
     * @see #hit(int, int)
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isDestroyed() {
 | 
			
		||||
        return damaged.size() == length;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether this Figure collides with another Figure. Two Figures collide
 | 
			
		||||
     * if any of their occupied positions overlap.
 | 
			
		||||
     *
 | 
			
		||||
     * @param other the other Figure to check collision with
 | 
			
		||||
     * @return true if the Figures collide, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean collidesWith(Figure other) {
 | 
			
		||||
        return other.getMaxX() >= getMinX() && getMaxX() >= other.getMinX() &&
 | 
			
		||||
               other.getMaxY() >= getMinY() && getMaxY() >= other.getMinY();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a string representation of the Figure, including its length, position,
 | 
			
		||||
     * and rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a string representation of the Figure
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return "Ship{length=" + length + ", x=" + x + ", y=" + y + ", rot=" + rot + '}';  //NON-NLS
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Accepts a visitor that returns a value of type {@code T}. This method is part of the
 | 
			
		||||
     * Visitor design pattern.
 | 
			
		||||
     *
 | 
			
		||||
     * @param visitor the visitor to accept
 | 
			
		||||
     * @param <T>     the type of the value returned by the visitor
 | 
			
		||||
     * @return the value returned by the visitor
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public <T> T accept(Visitor<T> visitor) {
 | 
			
		||||
        return visitor.visit(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Accepts a visitor that does not return a value. This method is part of the
 | 
			
		||||
     * Visitor design pattern.
 | 
			
		||||
     *
 | 
			
		||||
     * @param visitor the visitor to accept
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(VoidVisitor visitor) {
 | 
			
		||||
        visitor.visit(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,94 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a point in the two-dimensional plane with integer coordinates.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public final class IntPoint implements IntPosition {
 | 
			
		||||
    private int x;
 | 
			
		||||
    private int y;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private IntPoint() { /* do nothing */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new IntPoint with the specified coordinates.
 | 
			
		||||
     *
 | 
			
		||||
     * @param x the x-coordinate of the point
 | 
			
		||||
     * @param y the y-coordinate of the point
 | 
			
		||||
     */
 | 
			
		||||
    public IntPoint(int x, int y) {
 | 
			
		||||
        this.x = x;
 | 
			
		||||
        this.y = y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the x-coordinate of the point.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the x-coordinate
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getX() {
 | 
			
		||||
        return x;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the y-coordinate of the point.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the y-coordinate
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getY() {
 | 
			
		||||
        return y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Indicates whether some other object is "equal to" this one.
 | 
			
		||||
     *
 | 
			
		||||
     * @param obj the reference object with which to compare
 | 
			
		||||
     * @return true if this object is the same as the obj argument; false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object obj) {
 | 
			
		||||
        if (obj == this) return true;
 | 
			
		||||
        if (obj == null || obj.getClass() != this.getClass()) return false;
 | 
			
		||||
        var that = (IntPoint) obj;
 | 
			
		||||
        return this.x == that.x &&
 | 
			
		||||
               this.y == that.y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a hash code value for the IntPoint.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a hash code value for this object
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode() {
 | 
			
		||||
        return Objects.hash(x, y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a string representation of the IntPoint.
 | 
			
		||||
     *
 | 
			
		||||
     * @return a string representation of the object
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return "IntPoint[" + //NON-NLS
 | 
			
		||||
               "x=" + x + ", " + //NON-NLS
 | 
			
		||||
               "y=" + y + ']'; //NON-NLS
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface representing a position with X and Y coordinates.
 | 
			
		||||
 */
 | 
			
		||||
public interface IntPosition {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the X coordinate of this position.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the X coordinate.
 | 
			
		||||
     */
 | 
			
		||||
    int getX();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the Y coordinate of this position.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the Y coordinate.
 | 
			
		||||
     */
 | 
			
		||||
    int getY();
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An interface representing any item on a board
 | 
			
		||||
 * It extends the IntPosition interface to provide position information.
 | 
			
		||||
 */
 | 
			
		||||
public interface Item {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Accepts a visitor to perform operations on the item.
 | 
			
		||||
     *
 | 
			
		||||
     * @param visitor the visitor performing operations on the item
 | 
			
		||||
     * @param <T>     the type of result returned by the visitor
 | 
			
		||||
     * @return the result of the visitor's operation on the item
 | 
			
		||||
     */
 | 
			
		||||
    <T> T accept(Visitor<T> visitor);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Accepts a visitor to perform operations on the item without returning a result.
 | 
			
		||||
     *
 | 
			
		||||
     * @param visitor the visitor performing operations on the item
 | 
			
		||||
     */
 | 
			
		||||
    void accept(VoidVisitor visitor);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,67 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the rotation of a Item and provides functionality related to rotation.
 | 
			
		||||
 */
 | 
			
		||||
public enum Rotation implements Serializable {
 | 
			
		||||
    /**
 | 
			
		||||
     * Represents the item facing upwards.
 | 
			
		||||
     */
 | 
			
		||||
    UP,
 | 
			
		||||
    /**
 | 
			
		||||
     * Represents the item facing rightwards.
 | 
			
		||||
     */
 | 
			
		||||
    RIGHT,
 | 
			
		||||
    /**
 | 
			
		||||
     * Represents the item facing downwards.
 | 
			
		||||
     */
 | 
			
		||||
    DOWN,
 | 
			
		||||
    /**
 | 
			
		||||
     * Represents the item facing leftwards.
 | 
			
		||||
     */
 | 
			
		||||
    LEFT;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the change in x-coordinate corresponding to this rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the change in x-coordinate
 | 
			
		||||
     */
 | 
			
		||||
    public int dx() {
 | 
			
		||||
        return switch (this) {
 | 
			
		||||
            case UP, DOWN -> 0;
 | 
			
		||||
            case RIGHT -> 1;
 | 
			
		||||
            case LEFT -> -1;
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the change in y-coordinate corresponding to this rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the change in y-coordinate
 | 
			
		||||
     */
 | 
			
		||||
    public int dy() {
 | 
			
		||||
        return switch (this) {
 | 
			
		||||
            case UP -> 1;
 | 
			
		||||
            case LEFT, RIGHT -> 0;
 | 
			
		||||
            case DOWN -> -1;
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rotates the orientation clockwise and returns the next rotation.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the next rotation after rotating clockwise
 | 
			
		||||
     */
 | 
			
		||||
    public Rotation rotate() {
 | 
			
		||||
        return values()[(ordinal() + 1) % values().length];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,183 +0,0 @@
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper class that handles the trade logic between two players.
 | 
			
		||||
 * Manages trade initiation, validation, acceptance, and rejection involving multiple properties, money, and jail cards.
 | 
			
		||||
 */
 | 
			
		||||
public class TradeHandler {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initiates a trade offer between two players involving properties, money, and jail cards.
 | 
			
		||||
     *
 | 
			
		||||
     * @param sender             the Player who is initiating the trade
 | 
			
		||||
     * @param receiver           the Player who is the target of the trade offer
 | 
			
		||||
     * @param offeredAmount      the amount of money the sender offers
 | 
			
		||||
     * @param offeredProperties  the list of properties the sender offers
 | 
			
		||||
     * @param offeredJailCards   the number of jail cards the sender offers
 | 
			
		||||
     * @param requestedAmount    the amount of money the sender requests from the receiver
 | 
			
		||||
     * @param requestedProperties the list of properties the sender requests from the receiver
 | 
			
		||||
     * @param requestedJailCards the number of jail cards the sender requests from the receiver
 | 
			
		||||
     * @return true if the trade offer is valid and initiated, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public boolean initiateTrade(Player sender, Player receiver, int offeredAmount, List<PropertyField> offeredProperties,
 | 
			
		||||
                                 int offeredJailCards, int requestedAmount, List<PropertyField> requestedProperties, int requestedJailCards) {
 | 
			
		||||
        // Validate the trade offer
 | 
			
		||||
        if (!validateTrade(sender, offeredAmount, offeredProperties, offeredJailCards, receiver, requestedAmount, requestedProperties, requestedJailCards)) {
 | 
			
		||||
            System.out.println("Trade offer is invalid.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Notify the receiver about the trade offer (this would be an actual message in a real implementation)
 | 
			
		||||
        System.out.println("Trade offer initiated by " + sender.getName() + " to " + receiver.getName());
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Accepts the trade offer and completes the trade between two players.
 | 
			
		||||
     *
 | 
			
		||||
     * @param sender             the Player who initiated the trade
 | 
			
		||||
     * @param receiver           the Player who accepted the trade
 | 
			
		||||
     * @param offeredAmount      the amount of money to transfer from the sender to the receiver
 | 
			
		||||
     * @param offeredProperties  the list of properties to transfer from the sender to the receiver
 | 
			
		||||
     * @param offeredJailCards   the number of jail cards to transfer from the sender to the receiver
 | 
			
		||||
     * @param requestedAmount    the amount of money to transfer from the receiver to the sender
 | 
			
		||||
     * @param requestedProperties the list of properties to transfer from the receiver to the sender
 | 
			
		||||
     * @param requestedJailCards the number of jail cards to transfer from the receiver to the sender
 | 
			
		||||
     */
 | 
			
		||||
    public void acceptTrade(Player sender, Player receiver, int offeredAmount, List<PropertyField> offeredProperties,
 | 
			
		||||
                            int offeredJailCards, int requestedAmount, List<PropertyField> requestedProperties, int requestedJailCards) {
 | 
			
		||||
        // Transfer money
 | 
			
		||||
        sender.earnMoney(-offeredAmount);  // Deduct money from the sender
 | 
			
		||||
        receiver.earnMoney(offeredAmount); // Add money to the receiver
 | 
			
		||||
 | 
			
		||||
        receiver.earnMoney(-requestedAmount); // Deduct money from the receiver
 | 
			
		||||
        sender.earnMoney(requestedAmount);    // Add money to the sender
 | 
			
		||||
 | 
			
		||||
        // Transfer ownership of the properties from sender to receiver
 | 
			
		||||
        if (offeredProperties != null) {
 | 
			
		||||
            for (PropertyField property : offeredProperties) {
 | 
			
		||||
                transferProperty(sender, receiver, property);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Transfer ownership of the properties from receiver to sender
 | 
			
		||||
        if (requestedProperties != null) {
 | 
			
		||||
            for (PropertyField property : requestedProperties) {
 | 
			
		||||
                transferProperty(receiver, sender, property);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Transfer jail cards
 | 
			
		||||
        transferJailCards(sender, receiver, offeredJailCards);
 | 
			
		||||
        transferJailCards(receiver, sender, requestedJailCards);
 | 
			
		||||
 | 
			
		||||
        System.out.println("Trade accepted. " + sender.getName() + " and " + receiver.getName() + " completed the trade.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rejects the trade offer.
 | 
			
		||||
     *
 | 
			
		||||
     * @param receiver the Player who is rejecting the trade
 | 
			
		||||
     */
 | 
			
		||||
    public void rejectTrade(Player receiver) {
 | 
			
		||||
        System.out.println("Trade rejected by " + receiver.getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Validates a trade offer by checking if the sender and receiver own the properties involved,
 | 
			
		||||
     * have sufficient funds for the money involved in the trade, and have enough jail cards.
 | 
			
		||||
     *
 | 
			
		||||
     * @param sender             the Player initiating the trade
 | 
			
		||||
     * @param offeredAmount      the amount of money the sender is offering
 | 
			
		||||
     * @param offeredProperties  the list of properties the sender is offering
 | 
			
		||||
     * @param offeredJailCards   the number of jail cards the sender is offering
 | 
			
		||||
     * @param receiver           the Player receiving the trade offer
 | 
			
		||||
     * @param requestedAmount    the amount of money the sender is requesting
 | 
			
		||||
     * @param requestedProperties the list of properties the sender is requesting from the receiver
 | 
			
		||||
     * @param requestedJailCards the number of jail cards the sender is requesting from the receiver
 | 
			
		||||
     * @return true if the trade offer is valid, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    private boolean validateTrade(Player sender, int offeredAmount, List<PropertyField> offeredProperties, int offeredJailCards,
 | 
			
		||||
                                  Player receiver, int requestedAmount, List<PropertyField> requestedProperties, int requestedJailCards) {
 | 
			
		||||
        // Check if sender has enough money to offer
 | 
			
		||||
        if (sender.getAccountBalance() < offeredAmount) {
 | 
			
		||||
            System.out.println("Sender does not have enough balance to make this offer.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if receiver has enough money to offer
 | 
			
		||||
        if (receiver.getAccountBalance() < requestedAmount) {
 | 
			
		||||
            System.out.println("Receiver does not have enough balance to fulfill requested amount.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if sender owns all the offered properties
 | 
			
		||||
        if (offeredProperties != null) {
 | 
			
		||||
            for (PropertyField property : offeredProperties) {
 | 
			
		||||
                if (!sender.getProperties().contains(property)) {
 | 
			
		||||
                    System.out.println("Sender does not own the property " + property.getName() + " being offered.");
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if receiver owns all the requested properties
 | 
			
		||||
        if (requestedProperties != null) {
 | 
			
		||||
            for (PropertyField property : requestedProperties) {
 | 
			
		||||
                if (!receiver.getProperties().contains(property)) {
 | 
			
		||||
                    System.out.println("Receiver does not own the property " + property.getName() + " requested.");
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if sender has enough jail cards to offer
 | 
			
		||||
        if (sender.getNumJailCard() < offeredJailCards) {
 | 
			
		||||
            System.out.println("Sender does not have enough jail cards to offer.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if receiver has enough jail cards to fulfill the request
 | 
			
		||||
        if (receiver.getNumJailCard() < requestedJailCards) {
 | 
			
		||||
            System.out.println("Receiver does not have enough jail cards to fulfill the request.");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Transfers a property from one player to another.
 | 
			
		||||
     *
 | 
			
		||||
     * @param from     the Player transferring the property
 | 
			
		||||
     * @param to       the Player receiving the property
 | 
			
		||||
     * @param property the PropertyField being transferred
 | 
			
		||||
     */
 | 
			
		||||
    private void transferProperty(Player from, Player to, PropertyField property) {
 | 
			
		||||
        from.sellProperty(property);
 | 
			
		||||
        to.buyProperty(property);
 | 
			
		||||
        property.setOwner(to); // Update the property's owner
 | 
			
		||||
 | 
			
		||||
        System.out.println("Property " + property.getName() + " transferred from " + from.getName() + " to " + to.getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Transfers jail cards between players.
 | 
			
		||||
     *
 | 
			
		||||
     * @param from the Player transferring jail cards
 | 
			
		||||
     * @param to   the Player receiving jail cards
 | 
			
		||||
     * @param numCards the number of jail cards to transfer
 | 
			
		||||
     */
 | 
			
		||||
    private void transferJailCards(Player from, Player to, int numCards) {
 | 
			
		||||
        for (int i = 0; i < numCards; i++) {
 | 
			
		||||
            from.removeJailCard();
 | 
			
		||||
            to.addJailCard();
 | 
			
		||||
        }
 | 
			
		||||
        System.out.println("Transferred " + numCards + " jail card(s) from " + from.getName() + " to " + to.getName());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,25 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An interface for implementing the Visitor pattern for different types of elements in the Monopoly model.
 | 
			
		||||
 *
 | 
			
		||||
 * @param <T> the type of result returned by the visit methods
 | 
			
		||||
 */
 | 
			
		||||
public interface Visitor<T> {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Visits a Figure element.
 | 
			
		||||
     *
 | 
			
		||||
     * @param figure the figure element to visit
 | 
			
		||||
     * @return the result of visiting the figure element
 | 
			
		||||
     */
 | 
			
		||||
    T visit(Figure figure);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * An interface for implementing the Visitor pattern for different types of elements in the Monopoly model
 | 
			
		||||
 * without returning any result.
 | 
			
		||||
 */
 | 
			
		||||
public interface VoidVisitor {
 | 
			
		||||
    /**
 | 
			
		||||
     * Visits a Figure element.
 | 
			
		||||
     *
 | 
			
		||||
     * @param figure the Figure element to visit
 | 
			
		||||
     */
 | 
			
		||||
    void visit(Figure figure);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user