Compare commits
	
		
			64 Commits
		
	
	
		
			46d2dce372
			...
			connect
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4ecccc5951 | ||
| 
						 | 
					f90ce5aa81 | ||
| 
						 | 
					4a9eba255b | ||
| 
						 | 
					4713a526b3 | ||
| 
						 | 
					362c0e5679 | ||
| 
						 | 
					fab2457715 | ||
| 
						 | 
					7b3f31f099 | ||
| 
						 | 
					ed105f1b70 | ||
| 
						 | 
					cd4331aee3 | ||
| 
						 | 
					acc797f2ff | ||
| 
						 | 
					853c32a5b8 | ||
| 
						 | 
					72bef7143a | ||
| 
						 | 
					b1ed571950 | ||
| 
						 | 
					1a75d6d6a8 | ||
| 
						 | 
					c990e7b562 | ||
| 
						 | 
					c87406f60e | ||
| 
						 | 
					21914a1294 | ||
| 
						 | 
					a344145732 | ||
| 
						 | 
					a27ac31086 | ||
| 
						 | 
					9a7f75b76b | ||
| 
						 | 
					687d1621fc | ||
| 
						 | 
					a6944aa6e3 | ||
| 
						 | 
					3e487c00d5 | ||
| 
						 | 
					4820b8cf46 | ||
| 
						 | 
					caa4cb5262 | ||
| 
						 | 
					b8365c76a1 | ||
| 
						 | 
					19216cc174 | ||
| 
						 | 
					c6a23b9b8e | ||
| 
						 | 
					c0f42fb1eb | ||
| 
						 | 
					160873e2cc | ||
| 
						 | 
					1b2a7d73b5 | ||
| 
						 | 
					8df859bbef | ||
| 
						 | 
					e30d10a85d | ||
| 
						 | 
					55778dbcea | ||
| 
						 | 
					422faec281 | ||
| 
						 | 
					dcf10e0819 | ||
| 
						 | 
					6b78733a5d | ||
| 
						 | 
					c124a99901 | ||
| 
						 | 
					d7df4002da | ||
| 
						 | 
					8b0ef97a82 | ||
| 
						 | 
					75d3bef5c8 | ||
| 
						 | 
					bafc3f1db6 | ||
| 
						 | 
					03571fcf74 | ||
| 
						 | 
					e7a6802488 | ||
| 
						 | 
					c2d5611ab9 | ||
| 
						 | 
					a6e6b5e158 | ||
| 
						 | 
					74c3d925e6 | ||
| 
						 | 
					fb28f3fefc | ||
| 
						 | 
					f67fa4d7f0 | ||
| 
						 | 
					6a34dab00c | ||
| 
						 | 
					225a8c0e08 | ||
| 
						 | 
					9a6ce27fe1 | ||
| 
						 | 
					c7bd7d18b7 | ||
| 
						 | 
					437114704a | ||
| 
						 | 
					9b4cac4e56 | ||
| 
						 | 
					e780513b35 | ||
| 
						 | 
					d582c59a7d | ||
| 
						 | 
					7d2c85f617 | ||
| 
						 | 
					4a882bc4ac | ||
| 
						 | 
					3c4eac1fcd | ||
| 
						 | 
					75d5a15bdb | ||
| 
						 | 
					17f121f7d1 | ||
| 
						 | 
					a66c570b51 | ||
| 
						 | 
					e1e7f2eaf6 | 
							
								
								
									
										18
									
								
								Projekte/.run/MonopolyApp (Mac).run.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,18 @@
 | 
			
		||||
<component name="ProjectRunConfigurationManager">
 | 
			
		||||
    <configuration default="false" name="MonopolyApp (Mac)" type="Application" factoryName="Application"
 | 
			
		||||
                   singleton="false">
 | 
			
		||||
        <option name="MAIN_CLASS_NAME" value="pp.monopoly.client.MonopolyApp"/>
 | 
			
		||||
        <module name="Projekte.monopoly.client.main"/>
 | 
			
		||||
        <option name="VM_PARAMETERS" value="-XstartOnFirstThread"/>
 | 
			
		||||
        <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>
 | 
			
		||||
@@ -18,10 +18,11 @@ 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 pp.battleship.client.gui.VolumeSlider;
 | 
			
		||||
 | 
			
		||||
import static pp.util.PreferencesUtils.getPreferences;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package pp.battleship.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Slider;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The VolumeSlider class represents the Volume Slider in the Menu.
 | 
			
		||||
 * It extends the Slider class and provides functionalities for setting the music volume,
 | 
			
		||||
 
 | 
			
		||||
@@ -21,9 +21,11 @@ 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 solidWhiteBackground = new QuadBackgroundComponent(new ColorRGBA(1, 1, 1, 1))
 | 
			
		||||
def greyBackground = new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 1.0f));
 | 
			
		||||
def lightGreyBackground = new QuadBackgroundComponent(new ColorRGBA(0.4f, 0.4f, 0.4f, 1.0f));
 | 
			
		||||
def lightGrey = color(0.6, 0.6, 0.6, 1.0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -246,7 +248,12 @@ selector("tab.button", "pp") {
 | 
			
		||||
    buttonCommands = stdButtonCommands
 | 
			
		||||
}
 | 
			
		||||
selector("settings-title", "pp") {
 | 
			
		||||
    fontSize = 48 // Set font size
 | 
			
		||||
    def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Grey inner border
 | 
			
		||||
    def innerBackground = new QuadBackgroundComponent(buttonBgColor) // White outer border background
 | 
			
		||||
 | 
			
		||||
    background = outerBackground
 | 
			
		||||
    fontSize = 40
 | 
			
		||||
    insets = new Insets3f(3, 3, 3, 3)
 | 
			
		||||
    textHAlignment = HAlignment.Center
 | 
			
		||||
    textVAlignment = VAlignment.Center
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,10 +24,10 @@ overlay.top.color=1, 1, 1, 1
 | 
			
		||||
settings.show=false
 | 
			
		||||
#
 | 
			
		||||
# Specifies the width of the application window in pixels.
 | 
			
		||||
settings.resolution.width=1920
 | 
			
		||||
settings.resolution.width=1200
 | 
			
		||||
#
 | 
			
		||||
# Specifies the height of the application window in pixels.
 | 
			
		||||
settings.resolution.height=1080
 | 
			
		||||
settings.resolution.height=800
 | 
			
		||||
#
 | 
			
		||||
# Determines whether the application runs in full-screen mode.
 | 
			
		||||
settings.full-screen=false
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ public class GameMusic extends AbstractAppState{
 | 
			
		||||
        return PREFERENCES.getBoolean(ENABLED_PREF, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if sound is enabled in the preferences.
 | 
			
		||||
     *
 | 
			
		||||
     * @return float to which the volume is set
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ 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 static final String VOLUME_PREF = "volume"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    private AudioNode passStartSound;
 | 
			
		||||
    private AudioNode eventCardSound;
 | 
			
		||||
@@ -59,6 +60,15 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
        setEnabled(!isEnabled());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the enabled state of this AppState.
 | 
			
		||||
     * Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
 | 
			
		||||
@@ -92,7 +102,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
        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");
 | 
			
		||||
        looserSound = loadSound(app, "Sound/Effects/loser.ogg");
 | 
			
		||||
        buttonSound = loadSound(app, "Sound/Effects/button.ogg");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -193,21 +203,40 @@ public class GameSound extends AbstractAppState implements GameEventListener {
 | 
			
		||||
        if (isEnabled() && buttonSound != null)
 | 
			
		||||
            buttonSound.playInstance();
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the volume of the sounds
 | 
			
		||||
     * @param vol the volume to which the sounds should be set
 | 
			
		||||
     */
 | 
			
		||||
    public void setVolume(float vol){
 | 
			
		||||
        passStartSound.setVolume(vol);
 | 
			
		||||
        eventCardSound.setVolume(vol);
 | 
			
		||||
        gulagSound.setVolume(vol);
 | 
			
		||||
        diceRollSound.setVolume(vol);
 | 
			
		||||
        moneyCollectSound.setVolume(vol);
 | 
			
		||||
        moneyLostSound.setVolume(vol);
 | 
			
		||||
        tradeAcceptedSound.setVolume(vol);
 | 
			
		||||
        tradeRejectedSound.setVolume(vol);
 | 
			
		||||
        winnerSound.setVolume(vol);
 | 
			
		||||
        looserSound.setVolume(vol);
 | 
			
		||||
        buttonSound.setVolume(vol);
 | 
			
		||||
 | 
			
		||||
        PREFERENCES.putFloat(VOLUME_PREF, vol);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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();
 | 
			
		||||
            case GULAG -> gulag();
 | 
			
		||||
            case DICE_ROLL -> diceRoll();
 | 
			
		||||
            case MONEY_COLLECTED -> moneyCollect();
 | 
			
		||||
            case MONEY_LOST -> moneyLost();
 | 
			
		||||
            case TRADE_ACCEPTED -> tradeAccepted();
 | 
			
		||||
            case TRADE_REJECTED -> tradeRejected();
 | 
			
		||||
            case WINNER -> winner();
 | 
			
		||||
            case LOSER -> looser();
 | 
			
		||||
            case BUTTON -> button();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,290 +1,446 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// 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.concurrent.ExecutorService;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
 | 
			
		||||
import com.jme3.app.DebugKeysAppState;
 | 
			
		||||
import com.jme3.app.SimpleApplication;
 | 
			
		||||
import com.jme3.app.StatsAppState;
 | 
			
		||||
import com.jme3.font.BitmapFont;
 | 
			
		||||
import com.jme3.font.BitmapText;
 | 
			
		||||
import com.jme3.input.KeyInput;
 | 
			
		||||
import com.jme3.input.MouseInput;
 | 
			
		||||
import com.jme3.input.controls.ActionListener;
 | 
			
		||||
import com.jme3.input.controls.KeyTrigger;
 | 
			
		||||
import com.jme3.input.controls.MouseButtonTrigger;
 | 
			
		||||
import com.jme3.system.AppSettings;
 | 
			
		||||
import com.simsilica.lemur.GuiGlobals;
 | 
			
		||||
import com.simsilica.lemur.style.BaseStyles;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.client.MonopolyClient;
 | 
			
		||||
import pp.monopoly.client.gui.SettingsMenu;
 | 
			
		||||
import pp.monopoly.client.gui.StartMenu;
 | 
			
		||||
import pp.monopoly.game.client.ClientGameLogic;
 | 
			
		||||
import pp.monopoly.game.client.ServerConnection;
 | 
			
		||||
import pp.monopoly.notification.ClientStateEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.InfoTextEvent;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
import pp.dialog.DialogBuilder;
 | 
			
		||||
import pp.dialog.DialogManager;
 | 
			
		||||
import pp.graphics.Draw;
 | 
			
		||||
import pp.monopoly.client.gui.*;
 | 
			
		||||
import pp.monopoly.client.gui.popups.BuildingPropertyCard;
 | 
			
		||||
import pp.monopoly.client.gui.popups.BuyCard;
 | 
			
		||||
import pp.monopoly.client.gui.popups.FoodFieldCard;
 | 
			
		||||
import pp.monopoly.client.gui.popups.GateFieldCard;
 | 
			
		||||
import pp.monopoly.game.client.ClientGameLogic;
 | 
			
		||||
import pp.monopoly.game.client.MonopolyClient;
 | 
			
		||||
import pp.monopoly.game.client.ServerConnection;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.notification.GameEventListener;
 | 
			
		||||
import pp.monopoly.notification.InfoTextEvent;
 | 
			
		||||
import pp.monopoly.server.MonopolyServer;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.concurrent.ExecutorService;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
import java.util.logging.LogManager;
 | 
			
		||||
 | 
			
		||||
import static pp.monopoly.Resources.lookup;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The main class for the Battleship client application.
 | 
			
		||||
 * It manages the initialization, input setup, GUI setup, and game states for the client.
 | 
			
		||||
 */
 | 
			
		||||
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;
 | 
			
		||||
    private NetworkSupport networkSupport;
 | 
			
		||||
    private BoardManager boardManager = new BoardManager();
 | 
			
		||||
 | 
			
		||||
    // TODO Temp später entfernen
 | 
			
		||||
 | 
			
		||||
    private BuildingPropertyCard buildingProperty;
 | 
			
		||||
    private FoodFieldCard foodField;
 | 
			
		||||
    private GateFieldCard gateField;
 | 
			
		||||
    private BuyCard buyCard;
 | 
			
		||||
    private boolean isBuyCardPopupOpen = false;
 | 
			
		||||
    private final ActionListener BListener = (name, isPressed, tpf) -> handleB(isPressed);
 | 
			
		||||
    /**
 | 
			
		||||
     * Logger for logging messages within the application.
 | 
			
		||||
     */
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(MonopolyApp.class.getName());
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Path to the styles script for GUI elements.
 | 
			
		||||
     */
 | 
			
		||||
    private static final String STYLES_SCRIPT = "Interface/Lemur/pp-styles.groovy"; // NON-NLS
 | 
			
		||||
    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
 | 
			
		||||
    private static final String FONT = "Interface/Fonts/Default.fnt"; //NON-NLS
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Path to the client configuration file, if one exists.
 | 
			
		||||
     */
 | 
			
		||||
    private static final File CONFIG_FILE = new File("client.properties");
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Input mapping name for mouse clicks.
 | 
			
		||||
     */
 | 
			
		||||
    public static final String CLICK = "CLICK";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Input mapping name for the Escape key.
 | 
			
		||||
     */
 | 
			
		||||
    private static final String ESC = "ESC";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Manager for handling dialogs within the application.
 | 
			
		||||
     */
 | 
			
		||||
    private final DialogManager dialogManager = new DialogManager(this);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The server connection instance, used for communicating with the game server.
 | 
			
		||||
     */
 | 
			
		||||
    private final ServerConnection serverConnection;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instance of the {@link Draw} class for rendering graphics.
 | 
			
		||||
     */
 | 
			
		||||
    private Draw draw;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Text display at the top of the GUI for showing information to the user.
 | 
			
		||||
     */
 | 
			
		||||
    private BitmapText topText;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Executor service for handling asynchronous tasks within the application.
 | 
			
		||||
     */
 | 
			
		||||
    private ExecutorService executor;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handler for managing the client's game logic.
 | 
			
		||||
     */
 | 
			
		||||
    private final ClientGameLogic logic;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Configuration settings for the Battleship client application.
 | 
			
		||||
     */
 | 
			
		||||
    private final MonopolyAppConfig config;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Listener for handling actions triggered by the Escape key.
 | 
			
		||||
     */
 | 
			
		||||
    private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        // Configure logging
 | 
			
		||||
        LogManager manager = LogManager.getLogManager();
 | 
			
		||||
        try {
 | 
			
		||||
            manager.readConfiguration(new FileInputStream("logging.properties"));
 | 
			
		||||
            LOGGER.log(Level.INFO, "Successfully read logging properties"); //NON-NLS
 | 
			
		||||
        }
 | 
			
		||||
        catch (IOException e) {
 | 
			
		||||
            LOGGER.log(Level.INFO, e.getMessage());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts the Battleship application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param args Command-line arguments for launching the application.
 | 
			
		||||
     */
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        new MonopolyApp().start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MonopolyApp() {
 | 
			
		||||
        this.draw = new Draw(assetManager);
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new {@code MonopolyApp} instance.
 | 
			
		||||
     * Initializes the configuration, server connection, and game logic listeners.
 | 
			
		||||
     */
 | 
			
		||||
    private MonopolyApp() {
 | 
			
		||||
        config = new MonopolyAppConfig();
 | 
			
		||||
        networkSupport = new NetworkSupport(this); // Initialize NetworkSupport
 | 
			
		||||
        serverConnection = networkSupport;
 | 
			
		||||
        config.readFromIfExists(CONFIG_FILE);
 | 
			
		||||
        serverConnection = makeServerConnection();
 | 
			
		||||
        logic = new ClientGameLogic(serverConnection);
 | 
			
		||||
        logic.addListener(this);
 | 
			
		||||
        setShowSettings(config.getShowSettings());
 | 
			
		||||
        setSettings(makeSettings());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public MonopolyAppConfig getConfig() {
 | 
			
		||||
        return config;
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates and configures application settings from the client configuration.
 | 
			
		||||
     *
 | 
			
		||||
     * @return A configured {@link AppSettings} object.
 | 
			
		||||
     */
 | 
			
		||||
    private AppSettings makeSettings() {
 | 
			
		||||
        final AppSettings settings = new AppSettings(true);
 | 
			
		||||
        settings.setTitle(lookup("monopoly.name"));
 | 
			
		||||
        settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight());
 | 
			
		||||
        settings.setFullscreen(config.fullScreen());
 | 
			
		||||
        settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer());
 | 
			
		||||
        settings.setGammaCorrection(config.useGammaCorrection());
 | 
			
		||||
        return settings;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Factory method for creating a server connection based on the current
 | 
			
		||||
     * client configuration.
 | 
			
		||||
     *
 | 
			
		||||
     * @return A {@link ServerConnection} instance, which could be a real or mock server.
 | 
			
		||||
     */
 | 
			
		||||
    private ServerConnection makeServerConnection() {
 | 
			
		||||
        return new NetworkSupport(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the dialog manager responsible for managing in-game dialogs.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The {@link DialogManager} instance.
 | 
			
		||||
     */
 | 
			
		||||
    public DialogManager getDialogManager() {
 | 
			
		||||
        return dialogManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the game logic handler for the client.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The {@link ClientGameLogic} instance.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public ClientGameLogic getGameLogic() {
 | 
			
		||||
        return logic;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BoardManager getBoardManager() {
 | 
			
		||||
        return boardManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NetworkSupport getNetworkSupport() {
 | 
			
		||||
        return networkSupport;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current configuration settings for the Battleship client.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The {@link BattleshipClientConfig} instance.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public MonopolyAppConfig getConfig() {
 | 
			
		||||
        return config;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the application.
 | 
			
		||||
     * Sets up input mappings, GUI, game states, and connects to the server.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void simpleInitApp() {
 | 
			
		||||
        GuiGlobals.initialize(this);
 | 
			
		||||
        BaseStyles.loadStyleResources(STYLES_SCRIPT);
 | 
			
		||||
        GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); // NON-NLS
 | 
			
		||||
        BaseStyles.loadStyleResources("com/simsilica/lemur/style/base/glass-styles.groovy");
 | 
			
		||||
        GuiGlobals.getInstance().getStyles();
 | 
			
		||||
        final BitmapFont normalFont = assetManager.loadFont(FONT); // NON-NLS
 | 
			
		||||
 | 
			
		||||
        setPauseOnLostFocus(false);
 | 
			
		||||
        draw = new Draw(assetManager);
 | 
			
		||||
        setupInput();
 | 
			
		||||
        setupStates();
 | 
			
		||||
        setupGui();
 | 
			
		||||
 | 
			
		||||
        // Zeige das Startmenü
 | 
			
		||||
        StartMenu.createStartMenu(this);
 | 
			
		||||
        new StartMenu(this).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets up the graphical user interface (GUI) for the application.
 | 
			
		||||
     */
 | 
			
		||||
    private void setupGui() {
 | 
			
		||||
        BitmapFont normalFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
 | 
			
		||||
        GuiGlobals.initialize(this);
 | 
			
		||||
        BaseStyles.loadStyleResources(STYLES_SCRIPT);
 | 
			
		||||
        BaseStyles.loadGlassStyle();
 | 
			
		||||
        GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS
 | 
			
		||||
        final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
 | 
			
		||||
        topText = new BitmapText(normalFont);
 | 
			
		||||
        topText.setLocalTranslation(10, settings.getHeight() - 10, 0);
 | 
			
		||||
        final int height = context.getSettings().getHeight();
 | 
			
		||||
        topText.setLocalTranslation(10f, height - 10f, 0f);
 | 
			
		||||
        topText.setColor(config.getTopColor());
 | 
			
		||||
        guiNode.attachChild(topText);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Configures input mappings and sets up listeners for user interactions.
 | 
			
		||||
     */
 | 
			
		||||
    private void setupInput() {
 | 
			
		||||
        inputManager.deleteMapping(INPUT_MAPPING_EXIT);
 | 
			
		||||
        inputManager.setCursorVisible(true);
 | 
			
		||||
        inputManager.addMapping("ESC", new KeyTrigger(KeyInput.KEY_ESCAPE));
 | 
			
		||||
        inputManager.addListener(escapeListener, "ESC");
 | 
			
		||||
 | 
			
		||||
        inputManager.addMapping("B", new KeyTrigger(KeyInput.KEY_B));
 | 
			
		||||
        inputManager.addListener(BListener, "B");
 | 
			
		||||
        inputManager.setCursorVisible(false);
 | 
			
		||||
        inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE));
 | 
			
		||||
        inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
 | 
			
		||||
        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);
 | 
			
		||||
            }
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes and attaches the necessary application states for the game.
 | 
			
		||||
     */
 | 
			
		||||
    private void setupStates() {
 | 
			
		||||
        if (config.getShowStatistics()) {
 | 
			
		||||
            final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
 | 
			
		||||
            final StatsAppState stats = new StatsAppState(guiNode, normalFont);
 | 
			
		||||
            stateManager.attach(stats);
 | 
			
		||||
        }
 | 
			
		||||
        flyCam.setEnabled(false);
 | 
			
		||||
        stateManager.detach(stateManager.getState(StatsAppState.class));
 | 
			
		||||
        stateManager.detach(stateManager.getState(DebugKeysAppState.class));
 | 
			
		||||
 | 
			
		||||
        attachGameSound();
 | 
			
		||||
        attachGameMusic();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //logik zum wechselnden erscheinen und verschwinden beim drücken von B //TODO süäter entfernen
 | 
			
		||||
    private void handleB(boolean isPressed) {
 | 
			
		||||
        if (isPressed) {
 | 
			
		||||
            if (gateField != null && isBuyCardPopupOpen) {
 | 
			
		||||
                // Schließe das SettingsMenu
 | 
			
		||||
                System.out.println("Schließe BuyCardPopup...");
 | 
			
		||||
                gateField.close();
 | 
			
		||||
                gateField = null;
 | 
			
		||||
                setBuyCardPopupOpen(false);
 | 
			
		||||
            } else {
 | 
			
		||||
                // Öffne das SettingsMenu
 | 
			
		||||
                System.out.println("Öffne BuyCardPopup...");
 | 
			
		||||
                gateField = new GateFieldCard(this);
 | 
			
		||||
                gateField.open();
 | 
			
		||||
                setBuyCardPopupOpen(true);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    /**
 | 
			
		||||
     * Attaches the game sound state and sets its initial enabled state.
 | 
			
		||||
     */
 | 
			
		||||
    private void attachGameSound() {
 | 
			
		||||
        final GameSound gameSound = new GameSound();
 | 
			
		||||
        logic.addListener(gameSound);
 | 
			
		||||
        gameSound.setEnabled(GameSound.enabledInPreferences());
 | 
			
		||||
        stateManager.attach(gameSound);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    /**
 | 
			
		||||
     * Attaches the background music state and sets its initial enabled state.
 | 
			
		||||
     */
 | 
			
		||||
    private void attachGameMusic() {
 | 
			
		||||
        final GameMusic gameSound = new GameMusic();
 | 
			
		||||
        gameSound.setEnabled(GameMusic.enabledInPreferences());
 | 
			
		||||
        stateManager.attach(gameSound);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the application state every frame.
 | 
			
		||||
     * This method is called once per frame during the game loop.
 | 
			
		||||
     *
 | 
			
		||||
     * @param tpf Time per frame in seconds.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(InfoTextEvent event) {
 | 
			
		||||
        setInfoText(event.key());
 | 
			
		||||
    public void simpleUpdate(float tpf) {
 | 
			
		||||
        super.simpleUpdate(tpf);
 | 
			
		||||
        dialogManager.update(tpf);
 | 
			
		||||
        logic.update(tpf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void stop(boolean waitFor) {
 | 
			
		||||
        if (executor != null) executor.shutdownNow();
 | 
			
		||||
        serverConnection.disconnect();
 | 
			
		||||
        super.stop(waitFor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public DialogManager getDialogManager() {
 | 
			
		||||
        return dialogManager;
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the Escape key action to either close the top dialog or show the main menu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param isPressed Indicates whether the Escape key is pressed.
 | 
			
		||||
     */
 | 
			
		||||
    public void escape(boolean isPressed) {
 | 
			
		||||
        if (!isPressed) return;
 | 
			
		||||
        if (dialogManager.showsDialog())
 | 
			
		||||
            dialogManager.escape();
 | 
			
		||||
        else
 | 
			
		||||
            new SettingsMenu(this).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the {@link Draw} instance used for rendering graphical elements in the game.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The {@link Draw} instance.
 | 
			
		||||
     */
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO später entfernen
 | 
			
		||||
 | 
			
		||||
    public void setBuyCardPopupOpen(boolean isOpen) {
 | 
			
		||||
        this.isBuyCardPopupOpen = 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
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO später entfernen
 | 
			
		||||
 | 
			
		||||
    public void startBuyCard() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void returnToMenu() {
 | 
			
		||||
        guiNode.detachAllChildren(); // Entferne die GUI
 | 
			
		||||
        StartMenu.createStartMenu(this); // Zeige das Startmenü erneut
 | 
			
		||||
    /**
 | 
			
		||||
     * Tries to connect
 | 
			
		||||
     */
 | 
			
		||||
    public void connect() {
 | 
			
		||||
        serverConnection.connect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Startet den Server in einem neuen Thread.
 | 
			
		||||
     * Handles a request to close the application.
 | 
			
		||||
     * If the request is initiated by pressing ESC, this parameter is true.
 | 
			
		||||
     *
 | 
			
		||||
     * @param esc If true, the request is due to the ESC key being pressed.
 | 
			
		||||
     */
 | 
			
		||||
    public void startServer() {
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            try {
 | 
			
		||||
                MonopolyServer.main(new String[0]); // Startet den MonopolyServer
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                errorDialog("Fehler: Server konnte nicht gestartet werden.");
 | 
			
		||||
            }
 | 
			
		||||
        }).start();
 | 
			
		||||
    @Override
 | 
			
		||||
    public void requestClose(boolean esc) { /* do nothing */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the application, displaying a confirmation dialog if the client is connected to a server.
 | 
			
		||||
     */
 | 
			
		||||
    public void closeApp() {
 | 
			
		||||
        if (serverConnection.isConnected())
 | 
			
		||||
            confirmDialog(lookup("confirm.leaving"), this::close);
 | 
			
		||||
        else
 | 
			
		||||
            close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MonopolyServer getMonopolyServer() {
 | 
			
		||||
        return monopolyServer;
 | 
			
		||||
    /**
 | 
			
		||||
     * Closes the application, disconnecting from the server and stopping the application.
 | 
			
		||||
     */
 | 
			
		||||
    private void close() {
 | 
			
		||||
        serverConnection.disconnect();
 | 
			
		||||
        stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ServerConnection getServerConnection() {
 | 
			
		||||
        return serverConnection;
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the informational text displayed in the GUI.
 | 
			
		||||
     *
 | 
			
		||||
     * @param text The information text to display.
 | 
			
		||||
     */
 | 
			
		||||
    public void setInfoText(String text) {
 | 
			
		||||
        LOGGER.log(Level.DEBUG, "setInfoText {0}", text); //NON-NLS
 | 
			
		||||
        topText.setText(text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the informational text in the GUI based on the key received in an {@link InfoTextEvent}.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event The {@link InfoTextEvent} containing the key for the text to display.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(InfoTextEvent event) {
 | 
			
		||||
        LOGGER.log(Level.DEBUG, "received info text {0}", event.key()); //NON-NLS
 | 
			
		||||
        setInfoText(lookup(event.key()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles client state events to update the game states accordingly.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event The {@link ClientStateEvent} representing the state change.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void receivedEvent(ClientStateEvent event) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the executor service used for handling multithreaded tasks.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The {@link ExecutorService} instance.
 | 
			
		||||
     */
 | 
			
		||||
    public ExecutorService getExecutor() {
 | 
			
		||||
        if (executor == null)
 | 
			
		||||
            executor = Executors.newCachedThreadPool();
 | 
			
		||||
        return executor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Stops the application, shutting down the executor service and halting execution.
 | 
			
		||||
     *
 | 
			
		||||
     * @param waitFor If true, waits for the application to stop before returning.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void stop(boolean waitFor) {
 | 
			
		||||
        if (executor != null) executor.shutdownNow();
 | 
			
		||||
        super.stop(waitFor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Displays a confirmation dialog with a specified question and action for the "Yes" button.
 | 
			
		||||
     *
 | 
			
		||||
     * @param question  The question to display in the dialog.
 | 
			
		||||
     * @param yesAction The action to perform if "Yes" is selected.
 | 
			
		||||
     */
 | 
			
		||||
    public void confirmDialog(String question, Runnable yesAction) {
 | 
			
		||||
        DialogBuilder.simple(dialogManager)
 | 
			
		||||
                     .setTitle(lookup("dialog.question"))
 | 
			
		||||
                     .setText(question)
 | 
			
		||||
                     .setOkButton(lookup("button.yes"), d -> {
 | 
			
		||||
                        getGameLogic().playSound(Sound.BUTTON); // Play sound
 | 
			
		||||
                        yesAction.run(); // Execute the original yesAction
 | 
			
		||||
                    })
 | 
			
		||||
                     .setNoButton(lookup("button.no"),  d -> getGameLogic().playSound(Sound.BUTTON))
 | 
			
		||||
                     .build()
 | 
			
		||||
                     .open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Displays an error dialog with the specified error message.
 | 
			
		||||
     *
 | 
			
		||||
     * @param errorMessage The error message to display in the dialog.
 | 
			
		||||
     */
 | 
			
		||||
    public void errorDialog(String errorMessage) {
 | 
			
		||||
        DialogBuilder.simple(dialogManager)
 | 
			
		||||
                     .setTitle(lookup("dialog.error"))
 | 
			
		||||
                     .setText(errorMessage)
 | 
			
		||||
                     .setOkButton(lookup("button.ok"), d -> getGameLogic().playSound(Sound.BUTTON))
 | 
			
		||||
                     .build()
 | 
			
		||||
                     .open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void disconnect() {
 | 
			
		||||
        serverConnection.disconnect();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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 = "42069";
 | 
			
		||||
    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,8 +1,11 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Programming project code
 | 
			
		||||
// UniBw M, 2022, 2023, 2024
 | 
			
		||||
// www.unibw.de/inf2
 | 
			
		||||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.Client;
 | 
			
		||||
import com.jme3.network.ClientStateListener;
 | 
			
		||||
@@ -10,12 +13,19 @@ import com.jme3.network.Message;
 | 
			
		||||
import com.jme3.network.MessageListener;
 | 
			
		||||
import com.jme3.network.Network;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.gui.CreateGameMenu;
 | 
			
		||||
import pp.monopoly.game.client.ServerConnection;
 | 
			
		||||
import pp.monopoly.message.client.ClientMessage;
 | 
			
		||||
import pp.monopoly.message.server.ServerMessage;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
 | 
			
		||||
import static pp.monopoly.Resources.lookup;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Manages the network connection for the Monopoly application.
 | 
			
		||||
 * Manages the network connection for the Battleship application.
 | 
			
		||||
 * Handles connecting to and disconnecting from the server, and sending messages.
 | 
			
		||||
 */
 | 
			
		||||
public class NetworkSupport implements MessageListener<Client>, ClientStateListener, ServerConnection {
 | 
			
		||||
@@ -24,20 +34,29 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
    private Client client;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a NetworkSupport instance for the Monopoly application.
 | 
			
		||||
     * Constructs a NetworkSupport instance for the given Battleship application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The Monopoly application instance.
 | 
			
		||||
     * @param app The Battleship application instance.
 | 
			
		||||
     */
 | 
			
		||||
    public NetworkSupport(MonopolyApp app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the Monopoly application instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Monopoly application instance
 | 
			
		||||
     * Return the client connections Id
 | 
			
		||||
     * @return the client id
 | 
			
		||||
     */
 | 
			
		||||
    MonopolyApp getApp() {
 | 
			
		||||
    public int getId() {
 | 
			
		||||
        if (client == null) return 0;
 | 
			
		||||
        return client.getId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the Battleship application instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Battleship application instance
 | 
			
		||||
     */
 | 
			
		||||
    public MonopolyApp getApp() {
 | 
			
		||||
        return app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -57,9 +76,8 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void connect() {
 | 
			
		||||
        if (client == null) {
 | 
			
		||||
            new NetworkDialog(this).open();
 | 
			
		||||
        }
 | 
			
		||||
        if (client == null)
 | 
			
		||||
            new CreateGameMenu(this).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -70,7 +88,7 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
        if (client == null) return;
 | 
			
		||||
        client.close();
 | 
			
		||||
        client = null;
 | 
			
		||||
        LOGGER.log(Level.INFO, "Client connection closed.");
 | 
			
		||||
        LOGGER.log(Level.INFO, "client closed"); //NON-NLS
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -80,10 +98,9 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
     * @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.");
 | 
			
		||||
        }
 | 
			
		||||
    public void initNetwork(String host, int port) throws IOException {
 | 
			
		||||
        if (client != null)
 | 
			
		||||
            throw new IllegalStateException("trying to join a game again");
 | 
			
		||||
        client = Network.connectToServer(host, port);
 | 
			
		||||
        client.start();
 | 
			
		||||
        client.addMessageListener(this);
 | 
			
		||||
@@ -98,10 +115,9 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void messageReceived(Client client, Message message) {
 | 
			
		||||
        LOGGER.log(Level.INFO, "Message received from server: {0}", message);
 | 
			
		||||
        if (message instanceof ServerMessage serverMessage) {
 | 
			
		||||
        LOGGER.log(Level.INFO, "message received from server: {0}", message); //NON-NLS
 | 
			
		||||
        if (message instanceof ServerMessage serverMessage)
 | 
			
		||||
            app.enqueue(() -> serverMessage.accept(app.getGameLogic()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -111,7 +127,7 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void clientConnected(Client client) {
 | 
			
		||||
        LOGGER.log(Level.INFO, "Successfully connected to server: {0}", client);
 | 
			
		||||
        LOGGER.log(Level.INFO, "Client connected: {0}", client); //NON-NLS
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -122,9 +138,13 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void clientDisconnected(Client client, DisconnectInfo disconnectInfo) {
 | 
			
		||||
        LOGGER.log(Level.INFO, "Disconnected from server: {0}", disconnectInfo);
 | 
			
		||||
        LOGGER.log(Level.INFO, "Client {0} disconnected: {1}", client, disconnectInfo); //NON-NLS
 | 
			
		||||
        if (this.client != client)
 | 
			
		||||
            throw new IllegalArgumentException("parameter value must be client");
 | 
			
		||||
        LOGGER.log(Level.INFO, "client still connected: {0}", client.isConnected()); //NON-NLS
 | 
			
		||||
        this.client = null;
 | 
			
		||||
        app.enqueue(() -> app.setInfoText("Verbindung zum Server verloren."));
 | 
			
		||||
        disconnect();
 | 
			
		||||
        app.enqueue(() -> app.setInfoText(lookup("lost.connection.to.server")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -134,47 +154,10 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
 | 
			
		||||
     */
 | 
			
		||||
    @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 {
 | 
			
		||||
        LOGGER.log(Level.INFO, "sending {0}", message); //NON-NLS
 | 
			
		||||
        if (client == null)
 | 
			
		||||
            app.errorDialog(lookup("lost.connection.to.server"));
 | 
			
		||||
        else
 | 
			
		||||
            client.send(message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public void startServerAndJoin() {
 | 
			
		||||
        new Thread(() -> {
 | 
			
		||||
            // Server starten
 | 
			
		||||
            app.startServer();
 | 
			
		||||
            
 | 
			
		||||
            // Warten, bis der Server tatsächlich betriebsbereit ist
 | 
			
		||||
            int retries = 5;
 | 
			
		||||
            while (retries > 0) {
 | 
			
		||||
                try {
 | 
			
		||||
                    initNetwork("localhost", app.getConfig().getPort());
 | 
			
		||||
                    app.enqueue(() -> app.setInfoText("Erfolgreich verbunden!"));
 | 
			
		||||
                    return; // Verbindung erfolgreich
 | 
			
		||||
                } catch (IOException e) {
 | 
			
		||||
                    retries--;
 | 
			
		||||
                    try {
 | 
			
		||||
                        Thread.sleep(1000); // Eine Sekunde warten und erneut versuchen
 | 
			
		||||
                    } catch (InterruptedException ex) {
 | 
			
		||||
                        Thread.currentThread().interrupt();
 | 
			
		||||
                        break; // Abbrechen, wenn der Thread unterbrochen wird
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Wenn alle Versuche fehlschlagen
 | 
			
		||||
            app.enqueue(() -> app.errorDialog("Fehler: Verbindung zum Server fehlgeschlagen."));
 | 
			
		||||
        }).start();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void connectToServer(String host, int port) {
 | 
			
		||||
        try {
 | 
			
		||||
            initNetwork(host, port); // Verbindung initialisieren
 | 
			
		||||
            app.setInfoText("Erfolgreich mit Server verbunden!");
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            app.errorDialog("Fehler: Verbindung zum Server fehlgeschlagen.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,151 +1,226 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// 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 java.lang.System.Logger;
 | 
			
		||||
import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.concurrent.ExecutionException;
 | 
			
		||||
import java.util.concurrent.Future;
 | 
			
		||||
 | 
			
		||||
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.Label;
 | 
			
		||||
import com.simsilica.lemur.TextField;
 | 
			
		||||
import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
 | 
			
		||||
import static pp.monopoly.Resources.lookup;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.client.StartMenu;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.NetworkSupport;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
import pp.monopoly.server.MonopolyServer;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.DialogBuilder;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * CreateGameMenu class represents the menu for creating a new game.
 | 
			
		||||
 * Represents a dialog for setting up a network connection in the Battleship game.
 | 
			
		||||
 * Allows users to specify the host and port for connecting to a game server.
 | 
			
		||||
 */
 | 
			
		||||
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", new ElementId("header")));
 | 
			
		||||
        title.setFont(app.getAssetManager().loadFont("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt"));
 | 
			
		||||
        title.setFontSize(50);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // 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 -> app.getNetworkSupport().startServerAndJoin());
 | 
			
		||||
 | 
			
		||||
        // "Beitreten"-Button
 | 
			
		||||
        Button joinButton = buttonContainer.addChild(new Button("Beitreten"));
 | 
			
		||||
        joinButton.setPreferredSize(new Vector3f(120, 40, 0));
 | 
			
		||||
        joinButton.addClickCommands(source -> {
 | 
			
		||||
            try {
 | 
			
		||||
                String host = playerNameField.getText().trim();
 | 
			
		||||
                int port = Integer.parseInt(serverAddressField.getText().trim());
 | 
			
		||||
                app.getNetworkSupport().connectToServer(host, port);
 | 
			
		||||
        
 | 
			
		||||
                // LobbyMenu öffnen
 | 
			
		||||
                app.enqueue(() -> {
 | 
			
		||||
                    app.getGuiNode().detachAllChildren(); // Bestehende GUI entfernen
 | 
			
		||||
                    new LobbyMenu(app); // LobbyMenu erstellen
 | 
			
		||||
                });
 | 
			
		||||
            } catch (NumberFormatException e) {
 | 
			
		||||
                app.errorDialog("Port muss eine Zahl sein.");
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // 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");
 | 
			
		||||
 | 
			
		||||
        // TODO später entfernen
 | 
			
		||||
 | 
			
		||||
        app.getInputManager().addMapping("OpenBuyCard", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_B));
 | 
			
		||||
        app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void onAction(String name, boolean isPressed, float tpf) {
 | 
			
		||||
                if (name.equals("OpenBuyCard") && isPressed) {
 | 
			
		||||
                    app.startBuyCard(); // Öffnet die TestWorld
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }, "OpenBuyCard");
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(menuContainer);
 | 
			
		||||
    }
 | 
			
		||||
public class CreateGameMenu extends Dialog {
 | 
			
		||||
    private static final Logger LOGGER = System.getLogger(CreateGameMenu.class.getName());
 | 
			
		||||
    private static final String LOCALHOST = "localhost"; //NON-NLS
 | 
			
		||||
    private static final String DEFAULT_PORT = "42069"; //NON-NLS
 | 
			
		||||
    private final NetworkSupport network;
 | 
			
		||||
    private final TextField host = new TextField(LOCALHOST);
 | 
			
		||||
    private final TextField port = new TextField(DEFAULT_PORT);
 | 
			
		||||
    private final Button serverButton = new Button("Selber hosten");
 | 
			
		||||
    private final Button cancelButton = new Button("Abbrechen");
 | 
			
		||||
    private final Button joinButton = new Button("Beitreten");
 | 
			
		||||
    private String hostname;
 | 
			
		||||
    private int portNumber;
 | 
			
		||||
    private Future<Object> connectionFuture;
 | 
			
		||||
    private Dialog progressDialog;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu.
 | 
			
		||||
     * Constructs a new CreateGameMenu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param network The NetworkSupport instance to be used for network operations.
 | 
			
		||||
     */
 | 
			
		||||
    private void addBackgroundImage() {
 | 
			
		||||
    public CreateGameMenu(NetworkSupport network) {
 | 
			
		||||
        super(network.getApp().getDialogManager());
 | 
			
		||||
        this.network = network;
 | 
			
		||||
        host.setSingleLine(true);
 | 
			
		||||
        host.setPreferredWidth(400f);
 | 
			
		||||
        port.setSingleLine(true);
 | 
			
		||||
 | 
			
		||||
        final MonopolyApp app = network.getApp();
 | 
			
		||||
 | 
			
		||||
                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(app.getCamera().getWidth(), app.getCamera().getHeight());
 | 
			
		||||
        background = new Geometry("Background", quad);
 | 
			
		||||
        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); // Hintergrundebene
 | 
			
		||||
 | 
			
		||||
        background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
 | 
			
		||||
        addChild(new Label("Spiel erstellen", new ElementId("header"))); //NON-NLS
 | 
			
		||||
        final Container input = new Container(new SpringGridLayout());
 | 
			
		||||
        input.addChild(new Label(lookup("host.name") + ":  "));
 | 
			
		||||
        input.addChild(host, 1);
 | 
			
		||||
        input.addChild(new Label(lookup("port.number") + ":  "));
 | 
			
		||||
        input.addChild(port, 1);
 | 
			
		||||
        
 | 
			
		||||
        addChild(input);
 | 
			
		||||
        // "Abbrechen"-Button
 | 
			
		||||
        cancelButton.setPreferredSize(new Vector3f(120, 40, 0));
 | 
			
		||||
        cancelButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            this.close();
 | 
			
		||||
            new StartMenu(network.getApp()).open();
 | 
			
		||||
        }));
 | 
			
		||||
        addChild(cancelButton);
 | 
			
		||||
 | 
			
		||||
        // "Selber hosten"-Button
 | 
			
		||||
        serverButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            network.getApp().getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            startServerInThread();
 | 
			
		||||
        }   ));
 | 
			
		||||
        addChild(serverButton);
 | 
			
		||||
 | 
			
		||||
        // "Beitreten"-Button
 | 
			
		||||
        joinButton.setPreferredSize(new Vector3f(120, 40, 0));
 | 
			
		||||
        joinButton.addClickCommands(s -> ifTopDialog( () -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            connect();
 | 
			
		||||
        }));
 | 
			
		||||
        addChild(joinButton);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird.
 | 
			
		||||
     * Handles the action for the connect button in the connection dialog.
 | 
			
		||||
     * Tries to parse the port number and initiate connection to the server.
 | 
			
		||||
     */
 | 
			
		||||
    private void goBackToStartMenu() {
 | 
			
		||||
        app.getGuiNode().detachChild(menuContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
 | 
			
		||||
        StartMenu.createStartMenu(app);
 | 
			
		||||
    private void connect() {
 | 
			
		||||
        LOGGER.log(Level.INFO, "connect to host={0}, port={1}", host, port); //NON-NLS
 | 
			
		||||
        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(lookup("port.must.be.integer"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a dialog indicating that the connection is in progress.
 | 
			
		||||
     */
 | 
			
		||||
    private void openProgressDialog() {
 | 
			
		||||
        progressDialog = DialogBuilder.simple(network.getApp().getDialogManager())
 | 
			
		||||
                                      .setText(lookup("label.connecting"))
 | 
			
		||||
                                      .build();
 | 
			
		||||
        progressDialog.open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Tries 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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(network.getApp()).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This method is called by {@linkplain pp.dialog.DialogManager#update(float)} for periodically
 | 
			
		||||
     * updating this dialog. T
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        if (connectionFuture != null && connectionFuture.isDone())
 | 
			
		||||
            try {
 | 
			
		||||
                connectionFuture.get();
 | 
			
		||||
                success();
 | 
			
		||||
            }
 | 
			
		||||
            catch (ExecutionException e) {
 | 
			
		||||
                failure(e.getCause());
 | 
			
		||||
            }
 | 
			
		||||
            catch (InterruptedException e) {
 | 
			
		||||
                LOGGER.log(Level.WARNING, "Interrupted!", e); //NON-NLS
 | 
			
		||||
                Thread.currentThread().interrupt();
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a successful connection to the game server.
 | 
			
		||||
     */
 | 
			
		||||
    private void success() {
 | 
			
		||||
        connectionFuture = null;
 | 
			
		||||
        progressDialog.close();
 | 
			
		||||
        this.close();
 | 
			
		||||
        new LobbyMenu(network.getApp()).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles a failed connection attempt.
 | 
			
		||||
     *
 | 
			
		||||
     * @param e The cause of the failure.
 | 
			
		||||
     */
 | 
			
		||||
    private void failure(Throwable e) {
 | 
			
		||||
        connectionFuture = null;
 | 
			
		||||
        progressDialog.close();
 | 
			
		||||
        network.getApp().errorDialog(lookup("server.connection.failed"));
 | 
			
		||||
        network.getApp().setInfoText(e.getLocalizedMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts the server in a separate thread.
 | 
			
		||||
     */
 | 
			
		||||
    private void startServerInThread() {
 | 
			
		||||
        serverButton.setEnabled(false);
 | 
			
		||||
        Thread serverThread = new Thread(() -> {
 | 
			
		||||
            try {
 | 
			
		||||
                MonopolyServer.main(null);
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                serverButton.setEnabled(true);
 | 
			
		||||
                LOGGER.log(Level.ERROR, "Server could not be started", e);
 | 
			
		||||
                network.getApp().errorDialog("Could not start server: " + e.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        serverThread.start();
 | 
			
		||||
        try {
 | 
			
		||||
            Thread.sleep(2000);
 | 
			
		||||
        } catch (InterruptedException e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
        connect();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,35 +22,52 @@ import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedList;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.message.client.PlayerReady;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
public class LobbyMenu {
 | 
			
		||||
public class LobbyMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Container menuContainer;
 | 
			
		||||
    private Geometry background;
 | 
			
		||||
    private Geometry circle;
 | 
			
		||||
    private Container lowerLeftMenu;
 | 
			
		||||
    private Container lowerRightMenu;
 | 
			
		||||
    private ColorRGBA playerColor= ColorRGBA.Gray;
 | 
			
		||||
 | 
			
		||||
    private PlayerHandler playerHandler;
 | 
			
		||||
    private TextField startingCapital;
 | 
			
		||||
    private TextField playerInputField;
 | 
			
		||||
    private Selector<String> figureDropdown;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private TextField playerInputField = new TextField("Spieler 1");
 | 
			
		||||
    private TextField startingCapital = new TextField("15000");
 | 
			
		||||
    private String figure;
 | 
			
		||||
 | 
			
		||||
    public LobbyMenu(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        // Entfernt das CreateGameMenu (inklusive Hintergrund)
 | 
			
		||||
        app.getGuiNode().detachAllChildren();
 | 
			
		||||
        app.getGuiNode().detachAllChildren(); // Entfernt das CreateGameMenu (inklusive Hintergrund)
 | 
			
		||||
 | 
			
		||||
        // Hintergrundbild laden und hinzufügen
 | 
			
		||||
        addBackgroundImage();
 | 
			
		||||
        addBackgroundImage();// Hintergrundbild laden und hinzufügen
 | 
			
		||||
 | 
			
		||||
        QuadBackgroundComponent translucentWhiteBackground =
 | 
			
		||||
                new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
 | 
			
		||||
 | 
			
		||||
        menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
 | 
			
		||||
        menuContainer.setPreferredSize(new Vector3f(1000, 600, 0)); // Fixed size of the container
 | 
			
		||||
        menuContainer.setPreferredSize(new Vector3f(1000, 600, 0));
 | 
			
		||||
        menuContainer.setBackground(translucentWhiteBackground);
 | 
			
		||||
 | 
			
		||||
        // Create a smaller horizontal container for the label, input field, and spacers
 | 
			
		||||
        Container horizontalContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
 | 
			
		||||
        horizontalContainer.setPreferredSize(new Vector3f(600, 40, 0)); // Adjust container size
 | 
			
		||||
        horizontalContainer.setPreferredSize(new Vector3f(600, 40, 0));
 | 
			
		||||
        horizontalContainer.setBackground(null);
 | 
			
		||||
 | 
			
		||||
        Label title = horizontalContainer.addChild(new Label("Startkapital:", new ElementId("label-Bold")));
 | 
			
		||||
@@ -61,7 +78,7 @@ public class LobbyMenu {
 | 
			
		||||
        spacerBeforeInput.setPreferredSize(new Vector3f(20, 1, 0)); // Width of the spacer
 | 
			
		||||
 | 
			
		||||
        // Add an input field (TextField)
 | 
			
		||||
        TextField startingCapital = horizontalContainer.addChild(new TextField(""));
 | 
			
		||||
        horizontalContainer.addChild(startingCapital);
 | 
			
		||||
        startingCapital.setPreferredWidth(100); // Set the width of the input field
 | 
			
		||||
        startingCapital.setPreferredSize(new Vector3f(150, 50, 0));
 | 
			
		||||
        startingCapital.setInsets(new Insets3f(5, 10, 5, 10)); // Add padding around the text inside the field
 | 
			
		||||
@@ -88,29 +105,35 @@ public class LobbyMenu {
 | 
			
		||||
        playerInputContainer.setBackground(null);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        TextField playerInputField = new TextField("");
 | 
			
		||||
        playerInputField.setPreferredSize(new Vector3f(100, 20, 0));
 | 
			
		||||
        playerInputField.setInsets(new Insets3f(5, 10, 5, 10)); // Add padding for the text inside the field
 | 
			
		||||
        playerInputField.setInsets(new Insets3f(5, 10, 5, 10));
 | 
			
		||||
        playerInputField.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
 | 
			
		||||
        playerInputContainer.addChild(playerInputField);
 | 
			
		||||
        // Spacer (Center Circle Area)
 | 
			
		||||
        Label spacer = dropdownContainer.addChild(new Label(""));
 | 
			
		||||
        spacer.setPreferredSize(new Vector3f(200, 200, 0)); // Adjust this to fit the center graphic
 | 
			
		||||
        spacer.setPreferredSize(new Vector3f(200, 200, 0));
 | 
			
		||||
 | 
			
		||||
        // Figur Dropdown
 | 
			
		||||
        Container figureDropdownContainer = dropdownContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X)));
 | 
			
		||||
        figureDropdownContainer.setPreferredSize(new Vector3f(150, 80, 0));
 | 
			
		||||
        figureDropdownContainer.addChild(new Label("Figur:"));
 | 
			
		||||
        figureDropdownContainer.setBackground(null);
 | 
			
		||||
 | 
			
		||||
        VersionedList<String> figures = new VersionedList<>();
 | 
			
		||||
        figures.add("Hund");
 | 
			
		||||
        figures.add("Laptop");
 | 
			
		||||
        figures.add("Flugzeug");
 | 
			
		||||
        figures.add("Jägermeister");
 | 
			
		||||
        figures.add("Katze");
 | 
			
		||||
        figures.add("Panzer");
 | 
			
		||||
        figures.add("Pot");
 | 
			
		||||
        figures.add("OOP");
 | 
			
		||||
        figures.add("Handyholster");
 | 
			
		||||
 | 
			
		||||
        Selector<String> figureDropdown = new Selector<>(figures, "glass");
 | 
			
		||||
        figureDropdown.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
 | 
			
		||||
        figureDropdown.setPreferredSize(new Vector3f(100, 20, 0));
 | 
			
		||||
        figureDropdown.setPreferredSize(new Vector3f(150, 140, 0));
 | 
			
		||||
        Vector3f dimens = figureDropdownContainer.getPreferredSize();
 | 
			
		||||
        Vector3f dimens2 = figureDropdown.getPopupContainer().getPreferredSize();
 | 
			
		||||
        dimens2.setX( dimens.getX() );
 | 
			
		||||
        figureDropdown.getPopupContainer().setPreferredSize( dimens2 );
 | 
			
		||||
        figureDropdownContainer.addChild(figureDropdown);
 | 
			
		||||
 | 
			
		||||
        addSelectionActionListener(figureDropdown, this::onDropdownSelectionChanged);
 | 
			
		||||
@@ -120,32 +143,39 @@ public class LobbyMenu {
 | 
			
		||||
        buttonContainer.setInsets(new Insets3f(20, 0, 10, 0)); // Add spacing above the buttons
 | 
			
		||||
        buttonContainer.setBackground(null);
 | 
			
		||||
        // Lower-left container for "Abbrechen" button
 | 
			
		||||
        Container lowerLeftMenu = new Container();
 | 
			
		||||
        Button cancelButton = new Button("Abbrechen");
 | 
			
		||||
        lowerLeftMenu = new Container();
 | 
			
		||||
        Button cancelButton = new Button("Beenden");
 | 
			
		||||
        cancelButton.setPreferredSize(new Vector3f(200, 60, 0)); // Set size to match the appearance in the image
 | 
			
		||||
        cancelButton.setFontSize(18); // Adjust font size
 | 
			
		||||
        cancelButton.addClickCommands(source -> goBackToCreateGame()); // Add functionality
 | 
			
		||||
        cancelButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.closeApp();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        lowerLeftMenu.addChild(cancelButton);
 | 
			
		||||
 | 
			
		||||
// Position the container near the bottom-left corner
 | 
			
		||||
        // Position the container near the bottom-left corner
 | 
			
		||||
        lowerLeftMenu.setLocalTranslation(new Vector3f(120, 170, 3)); // Adjust X and Y to align with the bottom-left corner
 | 
			
		||||
        app.getGuiNode().attachChild(lowerLeftMenu);
 | 
			
		||||
 | 
			
		||||
// Lower-right container for "Bereit" button
 | 
			
		||||
        Container lowerRightMenu = new Container();
 | 
			
		||||
        // Lower-right container for "Bereit" button
 | 
			
		||||
        lowerRightMenu = new Container();
 | 
			
		||||
        Button readyButton = new Button("Bereit");
 | 
			
		||||
        readyButton.setPreferredSize(new Vector3f(200, 60, 0)); // Set size to match the appearance in the image
 | 
			
		||||
        readyButton.setFontSize(18); // Adjust font size
 | 
			
		||||
        readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.Green)); // Add color to match the style
 | 
			
		||||
        readyButton.addClickCommands(source -> toggleReady(null)); // Add functionality
 | 
			
		||||
        readyButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            toggleReady();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        lowerRightMenu.addChild(readyButton);
 | 
			
		||||
        //TODO aktivieren des Spielers in den ready Status und Sprung in den nächsten Menüzustand
 | 
			
		||||
 | 
			
		||||
// Position the container near the bottom-right corner
 | 
			
		||||
        // Position the container near the bottom-right corner
 | 
			
		||||
        lowerRightMenu.setLocalTranslation(new Vector3f(app.getCamera().getWidth() - 320, 170, 3)); // X: 220px from the right, Y: 50px above the bottom
 | 
			
		||||
        app.getGuiNode().attachChild(lowerRightMenu);
 | 
			
		||||
 | 
			
		||||
        // Add a colored circle between the input field and the dropdown menu
 | 
			
		||||
        Geometry circle = createCircle( ColorRGBA.Red); // 50 is the diameter, Red is the color
 | 
			
		||||
        circle = createCircle(); // 50 is the diameter, Red is the color
 | 
			
		||||
        circle.setLocalTranslation(new Vector3f(
 | 
			
		||||
                (app.getCamera().getWidth()) / 2, // Center horizontally
 | 
			
		||||
                (app.getCamera().getHeight() / 2) - 90, // Adjust Y position
 | 
			
		||||
@@ -162,7 +192,59 @@ public class LobbyMenu {
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(menuContainer);
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Apply the starting capital only if the current player is the host.
 | 
			
		||||
     */
 | 
			
		||||
    private void applyStartingCapital(int playerID) {
 | 
			
		||||
            Player currentPlayer = playerHandler.getPlayerById(playerID);
 | 
			
		||||
 | 
			
		||||
            // Check if the current player is the host
 | 
			
		||||
            if (currentPlayer.equals(playerHandler.getHostPlayer())) {
 | 
			
		||||
                try {
 | 
			
		||||
                    // Parse and validate starting capital
 | 
			
		||||
                    int startBalance = Integer.parseInt(startingCapital.getText().replaceAll("[^\\d]", ""));
 | 
			
		||||
                    if (startBalance < 0) throw new NumberFormatException("Starting capital must be positive.");
 | 
			
		||||
 | 
			
		||||
                    // Apply the starting balance to all players
 | 
			
		||||
                    playerHandler.setStartBalance(startBalance);
 | 
			
		||||
                    System.out.println("Starting balance set to: " + startBalance);
 | 
			
		||||
                } catch (NumberFormatException e) {
 | 
			
		||||
                    System.err.println("Invalid starting capital: " + e.getMessage());
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                System.out.println("Only the host can set the starting balance.");
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Apply the player name from the input field.
 | 
			
		||||
     */
 | 
			
		||||
    private void applyPlayerName(int playerID) {
 | 
			
		||||
        Player currentPlayer = playerHandler.getPlayerById(playerID);
 | 
			
		||||
 | 
			
		||||
        String playerName = playerInputField.getText().trim();
 | 
			
		||||
        if (!playerName.isEmpty()) {
 | 
			
		||||
            currentPlayer.setName(playerName);
 | 
			
		||||
            System.out.println("Player name set to: " + playerName);
 | 
			
		||||
        } else {
 | 
			
		||||
            System.err.println("Invalid player name: Name cannot be empty.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Apply the selected figure to the player.
 | 
			
		||||
     */
 | 
			
		||||
    private void applyFigure(int playerID) {
 | 
			
		||||
        Player currentPlayer = playerHandler.getPlayerById(playerID);
 | 
			
		||||
 | 
			
		||||
        String selectedFigure = figureDropdown.getSelectedItem();
 | 
			
		||||
        if (selectedFigure != null && !selectedFigure.isEmpty()) {
 | 
			
		||||
            currentPlayer.setFigure(new Figure(0, 0, 0, Rotation.RIGHT, "selectedFigure"));
 | 
			
		||||
            System.out.println("Player figure set to: " + selectedFigure);
 | 
			
		||||
        } else {
 | 
			
		||||
            System.err.println("Invalid figure selection.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu.
 | 
			
		||||
@@ -179,34 +261,40 @@ public class LobbyMenu {
 | 
			
		||||
        app.getGuiNode().attachChild(background);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Geometry createCircle(ColorRGBA color) {
 | 
			
		||||
    private Geometry createCircle() {
 | 
			
		||||
 | 
			
		||||
        Sphere sphere = new Sphere(90,90,60.0f);
 | 
			
		||||
        Geometry circleGeometry = new Geometry("Circle", sphere);
 | 
			
		||||
 | 
			
		||||
        // Create a material with a solid color
 | 
			
		||||
        Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
        material.setColor("Color", color); // Set the desired color
 | 
			
		||||
        material.setColor("Color", playerColor); // Set the desired color
 | 
			
		||||
        circleGeometry.setMaterial(material);
 | 
			
		||||
 | 
			
		||||
        return circleGeometry;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Schaltet den "Bereit"-Status um.
 | 
			
		||||
     */
 | 
			
		||||
    private void toggleReady(Label playersLabel) {
 | 
			
		||||
        // Beispiel-Logik für das Umschalten des Status
 | 
			
		||||
        playersLabel.setText("Spielerstatus aktualisiert."); // Beispieltext
 | 
			
		||||
    public void setPlayerColor(ColorRGBA newColor) {
 | 
			
		||||
        this.playerColor = newColor;
 | 
			
		||||
        // Update the circle's color
 | 
			
		||||
        if (circle != null) {
 | 
			
		||||
            Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
 | 
			
		||||
            material.setColor("Color", playerColor);
 | 
			
		||||
            circle.setMaterial(material);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Geht zurück zum CreateGameMenu.
 | 
			
		||||
     * Assigns a color to the player based on their ID.
 | 
			
		||||
     *
 | 
			
		||||
     * @param playerID the player's ID
 | 
			
		||||
     */
 | 
			
		||||
    private void goBackToCreateGame() {
 | 
			
		||||
        app.getGuiNode().detachChild(menuContainer);
 | 
			
		||||
        app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild
 | 
			
		||||
        new CreateGameMenu(app);
 | 
			
		||||
    private void toggleReady() {
 | 
			
		||||
        app.getGameLogic().send(new PlayerReady(true, playerInputField.getText(), figure, Integer.parseInt(startingCapital.getText())));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -250,21 +338,28 @@ public class LobbyMenu {
 | 
			
		||||
     */
 | 
			
		||||
    private void onDropdownSelectionChanged(String selected) {
 | 
			
		||||
        System.out.println("Selected: " + selected);
 | 
			
		||||
        app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        switch (selected) {
 | 
			
		||||
            case "[0]":
 | 
			
		||||
                System.out.println("Alpha selected");
 | 
			
		||||
                figure = "Laptop";
 | 
			
		||||
                break;
 | 
			
		||||
            case "[1]":
 | 
			
		||||
                System.out.println("Beta selected");
 | 
			
		||||
                figure = "Flugzeug";
 | 
			
		||||
                break;
 | 
			
		||||
            case "[2]":
 | 
			
		||||
                System.out.println("Gamma selected");
 | 
			
		||||
                figure = "Jägermeister";
 | 
			
		||||
                break;
 | 
			
		||||
            case "[3]":
 | 
			
		||||
                goBackToCreateGame();
 | 
			
		||||
                figure = "Katze";
 | 
			
		||||
                break;
 | 
			
		||||
            case "[4]":
 | 
			
		||||
                figure = "OOP";
 | 
			
		||||
                break;
 | 
			
		||||
            case "[5]":
 | 
			
		||||
                figure = "Handyholster";
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                System.out.println("Unknown selection");
 | 
			
		||||
                break;    
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,123 +1,92 @@
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// 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.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import java.util.prefs.Preferences;
 | 
			
		||||
 | 
			
		||||
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 com.simsilica.lemur.ValueRenderer;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Selector;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import static pp.monopoly.Resources.lookup;
 | 
			
		||||
import pp.monopoly.client.GameMusic;
 | 
			
		||||
import pp.monopoly.client.GameSound;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.dialog.StateCheckboxModel;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
import static pp.util.PreferencesUtils.getPreferences;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
public class SettingsMenu extends Dialog {
 | 
			
		||||
    private static final Preferences PREFERENCES = getPreferences(SettingsMenu.class);
 | 
			
		||||
    private static final String LAST_PATH = "last.file.path";
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private final Container settingsContainer;
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private final VolumeSlider musicSlider;
 | 
			
		||||
    private final SoundSlider soundSlider;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Menu dialog for the Battleship application.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app the MonopolyApp instance
 | 
			
		||||
     */
 | 
			
		||||
    public SettingsMenu(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        musicSlider = new VolumeSlider(app.getStateManager().getState(GameMusic.class));
 | 
			
		||||
        soundSlider = new SoundSlider(app.getStateManager().getState(GameSound.class));
 | 
			
		||||
        addChild(new Label("Einstellungen", new ElementId("settings-title"))); //NON-NLS
 | 
			
		||||
        addChild(new Label("Sound Effekte", new ElementId("label"))); //NON-NLS
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
        addChild(soundSlider);
 | 
			
		||||
 | 
			
		||||
        // 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);
 | 
			
		||||
        addChild(new Checkbox("Soundeffekte an / aus", new StateCheckboxModel(app, GameSound.class)));
 | 
			
		||||
        
 | 
			
		||||
        addChild(new Label("Hintergrund Musik", new ElementId("label"))); //NON-NLS
 | 
			
		||||
        addChild(new Checkbox("Musik an / aus", new StateCheckboxModel(app, GameMusic.class)));
 | 
			
		||||
        
 | 
			
		||||
        addChild(musicSlider);
 | 
			
		||||
 | 
			
		||||
        // 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);
 | 
			
		||||
        addChild(new Button("Zurück zum Spiel", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            this.close();  // Close the StartMenu dialog
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        addChild(new Button("Beenden", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
            app.closeApp();
 | 
			
		||||
        }));
 | 
			
		||||
        update();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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.
 | 
			
		||||
     * Updates the state of the load and save buttons based on the game logic.
 | 
			
		||||
     */
 | 
			
		||||
    @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
 | 
			
		||||
    public void update() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float delta) {
 | 
			
		||||
        musicSlider.update();
 | 
			
		||||
        soundSlider.update();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * As an escape action, this method closes the menu if it is the top dialog.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Slider;
 | 
			
		||||
import pp.monopoly.client.GameSound;
 | 
			
		||||
 | 
			
		||||
public class SoundSlider extends Slider {
 | 
			
		||||
 | 
			
		||||
    private final pp.monopoly.client.GameSound sound;
 | 
			
		||||
    private double vol;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Volume Slider for the Menu dialog
 | 
			
		||||
     * @param sound the Effects sound instance
 | 
			
		||||
     */
 | 
			
		||||
    public SoundSlider(GameSound sound) {
 | 
			
		||||
        super();
 | 
			
		||||
        this.sound = sound;
 | 
			
		||||
        vol = GameSound.volumeInPreferences();
 | 
			
		||||
        getModel().setPercent(vol);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * when triggered it updates the volume to the value set with the slider
 | 
			
		||||
     */
 | 
			
		||||
    public void update() {
 | 
			
		||||
        if (vol != getModel().getPercent()) {
 | 
			
		||||
            vol = getModel().getPercent();
 | 
			
		||||
            sound.setVolume( (float) vol);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package pp.monopoly.client;
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
@@ -13,8 +13,8 @@ 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;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Constructs the startup menu dialog for the Monopoly application.
 | 
			
		||||
@@ -22,8 +22,6 @@ 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.
 | 
			
		||||
@@ -33,13 +31,7 @@ public class StartMenu extends Dialog {
 | 
			
		||||
    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();
 | 
			
		||||
 | 
			
		||||
@@ -53,9 +45,6 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        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));
 | 
			
		||||
 | 
			
		||||
@@ -64,7 +53,11 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        startButton.setFontSize(40); // Set the font size for the button text
 | 
			
		||||
        startButton.setTextHAlignment(HAlignment.Center); // Center the text horizontally
 | 
			
		||||
 | 
			
		||||
        startButton.addClickCommands(source -> startGame(app));
 | 
			
		||||
        startButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            this.close();  // Close the StartMenu dialog
 | 
			
		||||
            app.connect(); // Perform the connection logic
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        centerMenu.addChild(startButton);
 | 
			
		||||
 | 
			
		||||
        // Position the center container in the middle of the screen
 | 
			
		||||
@@ -73,34 +66,6 @@ public class StartMenu extends Dialog {
 | 
			
		||||
                                                    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");
 | 
			
		||||
 | 
			
		||||
@@ -123,14 +88,6 @@ public class StartMenu extends Dialog {
 | 
			
		||||
 | 
			
		||||
        // 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");
 | 
			
		||||
@@ -156,26 +113,14 @@ public class StartMenu extends Dialog {
 | 
			
		||||
        app.getGuiNode().attachChild(unibwContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts the game by transitioning to the CreateGameMenu.
 | 
			
		||||
     */
 | 
			
		||||
    private static void startGame(MonopolyApp app) {
 | 
			
		||||
        app.getGuiNode().detachAllChildren();
 | 
			
		||||
        new CreateGameMenu(app);
 | 
			
		||||
    @Override
 | 
			
		||||
    public void escape() {
 | 
			
		||||
        new SettingsMenu(app).open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the settings menu.
 | 
			
		||||
     */
 | 
			
		||||
    private static void openSettings(MonopolyApp app) {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        app.getGuiNode().detachAllChildren();
 | 
			
		||||
        new SettingsMenu(app);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Quits the game application.
 | 
			
		||||
     */
 | 
			
		||||
    private static void quitGame() {
 | 
			
		||||
        System.exit(0);
 | 
			
		||||
        super.close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,6 +14,7 @@ import com.simsilica.lemur.component.SpringGridLayout;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.notification.Sound;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
 | 
			
		||||
@@ -135,7 +136,10 @@ public class Toolbar extends Dialog {
 | 
			
		||||
    private Button addDiceRollButton() {
 | 
			
		||||
        Button diceButton = new Button("Würfeln");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(50, 20, 0));
 | 
			
		||||
        diceButton.addClickCommands(source -> rollDice());
 | 
			
		||||
        diceButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            rollDice();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
        return diceButton;
 | 
			
		||||
    }
 | 
			
		||||
@@ -143,21 +147,30 @@ public class Toolbar extends Dialog {
 | 
			
		||||
    private void addTradeMenuButton() {
 | 
			
		||||
        Button diceButton = new Button("Handeln");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
 | 
			
		||||
        diceButton.addClickCommands(source -> rollDice());
 | 
			
		||||
        diceButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            rollDice();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void addEndTurnButton() {
 | 
			
		||||
        Button diceButton = new Button("Grundstücke");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
 | 
			
		||||
        diceButton.addClickCommands(source -> rollDice());
 | 
			
		||||
        diceButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            rollDice();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void addPropertyMenuButton() {
 | 
			
		||||
        Button diceButton = new Button("Zug beenden");
 | 
			
		||||
        diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
 | 
			
		||||
        diceButton.addClickCommands(source -> rollDice());
 | 
			
		||||
        diceButton.addClickCommands(s -> ifTopDialog(() -> {
 | 
			
		||||
            rollDice();
 | 
			
		||||
            app.getGameLogic().playSound(Sound.BUTTON);
 | 
			
		||||
        }));
 | 
			
		||||
        toolbarContainer.addChild(diceButton);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,37 @@
 | 
			
		||||
package pp.monopoly.client.gui;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Slider;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.client.GameMusic;
 | 
			
		||||
/**
 | 
			
		||||
 * The VolumeSlider class represents the Volume Slider in the Menu.
 | 
			
		||||
 * It extends the Slider class and provides functionalities for setting the music volume,
 | 
			
		||||
 * with the help of the Slider in the GUI 
 | 
			
		||||
 */
 | 
			
		||||
public class VolumeSlider extends Slider {
 | 
			
		||||
 | 
			
		||||
    private final pp.monopoly.client.GameMusic music;
 | 
			
		||||
    private double vol;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Volume Slider for the Menu dialog
 | 
			
		||||
     * @param music the music instance
 | 
			
		||||
     */
 | 
			
		||||
    public VolumeSlider(GameMusic music) {
 | 
			
		||||
        super();
 | 
			
		||||
        this.music = music;
 | 
			
		||||
        vol = GameMusic.volumeInPreferences();
 | 
			
		||||
        getModel().setPercent(vol);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * when triggered it updates the volume to the value set with the slider
 | 
			
		||||
     */
 | 
			
		||||
    public void update() {
 | 
			
		||||
        if (vol != getModel().getPercent()) {
 | 
			
		||||
            vol = getModel().getPercent();
 | 
			
		||||
            music.setVolume( (float) vol);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -23,14 +23,14 @@ public class BuildingPropertyCard extends Dialog {
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private final Container buildingPropertyContainer;
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
    private int index = 39;
 | 
			
		||||
    private int index = 37;
 | 
			
		||||
 | 
			
		||||
    public BuildingPropertyCard(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        BuildingProperty field = (BuildingProperty) app.getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
        BuildingProperty field = (BuildingProperty) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
@@ -121,7 +121,7 @@ public class BuildingPropertyCard extends Dialog {
 | 
			
		||||
        app.getGuiNode().detachChild(buildingPropertyContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren
 | 
			
		||||
        app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
 | 
			
		||||
        app.unblockInputs();                             // Eingaben wieder aktivieren
 | 
			
		||||
        System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,14 +3,16 @@ package pp.monopoly.client.gui.popups;
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.math.Vector3f;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.*;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
 | 
			
		||||
@@ -18,13 +20,18 @@ import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
public class BuyCard extends Dialog {
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private final Container settingsContainer;
 | 
			
		||||
    private final Container buyCardContainer;
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
    private int index = 37;
 | 
			
		||||
 | 
			
		||||
    public BuyCard(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        BuildingProperty field = (BuildingProperty) app.getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
@@ -34,52 +41,55 @@ public class BuyCard extends Dialog {
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für das Menü
 | 
			
		||||
        settingsContainer = new Container();
 | 
			
		||||
        settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
        buyCardContainer = new Container();
 | 
			
		||||
        buyCardContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        Label settingsTitle = settingsContainer.addChild(new Label("Gebäude 30", new ElementId("settings-title"))); //TODO Dynamische Gebäudezahl einfügen
 | 
			
		||||
        Label settingsTitle = buyCardContainer.addChild(new Label( field.getName(), new ElementId("settings-title")));
 | 
			
		||||
        settingsTitle.setFontSize(48);
 | 
			
		||||
 | 
			
		||||
        int i = 0;
 | 
			
		||||
        int a = 10;
 | 
			
		||||
        int b = -45;
 | 
			
		||||
 | 
			
		||||
        // Effekt-Sound: Slider und Checkbox
 | 
			
		||||
        Container propertyValuesContainer = settingsContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Preis:" + i, new ElementId("label-Text")));//TODO Variable hier einsetzen
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Miete:" + a, new ElementId("label-Text")));//TODO Variable hier einsetzen
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek:" + b, new ElementId("label-Text")));//TODO Variable hier einsetzen
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Preise werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        Container propertyValuesContainer = buyCardContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 1 Haus: " + field.getAllRent().get(1) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 2 Häuser: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 3 Häuser: " + field.getAllRent().get(3) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 4 Häuser: " + field.getAllRent().get(4) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-mit 1 Hotel: " + field.getAllRent().get(5) + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„-1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
 | 
			
		||||
        propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        Button quitButton = buyCardContainer.addChild(new Button("Beenden", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        // Kaufen-Button
 | 
			
		||||
        Button buyButton = settingsContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        Button buyButton = buyCardContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        buyButton.setFontSize(32);
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Padding around the settingsContainer for the background
 | 
			
		||||
        backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
        backgroundContainer.setPreferredSize(buyCardContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        settingsContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2,
 | 
			
		||||
        buyCardContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                (app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(settingsContainer);
 | 
			
		||||
        app.getGuiNode().attachChild(buyCardContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -104,13 +114,11 @@ public class BuyCard extends Dialog {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() {
 | 
			
		||||
        System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
 | 
			
		||||
        app.getGuiNode().detachChild(settingsContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(buyCardContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren
 | 
			
		||||
        app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
 | 
			
		||||
        app.unblockInputs();                             // Eingaben wieder aktivieren
 | 
			
		||||
        System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,118 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.material.Material;
 | 
			
		||||
import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.card.Card; // TODO für den Import der Queue notwendig
 | 
			
		||||
/**
 | 
			
		||||
 * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
 | 
			
		||||
 */
 | 
			
		||||
public class EventCard extends Dialog {
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
    private final Geometry overlayBackground;
 | 
			
		||||
    private final Container eventCardContainer;
 | 
			
		||||
    private final Container backgroundContainer;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public EventCard(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        Card card = app.getDeckHelper().drawCard(); // TODO nimmt die Karten gerade unabhängig aus dem DeckHelper
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
        app.getGuiNode().attachChild(overlayBackground);
 | 
			
		||||
 | 
			
		||||
        // Create the background container
 | 
			
		||||
        backgroundContainer = new Container();
 | 
			
		||||
        backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
 | 
			
		||||
        app.getGuiNode().attachChild(backgroundContainer);
 | 
			
		||||
 | 
			
		||||
        // Hauptcontainer für die Gebäudekarte
 | 
			
		||||
        eventCardContainer = new Container();
 | 
			
		||||
        eventCardContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        // Die Namen werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        Label gateFieldTitle = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Preise werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        Container propertyValuesContainer = eventCardContainer.addChild(new Container());
 | 
			
		||||
        propertyValuesContainer.addChild(new Label(card.getDescription(), new ElementId("label-Text")));
 | 
			
		||||
        propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
 | 
			
		||||
 | 
			
		||||
        // Beenden-Button
 | 
			
		||||
        Button quitButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
 | 
			
		||||
        quitButton.setFontSize(32);
 | 
			
		||||
        quitButton.addClickCommands(source -> close());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // TODO Kaufen-Button wird nicht mehr benötigt, prüfen ob weg kann
 | 
			
		||||
        //Button buyButton = buyCardContainer.addChild(new Button("Kaufen", new ElementId("button")));
 | 
			
		||||
        //buyButton.setFontSize(32);
 | 
			
		||||
 | 
			
		||||
        float padding = 10; // Padding around the settingsContainer for the background
 | 
			
		||||
        backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Zentriere das Menü
 | 
			
		||||
        eventCardContainer.setLocalTranslation(
 | 
			
		||||
            (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x) / 2,
 | 
			
		||||
            (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y) / 2,
 | 
			
		||||
            8
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        backgroundContainer.setLocalTranslation(
 | 
			
		||||
                (app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x - padding) / 2,
 | 
			
		||||
                (app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y+ padding) / 2,
 | 
			
		||||
                7
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        app.getGuiNode().attachChild(eventCardContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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(eventCardContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.setBuyCardPopupOpen(false);                  // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
 | 
			
		||||
        app.unblockInputs();                             // Eingaben wieder aktivieren
 | 
			
		||||
        System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,6 @@ import com.jme3.material.RenderState.BlendMode;
 | 
			
		||||
import com.jme3.math.ColorRGBA;
 | 
			
		||||
import com.jme3.scene.Geometry;
 | 
			
		||||
import com.jme3.scene.shape.Quad;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.QuadBackgroundComponent;
 | 
			
		||||
@@ -30,7 +29,7 @@ public class FoodFieldCard extends Dialog {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        FoodField field = (FoodField) app.getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
        FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
@@ -125,7 +124,7 @@ public class FoodFieldCard extends Dialog {
 | 
			
		||||
        app.getGuiNode().detachChild(foodFieldContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren
 | 
			
		||||
        app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
 | 
			
		||||
        app.unblockInputs();                             // Eingaben wieder aktivieren
 | 
			
		||||
        System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ public class GateFieldCard extends Dialog {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        //Generate the corresponfing field
 | 
			
		||||
        GateField field = (GateField) app.getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
        GateField field = (GateField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Halbtransparentes Overlay hinzufügen
 | 
			
		||||
        overlayBackground = createOverlayBackground();
 | 
			
		||||
@@ -45,9 +45,9 @@ public class GateFieldCard extends Dialog {
 | 
			
		||||
 | 
			
		||||
        // Titel
 | 
			
		||||
        // Die Namen werden dynamisch dem BoardManager entnommen
 | 
			
		||||
        Label settingsTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title")));
 | 
			
		||||
        settingsTitle.setFontSize(48);
 | 
			
		||||
        settingsTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
        Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title")));
 | 
			
		||||
        gateFieldTitle.setFontSize(48);
 | 
			
		||||
        gateFieldTitle.setColor(ColorRGBA.Black);
 | 
			
		||||
 | 
			
		||||
        // Text, der auf der Karte steht
 | 
			
		||||
        // Die Preise werden dynamisch dem BoardManager entnommen
 | 
			
		||||
@@ -118,7 +118,7 @@ public class GateFieldCard extends Dialog {
 | 
			
		||||
        app.getGuiNode().detachChild(gateFieldContainer);  // Entferne das Menü
 | 
			
		||||
        app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
 | 
			
		||||
        app.getGuiNode().detachChild(overlayBackground);  // Entferne das Overlay
 | 
			
		||||
        app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren
 | 
			
		||||
        app.setSettingsMenuOpen(false);                  // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
 | 
			
		||||
        app.unblockInputs();                             // Eingaben wieder aktivieren
 | 
			
		||||
        System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.IconComponent;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
public class LooserPopUp extends Dialog {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new NetworkDialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param network The NetworkSupport instance to be used for network operations.
 | 
			
		||||
     */
 | 
			
		||||
    public LooserPopUp(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        initializeDialog();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the dialog with input fields and connection buttons.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeDialog() {
 | 
			
		||||
        Container inputContainer = new Container();
 | 
			
		||||
 | 
			
		||||
        // Titel und Eingabefelder für Host und Port
 | 
			
		||||
        inputContainer.addChild(new Label("Schade, du hast leider verloren!"));
 | 
			
		||||
        inputContainer.addChild(new Label("Die nächste Runde wird besser!"));
 | 
			
		||||
 | 
			
		||||
        Label imageLabel = new Label("");
 | 
			
		||||
        IconComponent icon = new IconComponent("Pictures/MonopolyLooser.png"); // Icon mit Textur erstellen
 | 
			
		||||
        icon.setIconScale(1); // Skalierung des Bildes
 | 
			
		||||
        imageLabel.setIcon(icon);
 | 
			
		||||
 | 
			
		||||
        // Setze das Icon im Label
 | 
			
		||||
        inputContainer.addChild(imageLabel);
 | 
			
		||||
 | 
			
		||||
        Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
 | 
			
		||||
        cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
 | 
			
		||||
        
 | 
			
		||||
        inputContainer.setLocalTranslation(300, 800, 0);
 | 
			
		||||
        app.getGuiNode().attachChild(inputContainer);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.jme3.asset.TextureKey;
 | 
			
		||||
import com.jme3.math.Vector2f;
 | 
			
		||||
import com.jme3.texture.Texture;
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.IconComponent;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
public class LoserPopUp extends Dialog {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new NetworkDialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param network The NetworkSupport instance to be used for network operations.
 | 
			
		||||
     */
 | 
			
		||||
    public LoserPopUp(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        initializeDialog();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the dialog with input fields and connection buttons.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeDialog() {
 | 
			
		||||
        Container inputContainer = new Container();
 | 
			
		||||
 | 
			
		||||
        // Titel und Eingabefelder für Host und Port
 | 
			
		||||
        inputContainer.addChild(new Label("Schade, du hast leider verloren!"));
 | 
			
		||||
        inputContainer.addChild(new Label("Die nächste Runde wird besser!"));
 | 
			
		||||
 | 
			
		||||
        Label imageLabel = new Label("");
 | 
			
		||||
        TextureKey key = new TextureKey("Pictures/MonopolyLoser.png", true);
 | 
			
		||||
        Texture texture = app.getAssetManager().loadTexture(key);
 | 
			
		||||
        IconComponent icon = new IconComponent(texture.toString());     // Icon mit Textur erstellen
 | 
			
		||||
        icon.setIconSize(new Vector2f(155f, 120f));     // Skalierung des Bildes
 | 
			
		||||
        imageLabel.setIcon(icon);       // Setze das Icon im Label
 | 
			
		||||
 | 
			
		||||
        inputContainer.addChild(imageLabel);
 | 
			
		||||
 | 
			
		||||
        Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
 | 
			
		||||
        cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
 | 
			
		||||
        inputContainer.setLocalTranslation(300,500,0);
 | 
			
		||||
        attachChild(inputContainer);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,51 @@
 | 
			
		||||
package pp.monopoly.client.gui.popups;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Container;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.component.IconComponent;
 | 
			
		||||
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
import pp.monopoly.client.MonopolyApp;
 | 
			
		||||
 | 
			
		||||
public class WinnerPopUp extends Dialog {
 | 
			
		||||
 | 
			
		||||
    private final MonopolyApp app;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a new NetworkDialog.
 | 
			
		||||
     *
 | 
			
		||||
     * @param app The NetworkSupport instance to be used for network operations.
 | 
			
		||||
     */
 | 
			
		||||
    public WinnerPopUp(MonopolyApp app) {
 | 
			
		||||
        super(app.getDialogManager());
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        initializeDialog();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializes the dialog with input fields and connection buttons.
 | 
			
		||||
     */
 | 
			
		||||
    private void initializeDialog() {
 | 
			
		||||
        Container inputContainer = new Container();
 | 
			
		||||
 | 
			
		||||
        // Titel und Eingabefelder für Host und Port
 | 
			
		||||
        inputContainer.addChild(new Label("Herlichen Glückwunsch!"));
 | 
			
		||||
        inputContainer.addChild(new Label("Du,bist der Monopoly Champion!!!"));
 | 
			
		||||
 | 
			
		||||
        Label imageLabel = new Label("");
 | 
			
		||||
        IconComponent icon = new IconComponent("Pictures/MonopolyWinner.png"); // Icon mit Textur erstellen
 | 
			
		||||
        icon.setIconScale(1); // Skalierung des Bildes
 | 
			
		||||
        imageLabel.setIcon(icon);
 | 
			
		||||
 | 
			
		||||
        // Setze das Icon im Label
 | 
			
		||||
        inputContainer.addChild(imageLabel);
 | 
			
		||||
 | 
			
		||||
        Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
 | 
			
		||||
        cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
 | 
			
		||||
        
 | 
			
		||||
        inputContainer.setLocalTranslation(300, 800, 0);
 | 
			
		||||
        app.getGuiNode().attachChild(inputContainer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
		 After Width: | Height: | Size: 260 KiB  | 
| 
		 After Width: | Height: | Size: 260 KiB  | 
| 
		 After Width: | Height: | Size: 409 KiB  | 
| 
		 After Width: | Height: | Size: 105 KiB  | 
| 
		 After Width: | Height: | Size: 207 KiB  | 
| 
		 After Width: | Height: | Size: 169 KiB  | 
| 
		 After Width: | Height: | Size: 228 KiB  | 
| 
		 After Width: | Height: | Size: 183 KiB  | 
| 
		 After Width: | Height: | Size: 171 KiB  | 
@@ -28,7 +28,7 @@ public class MonopolyConfig extends Config {
 | 
			
		||||
     * The default port number for the Monopoly server.
 | 
			
		||||
     */
 | 
			
		||||
    @Property("port")
 | 
			
		||||
    private int port = 4321;
 | 
			
		||||
    private int port = 42069;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The width of the game map in terms of grid units.
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import java.lang.System.Logger.Level;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.message.client.ClientMessage;
 | 
			
		||||
import pp.monopoly.message.server.BuyPropertyResponse;
 | 
			
		||||
import pp.monopoly.message.server.DiceResult;
 | 
			
		||||
@@ -21,6 +22,7 @@ import pp.monopoly.message.server.TradeRequest;
 | 
			
		||||
import pp.monopoly.message.server.ViewAssetsResponse;
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.model.IntPoint;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.notification.ClientStateEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEvent;
 | 
			
		||||
import pp.monopoly.notification.GameEventBroker;
 | 
			
		||||
@@ -50,6 +52,10 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
    /** The current state of the client game logic. */
 | 
			
		||||
    private ClientState state = new LobbyState(this);
 | 
			
		||||
 | 
			
		||||
    private List<Player> players;
 | 
			
		||||
 | 
			
		||||
    private BoardManager boardManager = new BoardManager();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a ClientGameLogic with the specified sender object.
 | 
			
		||||
     *
 | 
			
		||||
@@ -59,6 +65,14 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
        this.clientSender = clientSender;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reutns the BoardManager
 | 
			
		||||
     * @return the boardManager
 | 
			
		||||
     */
 | 
			
		||||
    public BoardManager getBoardManager() {
 | 
			
		||||
        return boardManager;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the current state of the game logic.
 | 
			
		||||
     *
 | 
			
		||||
@@ -80,6 +94,10 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
        state.entry();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<Player> getPlayers() {
 | 
			
		||||
        return players;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the player's game board.
 | 
			
		||||
     *
 | 
			
		||||
@@ -121,11 +139,12 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     *
 | 
			
		||||
     * @param msg the message to be sent
 | 
			
		||||
     */
 | 
			
		||||
    void send(ClientMessage msg) {
 | 
			
		||||
    public 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);
 | 
			
		||||
            System.out.println("Message gesendet");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -207,7 +226,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(EventDrawCard msg) {
 | 
			
		||||
        setInfoText("Event card drawn: " + msg.getCardDescription());
 | 
			
		||||
        //event card logic
 | 
			
		||||
        // Kartenlogik
 | 
			
		||||
        playSound(Sound.EVENT_CARD);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -236,6 +255,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void received(GameStart msg) {
 | 
			
		||||
        players = msg.getPlayers();
 | 
			
		||||
        setInfoText("The game has started! Good luck!");
 | 
			
		||||
        setState(new WaitForTurnState(this));
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,11 +10,12 @@ package pp.monopoly.game.server;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.message.server.DiceResult;
 | 
			
		||||
import pp.monopoly.model.FieldVisitor;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.model.IntPoint;
 | 
			
		||||
import pp.monopoly.model.card.DeckHelper;
 | 
			
		||||
import pp.monopoly.model.card.Card;
 | 
			
		||||
import pp.monopoly.model.fields.BuildingProperty;
 | 
			
		||||
import pp.monopoly.model.fields.EventField;
 | 
			
		||||
import pp.monopoly.model.fields.FineField;
 | 
			
		||||
@@ -29,6 +30,7 @@ import pp.monopoly.model.fields.WacheField;
 | 
			
		||||
/**
 | 
			
		||||
 * Class representing a player
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    private final int id;
 | 
			
		||||
    private String name;
 | 
			
		||||
@@ -41,6 +43,14 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    private final PlayerHandler handler;
 | 
			
		||||
    private PlayerState state = new LobbyState();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private Player(){
 | 
			
		||||
        id = 0;
 | 
			
		||||
        handler = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a player with the speciefied params
 | 
			
		||||
     * @param id the id of the player
 | 
			
		||||
@@ -85,10 +95,18 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
     * Set the name of the Player
 | 
			
		||||
     * @param name the new name
 | 
			
		||||
     */
 | 
			
		||||
    void setName(String name) {
 | 
			
		||||
    public void setName(String name) {
 | 
			
		||||
        this.name = name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retuns the Playerhandler
 | 
			
		||||
     * @return the Playerhandler
 | 
			
		||||
     */
 | 
			
		||||
    public PlayerHandler getHandler() {
 | 
			
		||||
        return handler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns this players id
 | 
			
		||||
     * @return th eid of this player
 | 
			
		||||
@@ -104,6 +122,21 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    public int getFieldID() {
 | 
			
		||||
        return fieldID;
 | 
			
		||||
    }
 | 
			
		||||
    void setActive() {
 | 
			
		||||
        state = new ActiveState();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean finishTurn() {
 | 
			
		||||
        if(canFinishTurn()) {
 | 
			
		||||
            state = new WaitForTurnState();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean canFinishTurn() {
 | 
			
		||||
        return accountBalance >= 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Moves by the specified amount of steps
 | 
			
		||||
@@ -146,6 +179,7 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
    public void buyProperty(PropertyField property) {
 | 
			
		||||
        if (property.getOwner() == null && accountBalance >= property.getPrice()) {
 | 
			
		||||
            properties.add(property);
 | 
			
		||||
            property.setOwner(this);
 | 
			
		||||
            pay(property.getPrice());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -284,7 +318,8 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(EventField field) {
 | 
			
		||||
        DeckHelper.drawCard();
 | 
			
		||||
        Card c = getHandler().getLogic().getDeckHelper().drawCard();
 | 
			
		||||
        getHandler().getLogic().getDeckHelper().visit(c, this);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -327,6 +362,26 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        return count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getNumHouses() {
 | 
			
		||||
        int total = 0;
 | 
			
		||||
        for (PropertyField field : properties) {
 | 
			
		||||
            if (field.getClass() == BuildingProperty.class) {
 | 
			
		||||
                total += ((BuildingProperty) field).getHouses();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getNumHotels() {
 | 
			
		||||
        int total = 0;
 | 
			
		||||
        for (PropertyField field : properties) {
 | 
			
		||||
            if (field.getClass() == BuildingProperty.class) {
 | 
			
		||||
                total += ((BuildingProperty) field).getHotel();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
     * Inner class for dice functionality in the game.
 | 
			
		||||
     * Rolls random dice values.
 | 
			
		||||
@@ -460,47 +515,19 @@ public class Player implements FieldVisitor<Void>{
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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'");
 | 
			
		||||
            throw new UnsupportedOperationException("not allowed");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @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'");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,15 +8,24 @@ import java.util.List;
 | 
			
		||||
import java.util.NoSuchElementException;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.LimitedLinkedList;
 | 
			
		||||
/**
 | 
			
		||||
 * A class for helping with player actions and managing thier turns
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class PlayerHandler {
 | 
			
		||||
    private List<Player> players = new LimitedLinkedList<>(6);
 | 
			
		||||
    private Set<Player> readyPlayers = new HashSet<>();
 | 
			
		||||
    private ServerGameLogic logic;
 | 
			
		||||
    private Player hostPlayer;
 | 
			
		||||
    private Player extra = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private PlayerHandler() {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Contructs a PlayerHandler
 | 
			
		||||
@@ -131,8 +140,13 @@ public class PlayerHandler {
 | 
			
		||||
     * Completes a player turn and return the next player
 | 
			
		||||
     * @return the next players who is active
 | 
			
		||||
     */
 | 
			
		||||
    Player nextPlayer() {
 | 
			
		||||
    public Player nextPlayer() {
 | 
			
		||||
        Player tmp = players.get(0);
 | 
			
		||||
        if (extra != null) {
 | 
			
		||||
            tmp = extra;
 | 
			
		||||
            extra = null;
 | 
			
		||||
            return tmp;
 | 
			
		||||
        }
 | 
			
		||||
        players.remove(0);
 | 
			
		||||
        players.add(tmp);
 | 
			
		||||
        return players.get(0);
 | 
			
		||||
@@ -142,7 +156,7 @@ public class PlayerHandler {
 | 
			
		||||
     * Returns the {@link ServerGameLogic} of this PlayerHandler
 | 
			
		||||
     * @return the {@link ServerGameLogic} of this PlayerHandler
 | 
			
		||||
     */
 | 
			
		||||
    ServerGameLogic getLogic() {
 | 
			
		||||
    public ServerGameLogic getLogic() {
 | 
			
		||||
        return logic;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -151,7 +165,7 @@ public class PlayerHandler {
 | 
			
		||||
     * @param id the id to be searched for
 | 
			
		||||
     * @return the player with the required id
 | 
			
		||||
     */
 | 
			
		||||
    Player getPlayerById(int id) {
 | 
			
		||||
    public Player getPlayerById(int id) {
 | 
			
		||||
        for (Player player : players) {
 | 
			
		||||
            if (player.getId() == id) return player;
 | 
			
		||||
        }
 | 
			
		||||
@@ -159,15 +173,24 @@ public class PlayerHandler {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Arranges the players turns in a random order
 | 
			
		||||
     * Arranges the players turns in a random order.
 | 
			
		||||
     * Shuffles the players and sets their state to WaitForNextTurn, the first one will be active
 | 
			
		||||
     */
 | 
			
		||||
    void randomOrder() {
 | 
			
		||||
        Collections.shuffle(players);
 | 
			
		||||
        for (Player player : players) {
 | 
			
		||||
            player.finishTurn();
 | 
			
		||||
        }
 | 
			
		||||
        players.get(0).setActive();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setStartBalance(int amount) {
 | 
			
		||||
    public void setStartBalance(int amount) {
 | 
			
		||||
        for (Player player : players) {
 | 
			
		||||
            player.setAccountBalance(amount);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void extraTurn(Player player) {
 | 
			
		||||
        if (players.contains(player)) extra = player;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ import pp.monopoly.message.server.ViewAssetsResponse;
 | 
			
		||||
import pp.monopoly.model.Board;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.model.Rotation;
 | 
			
		||||
import pp.monopoly.model.card.DeckHelper;
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
 | 
			
		||||
@@ -38,6 +39,7 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    private ServerState state = ServerState.LOBBY;
 | 
			
		||||
    private static final int MAX_PLAYERS = 6;
 | 
			
		||||
    private BoardManager boardManager = new BoardManager();
 | 
			
		||||
    private final DeckHelper deckHelper = new DeckHelper();
 | 
			
		||||
    private int startMoney;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -169,9 +171,12 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    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());
 | 
			
		||||
            Player next = playerHandler.nextPlayer();
 | 
			
		||||
            send(next, new NextPlayerTurn(next));
 | 
			
		||||
            if (player.finishTurn()) {
 | 
			
		||||
                LOGGER.log(Level.DEBUG, "Ending turn for player {0}", player.getName());
 | 
			
		||||
                Player next = playerHandler.nextPlayer();
 | 
			
		||||
                next.setActive();
 | 
			
		||||
                send(next, new NextPlayerTurn(next));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -283,4 +288,8 @@ public class ServerGameLogic implements ClientInterpreter {
 | 
			
		||||
    public Player getPlayerById(int id) {
 | 
			
		||||
        return playerHandler.getPlayerById(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public DeckHelper getDeckHelper() {
 | 
			
		||||
        return deckHelper;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,19 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a request from a player to buy a property.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class BuyPropertyRequest extends ClientMessage{
 | 
			
		||||
    private int propertyId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private BuyPropertyRequest() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a BuyPropertyRequest with the specified property ID.
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,18 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a message indicating the player wants to end their turn.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class EndTurn extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    public EndTurn() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,21 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a message indicating the player is ready to play.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class PlayerReady extends ClientMessage {
 | 
			
		||||
    private final boolean isReady;
 | 
			
		||||
    private final String name;
 | 
			
		||||
    private final String figure;
 | 
			
		||||
    private final int startMoney;
 | 
			
		||||
    private boolean isReady;
 | 
			
		||||
    private String name;
 | 
			
		||||
    private String figure;
 | 
			
		||||
    private int startMoney;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private PlayerReady() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a PlayerReady message.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,18 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a message requesting to roll the dice.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class RollDice extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private RollDice() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void accept(ClientInterpreter interpreter, int from) {
 | 
			
		||||
        interpreter.received(this, from);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,21 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a trade Request message from one player to another.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class TradeOffer extends ClientMessage{
 | 
			
		||||
    private int receiverId;
 | 
			
		||||
    private TradeHandler tradehandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private TradeOffer() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeOffer with the specified details.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,22 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a response to a trade offer.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class TradeResponse extends ClientMessage{
 | 
			
		||||
    private int initiatorId;
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private TradeResponse() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeResponse with the specified response details.
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,21 @@
 | 
			
		||||
package pp.monopoly.message.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a request from a player to view their assets.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class ViewAssetsRequest extends ClientMessage{
 | 
			
		||||
 | 
			
		||||
    private final Player player;
 | 
			
		||||
    private Player player;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private ViewAssetsRequest() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public ViewAssetsRequest(Player player) {
 | 
			
		||||
        this.player = player;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,20 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the server's response to a player's request to buy a property.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class BuyPropertyResponse extends ServerMessage{
 | 
			
		||||
    private final boolean successful;
 | 
			
		||||
    private final String propertyName;
 | 
			
		||||
    private final String reason; // Reason for failure, if any
 | 
			
		||||
    private boolean successful;
 | 
			
		||||
    private String propertyName;
 | 
			
		||||
    private String reason; // Reason for failure, if any
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private BuyPropertyResponse() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public BuyPropertyResponse(boolean successful, String propertyName, String reason) {
 | 
			
		||||
        this.successful = successful;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,18 @@ package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class DiceResult extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private List<Integer> rollResult;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private DiceResult() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public DiceResult(List<Integer> rollResult) {
 | 
			
		||||
        this.rollResult = rollResult;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,15 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class EventDrawCard extends ServerMessage{
 | 
			
		||||
    private final String cardDescription;
 | 
			
		||||
    private String cardDescription;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private EventDrawCard() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public EventDrawCard(String cardDescription) {
 | 
			
		||||
        this.cardDescription = cardDescription;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,15 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class GameOver extends ServerMessage{
 | 
			
		||||
    private final boolean isWinner;
 | 
			
		||||
    private boolean isWinner;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private GameOver() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public GameOver(boolean isWinner) {
 | 
			
		||||
        this.isWinner = isWinner;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,19 @@ package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class GameStart extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final List<Player> players;
 | 
			
		||||
    private List<Player> players;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private GameStart() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public GameStart(List<Player> players) {
 | 
			
		||||
        this.players = players;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,16 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class JailEvent extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final boolean goingToJail;
 | 
			
		||||
    private boolean goingToJail;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private JailEvent() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public JailEvent(boolean goingToJail) {
 | 
			
		||||
        this.goingToJail = goingToJail;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,18 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class NextPlayerTurn extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final Player player;
 | 
			
		||||
    private Player player;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private NextPlayerTurn() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public NextPlayerTurn(Player player) {
 | 
			
		||||
        this.player = player;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,20 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.PlayerColor;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class PlayerStatusUpdate extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final String playerName;
 | 
			
		||||
    private final String status;
 | 
			
		||||
    private final PlayerColor color;
 | 
			
		||||
    private String playerName;
 | 
			
		||||
    private String status;
 | 
			
		||||
    private PlayerColor color;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private PlayerStatusUpdate() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public PlayerStatusUpdate(String playerName, String status, PlayerColor color) {
 | 
			
		||||
        this.playerName = playerName;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,16 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class TimeOutWarning extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final int remainingTime;
 | 
			
		||||
    private int remainingTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private TimeOutWarning() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    public TimeOutWarning(int remainingTime) {
 | 
			
		||||
        this.remainingTime = remainingTime;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,22 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a response to a trade offer.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class TradeReply extends ServerMessage{
 | 
			
		||||
    private int initiatorId;
 | 
			
		||||
    private TradeHandler tradeHandler;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private TradeReply() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeResponse with the specified response details.
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,23 @@
 | 
			
		||||
package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.TradeHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a trade Request message from one player to another.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class TradeRequest extends ServerMessage{
 | 
			
		||||
    private int receiverId;
 | 
			
		||||
    private TradeHandler tradehandler;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private TradeRequest() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a TradeRequest with the specified details.
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -2,18 +2,26 @@ package pp.monopoly.message.server;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.fields.BoardManager;
 | 
			
		||||
import pp.monopoly.model.fields.PropertyField;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a response containing the player's assets.
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class ViewAssetsResponse extends ServerMessage{
 | 
			
		||||
 | 
			
		||||
    private final List<PropertyField> properties;
 | 
			
		||||
    private final BoardManager board;
 | 
			
		||||
    private final int accountBalance;
 | 
			
		||||
    private final int jailCards;
 | 
			
		||||
    private List<PropertyField> properties;
 | 
			
		||||
    private BoardManager board;
 | 
			
		||||
    private int accountBalance;
 | 
			
		||||
    private int jailCards;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private ViewAssetsResponse() { /* empty */ }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a ViewAssetsResponse with the specified properties and account balance.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.card.Card;
 | 
			
		||||
 | 
			
		||||
public interface CardVisitor<T> {
 | 
			
		||||
    T visit(Card c);
 | 
			
		||||
}
 | 
			
		||||
@@ -4,9 +4,12 @@ import java.util.Collections;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
import static java.lang.Math.max;
 | 
			
		||||
import static java.lang.Math.min;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
public class Figure implements Item{
 | 
			
		||||
    private final String type;
 | 
			
		||||
    private final int length; // The length of the Figure
 | 
			
		||||
 
 | 
			
		||||
@@ -2,14 +2,22 @@ package pp.monopoly.model;
 | 
			
		||||
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
 | 
			
		||||
import com.jme3.network.serializing.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A LinkedList with a maximum size limit.
 | 
			
		||||
 *
 | 
			
		||||
 * @param <E> the type of elements held in this collection
 | 
			
		||||
 */
 | 
			
		||||
@Serializable
 | 
			
		||||
public class LimitedLinkedList<E> extends LinkedList<E> {
 | 
			
		||||
 | 
			
		||||
    private final int maxSize;
 | 
			
		||||
    private int maxSize;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default constructor for serialization purposes.
 | 
			
		||||
     */
 | 
			
		||||
    private LimitedLinkedList() {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a LimitedLinkedList with the specified maximum size.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package pp.monopoly.model.card;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
 | 
			
		||||
public class Card {
 | 
			
		||||
    private final String description;
 | 
			
		||||
    private final String keyword;
 | 
			
		||||
@@ -9,13 +11,13 @@ public class Card {
 | 
			
		||||
        this.keyword = keyword;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void accept(DeckHelper visitor) {
 | 
			
		||||
        visitor.visit(this);
 | 
			
		||||
    public void accept(DeckHelper visitor, Player player) {
 | 
			
		||||
        visitor.visit(this, player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    String getDescription() {
 | 
			
		||||
    public String getDescription() {
 | 
			
		||||
        return description;
 | 
			
		||||
    }
 | 
			
		||||
    } // TODO wird gerade in der EventCard zur erstellung des Popup genutzt
 | 
			
		||||
 | 
			
		||||
    String getKeyword() {
 | 
			
		||||
        return keyword;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,24 +2,317 @@ package pp.monopoly.model.card;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Queue;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.model.CardVisitor;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.message.client.EndTurn;
 | 
			
		||||
 | 
			
		||||
public class DeckHelper implements CardVisitor<Void>{
 | 
			
		||||
public class DeckHelper{
 | 
			
		||||
 | 
			
		||||
    private static Queue<Card> cards;
 | 
			
		||||
    private Queue<Card> cards;
 | 
			
		||||
    private List<Card> drawn = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    private DeckHelper() {
 | 
			
		||||
    public DeckHelper() {
 | 
			
		||||
        cards = new LinkedList<Card>();
 | 
			
		||||
        cards.add(new Card("Du wurdest mit einem Dienst KFZ geblitzt. Zahle: 800€", "dienst-kfz-blitzer"));
 | 
			
		||||
        cards.add(new Card("Die erste Spoparty steht bevor. Ziehe vor zum 23er.", "spoparty"));
 | 
			
		||||
        cards.add(new Card("Du kommst aus dem Gulak frei.", "gulak-frei-1"));
 | 
			
		||||
        cards.add(new Card("Du kommst aus dem Gulak frei.", "gulak-frei-2"));
 | 
			
		||||
        cards.add(new Card("Du hast den Dienstführerschein bestanden. Ziehe vor bis Teststrecke.", "dienstfuehrerschein"));
 | 
			
		||||
        cards.add(new Card("Malkmus läd zum Pubquiz ein. Rücke vor bis zum 20er.", "pubquiz"));
 | 
			
		||||
        cards.add(new Card("Du warst ohne Namensschild in der Truppenküche. Rücke vor zum 10er. Gehe nicht über Monatsgehalt. Ziehe keine 2000x€ ein.", "namensschild-truppenkueche"));
 | 
			
		||||
        cards.add(new Card("Du hast heute die Spendierhosen an und gibst eine Runde in der Unibar. Zahle jedem Spieler: 400€", "spendierhosen-unibar"));
 | 
			
		||||
        cards.add(new Card("Du warst in der Prüfungsphase krank. Gehe 3 Felder zurück.", "pruefungsphase-krank"));
 | 
			
		||||
        cards.add(new Card("Ziehe vor bis zum nächsten Monatsgehalt.", "naechstes-monatsgehalt"));
 | 
			
		||||
        cards.add(new Card("Du hast ein Antreten verschlafen. Zahle: 500€", "antreten-verschlafen-1"));
 | 
			
		||||
        cards.add(new Card("Du hast den Maibock organisiert. Du erhältst: 3000€", "maibock-organisiert"));
 | 
			
		||||
        cards.add(new Card("Der Spieß macht eine unangekündigte Inventur. Zahle für jedes Haus: 400€ und jedes Hotel: 2800€", "inventur-haeuser-hotels"));
 | 
			
		||||
        cards.add(new Card("Es gab keine Mozzarella Bällchen mehr für Thoma. Alle Spieler ziehen vor auf Gym.", "dienstsport-gym"));
 | 
			
		||||
        cards.add(new Card("Auf deiner Stube wurde Schimmel gefunden. Gehe ins Gulak. Begib Dich direkt dorthin. Gehe nicht über Monatsgehalt. Ziehe nicht ein.", "schimmel-gulak"));
 | 
			
		||||
        cards.add(new Card("Deine Stube ist nach einer Partynacht nicht mehr bewohnbar. Du ziehst ins Gulak. Begib Dich direkt dorthin. Gehe nicht über Monatsgehalt. Ziehe nicht ein.", "partynacht-gulak"));
 | 
			
		||||
        cards.add(new Card("Das Jahresabschlussantreten steht an. Ziehe vor bis Schwimmhalle.", "jahresabschlussantreten"));
 | 
			
		||||
        cards.add(new Card("Du wurdest beim Verkaufen von Versicherungen erwischt. Zahle: 4000€", "verkaufen-versicherungen"));
 | 
			
		||||
        cards.add(new Card("Du musstest einen Rückstuferantrag stellen. Setze eine Runde aus.", "rueckstuferantrag"));
 | 
			
		||||
        cards.add(new Card("Auf einer Hausfeier bist du betrunken auf der Treppe gestürzt und dabei auf einen Kameraden gefallen. Zahle: 800€ und gehe zurück zu SanZ.", "hausfeier-sturz"));
 | 
			
		||||
        cards.add(new Card("Beförderung. Beim nächsten Monatsgehalt ziehst du ein: 3000€", "befoerderung"));
 | 
			
		||||
        cards.add(new Card("Du entscheidest dich für eine Dienstreise nach Lourd. Zahle: 1000€ und setze eine Runde aus.", "dienstreise-lourd"));
 | 
			
		||||
        cards.add(new Card("Du warst fleißig Blutspenden und erhältst einen Tag Sonderurlaub. Du bist nochmal an der Reihe.", "blutspenden-sonderurlaub"));
 | 
			
		||||
        cards.add(new Card("Dir wurde auf dem Oktoberfest dein Geldbeutel geklaut. Gebe 10% deines Vermögens ab.", "geldbeutel-oktoberfest"));
 | 
			
		||||
        cards.add(new Card("Du wirst von deinem Chef für vorbildliches Verhalten gelobt. Du erhältst: 4000€", "lob-chef"));
 | 
			
		||||
        cards.add(new Card("Deine Bekanntschaft von letzter Nacht war eine Spo. Lasse dich testen und zahle: 200€", "spo-testen"));
 | 
			
		||||
        cards.add(new Card("Du wurdest von Kranz geexmattet. Gehe zurück zu Prüfungsamt.", "kranz-exmatrikulation"));
 | 
			
		||||
        cards.add(new Card("Die letzte Party ist ein wenig eskaliert. Setze eine Runde aus.", "party-eskaliert"));
 | 
			
		||||
        cards.add(new Card("Du wurdest zur VP gewählt und schmeißt eine Einstandsparty. Zahle: 800€", "vp-einstandsparty"));
 | 
			
		||||
        cards.add(new Card("Du hast eine Party veranstaltet und dick Gewinn gemacht. Ziehe ein: 1500€", "party-gewinn"));
 | 
			
		||||
        cards.add(new Card("Zur falschen Zeit am falschen Ort. Du musst einen Bergmarsch planen und setzt eine Runde aus.", "bergmarsch"));
 | 
			
		||||
        cards.add(new Card("Dein Jodel eines Eispenis mit Unterhodenbeleuchtung geht viral. Ziehe ein: 1000€", "jodel-eispenis"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void visit(Card card, Player player) {
 | 
			
		||||
        switch (card.getKeyword()) {
 | 
			
		||||
            case "dienst-kfz-blitzer":
 | 
			
		||||
                dienstKfzBlitzer(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "spoparty":
 | 
			
		||||
                spoparty(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "gulak-frei-1":
 | 
			
		||||
            case "gulak-frei-2":
 | 
			
		||||
                gulakFrei(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "dienstfuehrerschein":
 | 
			
		||||
                dienstfuehrerschein(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "pubquiz":
 | 
			
		||||
                pubquiz(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "namensschild-truppenkueche":
 | 
			
		||||
                namensschildTruppenkueche(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "spendierhosen-unibar":
 | 
			
		||||
                spendierhosenUnibar(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "pruefungsphase-krank":
 | 
			
		||||
                pruefungsphaseKrank(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "naechstes-monatsgehalt":
 | 
			
		||||
                naechstesMonatsgehalt(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "antreten-verschlafen-1":
 | 
			
		||||
                antretenVerschlafen(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "maibock-organisiert":
 | 
			
		||||
                maibockOrganisiert(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "inventur-haeuser-hotels":
 | 
			
		||||
                inventurHaeuserHotels(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "dienstsport-gym":
 | 
			
		||||
                dienstsportGym(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "schimmel-gulak":
 | 
			
		||||
                schimmelGulak(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "partynacht-gulak":
 | 
			
		||||
                partynachtGulak(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "jahresabschlussantreten":
 | 
			
		||||
                jahresabschlussantreten(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "verkaufen-versicherungen":
 | 
			
		||||
                verkaufenVersicherungen(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "rueckstuferantrag":
 | 
			
		||||
                rueckstuferantrag(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "hausfeier-sturz":
 | 
			
		||||
                hausfeierSturz(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "befoerderung":
 | 
			
		||||
                befoerderung(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "dienstreise-lourd":
 | 
			
		||||
                dienstreiseLourd(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "blutspenden-sonderurlaub":
 | 
			
		||||
                blutspendenSonderurlaub(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "geldbeutel-oktoberfest":
 | 
			
		||||
                geldbeutelOktoberfest(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "lob-chef":
 | 
			
		||||
                lobChef(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "spo-testen":
 | 
			
		||||
                spoTesten(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "kranz-exmatrikulation":
 | 
			
		||||
                kranzExmatrikulation(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "party-eskaliert":
 | 
			
		||||
                partyEskaliert(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "vp-einstandsparty":
 | 
			
		||||
                vpEinstandsparty(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "party-gewinn":
 | 
			
		||||
                partyGewinn(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "bergmarsch":
 | 
			
		||||
                bergmarsch(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            case "jodel-eispenis":
 | 
			
		||||
                jodelEispenis(player);
 | 
			
		||||
                break;
 | 
			
		||||
        
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Void visit(Card c) {
 | 
			
		||||
        // TODO Auto-generated method stub
 | 
			
		||||
        throw new UnsupportedOperationException("Unimplemented method 'visit'");
 | 
			
		||||
    }
 | 
			
		||||
        private void dienstKfzBlitzer(Player player) {
 | 
			
		||||
            player.pay(800);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void spoparty(Player player) {
 | 
			
		||||
            player.movePos(14);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void gulakFrei(Player player) {
 | 
			
		||||
            player.addJailCard();
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void dienstfuehrerschein(Player player) {
 | 
			
		||||
            player.movePos(20);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void pubquiz(Player player) {
 | 
			
		||||
            player.movePos(39);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void namensschildTruppenkueche(Player player) {
 | 
			
		||||
            //TODO
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void spendierhosenUnibar(Player player) {
 | 
			
		||||
            for (Player p : player.getHandler().getPlayers()) {
 | 
			
		||||
                p.earnMoney(400);
 | 
			
		||||
            }
 | 
			
		||||
            player.pay(player.getHandler().getPlayerCount()*400 - 400);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void pruefungsphaseKrank(Player player) {
 | 
			
		||||
            player.movePos(player.getFieldID() - 3);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void naechstesMonatsgehalt(Player player) {
 | 
			
		||||
            player.movePos(0);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void antretenVerschlafen(Player player) {
 | 
			
		||||
            player.pay(500);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void maibockOrganisiert(Player player) {
 | 
			
		||||
            player.earnMoney(3000);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void inventurHaeuserHotels(Player player) {
 | 
			
		||||
            player.pay(player.getNumHouses() * 400 + player.getNumHotels() * 2800);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void dienstsportGym(Player player) {
 | 
			
		||||
            for (Player p : player.getHandler().getPlayers()) {
 | 
			
		||||
                p.movePos(1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void schimmelGulak(Player player) {
 | 
			
		||||
            player.movePos(10);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void partynachtGulak(Player player) {
 | 
			
		||||
            player.movePos(10);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void jahresabschlussantreten(Player player) {
 | 
			
		||||
            player.movePos(17); 
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void verkaufenVersicherungen(Player player) {
 | 
			
		||||
            player.pay(4000);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void rueckstuferantrag(Player player) {
 | 
			
		||||
            player.getHandler().getLogic().received(new EndTurn(), player.getId());
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void hausfeierSturz(Player player) {
 | 
			
		||||
            player.pay(800);
 | 
			
		||||
            player.movePos(32);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void befoerderung(Player player) {
 | 
			
		||||
            player.earnMoney(3000);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void dienstreiseLourd(Player player) {
 | 
			
		||||
            player.pay(1000);
 | 
			
		||||
            player.getHandler().getLogic().received(new EndTurn(), player.getId());
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void blutspendenSonderurlaub(Player player) {
 | 
			
		||||
            player.getHandler().extraTurn(player);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void geldbeutelOktoberfest(Player player) {
 | 
			
		||||
            player.pay(player.getAccountBalance() / 10);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void lobChef(Player player) {
 | 
			
		||||
            player.earnMoney( 4000);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void spoTesten(Player player) {
 | 
			
		||||
            player.pay( 200);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void kranzExmatrikulation(Player player) {
 | 
			
		||||
            player.movePos(5);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void partyEskaliert(Player player) {
 | 
			
		||||
            player.getHandler().getLogic().received(new EndTurn(), player.getId());
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void vpEinstandsparty(Player player) {
 | 
			
		||||
            player.pay( 800);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void partyGewinn(Player player) {
 | 
			
		||||
            player.earnMoney( 1500);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void bergmarsch(Player player) {
 | 
			
		||||
            player.getHandler().getLogic().received(new EndTurn(), player.getId());
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        private void jodelEispenis(Player player) {
 | 
			
		||||
            player.earnMoney(1000);
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    private void shuffle() {
 | 
			
		||||
        List<Card> cardList = new ArrayList<>(cards);
 | 
			
		||||
@@ -28,7 +321,13 @@ public class DeckHelper implements CardVisitor<Void>{
 | 
			
		||||
        cards.addAll(cardList);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Card drawCard() {
 | 
			
		||||
        return cards != null ? cards.poll() : null;
 | 
			
		||||
    public Card drawCard() {
 | 
			
		||||
        if (cards.isEmpty()) {
 | 
			
		||||
            drawn.forEach(cards::add);
 | 
			
		||||
            shuffle();
 | 
			
		||||
        }
 | 
			
		||||
        Card card = cards.poll();
 | 
			
		||||
        drawn.add(card);
 | 
			
		||||
        return card;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -98,4 +98,12 @@ public class BuildingProperty extends PropertyField {
 | 
			
		||||
    public int getHousePrice() {
 | 
			
		||||
        return housePrice;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getHouses() {
 | 
			
		||||
        return houses;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getHotel() {
 | 
			
		||||
        return hotel ? 1:0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,6 @@ package pp.monopoly.model.fields;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.model.card.Card;
 | 
			
		||||
import pp.monopoly.model.card.DeckHelper;
 | 
			
		||||
 | 
			
		||||
public class EventField extends Field{
 | 
			
		||||
 | 
			
		||||
@@ -15,9 +13,4 @@ public class EventField extends Field{
 | 
			
		||||
    public void accept(Player player) {
 | 
			
		||||
        player.visit(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Card drawCard() {
 | 
			
		||||
        return DeckHelper.drawCard();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,11 +26,23 @@ import com.jme3.network.serializing.Serializer;
 | 
			
		||||
 | 
			
		||||
import pp.monopoly.MonopolyConfig;
 | 
			
		||||
import pp.monopoly.game.server.Player;
 | 
			
		||||
import pp.monopoly.game.server.PlayerHandler;
 | 
			
		||||
import pp.monopoly.game.server.ServerGameLogic;
 | 
			
		||||
import pp.monopoly.game.server.ServerSender;
 | 
			
		||||
import pp.monopoly.message.client.BuyPropertyRequest;
 | 
			
		||||
import pp.monopoly.message.client.ClientMessage;
 | 
			
		||||
import pp.monopoly.message.client.EndTurn;
 | 
			
		||||
import pp.monopoly.message.client.PlayerReady;
 | 
			
		||||
import pp.monopoly.message.client.RollDice;
 | 
			
		||||
import pp.monopoly.message.client.TradeOffer;
 | 
			
		||||
import pp.monopoly.message.client.TradeResponse;
 | 
			
		||||
import pp.monopoly.message.client.ViewAssetsRequest;
 | 
			
		||||
import pp.monopoly.message.server.GameStart;
 | 
			
		||||
import pp.monopoly.message.server.NextPlayerTurn;
 | 
			
		||||
import pp.monopoly.message.server.ServerMessage;
 | 
			
		||||
import pp.monopoly.model.Figure;
 | 
			
		||||
import pp.monopoly.model.IntPoint;
 | 
			
		||||
import pp.monopoly.model.LimitedLinkedList;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Server implementing the visitor pattern as MessageReceiver for ClientMessages
 | 
			
		||||
@@ -105,14 +117,35 @@ public class MonopolyServer implements MessageListener<HostedConnection>, Connec
 | 
			
		||||
 | 
			
		||||
    private void initializeSerializables() {
 | 
			
		||||
        Serializer.registerClass(IntPoint.class);
 | 
			
		||||
        Serializer.registerClass(BuyPropertyRequest.class);
 | 
			
		||||
        Serializer.registerClass(EndTurn.class);
 | 
			
		||||
        Serializer.registerClass(PlayerReady.class);
 | 
			
		||||
        Serializer.registerClass(RollDice.class);
 | 
			
		||||
        Serializer.registerClass(TradeOffer.class);
 | 
			
		||||
        Serializer.registerClass(TradeResponse.class);
 | 
			
		||||
        Serializer.registerClass(ViewAssetsRequest.class);
 | 
			
		||||
        Serializer.registerClass(GameStart.class);
 | 
			
		||||
        Serializer.registerClass(LimitedLinkedList.class);
 | 
			
		||||
        Serializer.registerClass(NextPlayerTurn.class);
 | 
			
		||||
        Serializer.registerClass(Player.class);
 | 
			
		||||
        Serializer.registerClass(Figure.class);
 | 
			
		||||
        Serializer.registerClass(PlayerHandler.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void registerListeners() {
 | 
			
		||||
        myServer.addMessageListener(this, BuyPropertyRequest.class);
 | 
			
		||||
        myServer.addMessageListener(this, EndTurn.class);
 | 
			
		||||
        myServer.addMessageListener(this, PlayerReady.class);
 | 
			
		||||
        myServer.addMessageListener(this, RollDice.class);
 | 
			
		||||
        myServer.addMessageListener(this, TradeOffer.class);
 | 
			
		||||
        myServer.addMessageListener(this, TradeResponse.class);
 | 
			
		||||
        myServer.addMessageListener(this, ViewAssetsRequest.class);
 | 
			
		||||
        myServer.addConnectionListener(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void messageReceived(HostedConnection source, Message message) {
 | 
			
		||||
        System.out.println("Message recieved");
 | 
			
		||||
        LOGGER.log(Level.INFO, "message received from {0}: {1}", source.getId(), message); //NON-NLS
 | 
			
		||||
        if (message instanceof ClientMessage clientMessage)
 | 
			
		||||
            pendingMessages.add(new ReceivedMessage(clientMessage, source.getId()));
 | 
			
		||||
 
 | 
			
		||||