diff --git a/.gitignore b/.gitignore index a3152bd..e252cad 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ build # VSC bin +.vscode # IntelliJ *.iml diff --git a/Battle.j3o b/Battle.j3o deleted file mode 100644 index 9e1ef4d..0000000 Binary files a/Battle.j3o and /dev/null differ diff --git a/BoatSmall.j3o b/BoatSmall.j3o deleted file mode 100644 index c13785d..0000000 Binary files a/BoatSmall.j3o and /dev/null differ diff --git a/CV.j3o b/CV.j3o deleted file mode 100644 index c49ddb2..0000000 Binary files a/CV.j3o and /dev/null differ diff --git a/KingGeorgeV.j3o b/KingGeorgeV.j3o deleted file mode 100644 index b030d91..0000000 Binary files a/KingGeorgeV.j3o and /dev/null differ diff --git a/Projekte/battleship/client/src/main/java/pp/battleship/client/NetworkDialog.java b/Projekte/battleship/client/src/main/java/pp/battleship/client/NetworkDialog.java index 2e043c1..d9dde65 100644 --- a/Projekte/battleship/client/src/main/java/pp/battleship/client/NetworkDialog.java +++ b/Projekte/battleship/client/src/main/java/pp/battleship/client/NetworkDialog.java @@ -7,24 +7,23 @@ package pp.battleship.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 com.simsilica.lemur.component.SpringGridLayout; +import static pp.battleship.Resources.lookup; import pp.battleship.server.BattleshipServer; import pp.dialog.Dialog; import pp.dialog.DialogBuilder; import pp.dialog.SimpleDialog; -import java.lang.System.Logger; -import java.lang.System.Logger.Level; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import static pp.battleship.Resources.lookup; - /** * 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. @@ -32,7 +31,7 @@ import static pp.battleship.Resources.lookup; class NetworkDialog extends SimpleDialog { private static final Logger LOGGER = System.getLogger(NetworkDialog.class.getName()); private static final String LOCALHOST = "localhost"; //NON-NLS - private static final String DEFAULT_PORT = "1234"; //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); diff --git a/Projekte/battleship/model/src/main/java/pp/battleship/BattleshipConfig.java b/Projekte/battleship/model/src/main/java/pp/battleship/BattleshipConfig.java index f6b4cf2..af4c63d 100644 --- a/Projekte/battleship/model/src/main/java/pp/battleship/BattleshipConfig.java +++ b/Projekte/battleship/model/src/main/java/pp/battleship/BattleshipConfig.java @@ -7,12 +7,11 @@ package pp.battleship; -import pp.util.config.Config; - +import static java.lang.Math.max; import java.util.Map; import java.util.TreeMap; -import static java.lang.Math.max; +import pp.util.config.Config; /** * Provides access to the configuration settings for the Battleship game. @@ -31,7 +30,7 @@ public class BattleshipConfig extends Config { * The default port number for the Battleship server. */ @Property("port") - private int port = 1234; + private int port = 12234; /** * The width of the game map in terms of grid units. diff --git a/Projekte/battleship/server/server.properties b/Projekte/battleship/server/server.properties index 9f168a6..1a03cec 100644 --- a/Projekte/battleship/server/server.properties +++ b/Projekte/battleship/server/server.properties @@ -10,7 +10,7 @@ # This file defines the configuration settings for the Battleship server. # # The port number on which the server will listen for incoming connections. -port=1234 +port=42069 # # The dimensions of the game map. # 'map.width' defines the number of columns, and 'map.height' defines the number of rows. diff --git a/Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy b/Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy index 68a0f6e..7bac65e 100644 --- a/Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy +++ b/Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy @@ -1,6 +1,8 @@ // Styling of Lemur components // For documentation, see: // https://github.com/jMonkeyEngine-Contributions/Lemur/wiki/Styling + +import com.jme3.math.ColorRGBA import com.simsilica.lemur.* import com.simsilica.lemur.component.QuadBackgroundComponent import com.simsilica.lemur.Button @@ -34,9 +36,10 @@ def gradient = TbtQuadBackgroundComponent.create( def doubleGradient = new QuadBackgroundComponent(gradientColor) doubleGradient.texture = texture(name: "/com/simsilica/lemur/icons/double-gradient-128.png", generateMips: false) +//doubleGradient.color = color(0, 0, 0, 1) def orangeBorder = TbtQuadBackgroundComponent.create( - texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png", // Replace with an appropriate texture if needed + texture(name: "/com/simsilica/lemur/icons/border.png", // Replace with an appropriate texture if needed generateMips: false), 1, 1, 1, 126, 126, 1f, false) @@ -51,11 +54,27 @@ selector("label", "pp") { color = buttonEnabledColor } +selector("label-Bold", "pp") { + insets = new Insets3f(2, 2, 2, 2) + font = font("Interface/Fonts/Metropolis/Metropolis-Bold-32.fnt") + fontSize = 30 + color = buttonEnabledColor + textHAlignment = HAlignment.Center + textVAlignment = VAlignment.Center + +} +selector("label-Text", "pp") { + insets = new Insets3f(2, 2, 2, 2) + fontSize = 25 + color = buttonEnabledColor +} + selector("header", "pp") { font = font("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt") insets = new Insets3f(2, 2, 2, 2) color = color(1, 0.5, 0, 1) textHAlignment = HAlignment.Center + textVAlignment = VAlignment.Center } selector("container", "pp") { @@ -64,20 +83,10 @@ selector("container", "pp") { } selector("toolbar") { - // Set the grey background - background = new QuadBackgroundComponent(greyBackground) + background = gradient.clone() + background.setColor(bgColor) + //color = (new ColorRGBA(0.4157f, 0.4235f, 0.4392f, 1.0f)) - // Add a red border using a TbtQuadBackgroundComponent - def redBorder = TbtQuadBackgroundComponent.create( - texture(name: "/com/simsilica/lemur/icons/bordered-gradient.png", - generateMips: false), - 1, 1, 1, 1, 1, - 1f, false) - redBorder.color = redBorderColor - background = greyBackground - - // Optional: Set padding inside the toolbar - insets = new Insets3f(10, 10, 10, 10) } selector("slider", "pp") { background = gradient.clone() @@ -146,6 +155,8 @@ selector("title", "pp") { background.texture = texture(name: "/com/simsilica/lemur/icons/double-gradient-128.png", generateMips: false) insets = new Insets3f(2, 2, 2, 2) + textHAlignment = HAlignment.Center + textVAlignment = VAlignment.Center buttonCommands = stdButtonCommands } @@ -160,6 +171,8 @@ selector("button", "pp") { // Use insets to create a margin/padding effect for the inner background insets = new Insets3f(3, 3, 3, 3) // Adjust the border thickness + textHAlignment = HAlignment.Center + textVAlignment = VAlignment.Center buttonCommands = stdButtonCommands } @@ -234,5 +247,41 @@ selector("tab.button", "pp") { } selector("settings-title", "pp") { fontSize = 48 // Set font size - background = new QuadBackgroundComponent(color(0.4157f, 0.4235f, 0.4392f, 1.0f)) // Grey background - } \ No newline at end of file + textHAlignment = HAlignment.Center + textVAlignment = VAlignment.Center + } + +selector("menu-button", "pp") { + fontSize = 40 // Set font size + textHAlignment = HAlignment.Center + textVAlignment = VAlignment.Center + buttonCommands = stdButtonCommands +} + +// Style for Selector text +selector("selector.item.label") { + color = color(0, 0, 0, 1) // Black text + fontSize = 16 // Optional: Adjust the text size if needed + textHAlignment = HAlignment.Left // Optional: Align text to the left + insets = new Insets3f(2, 2, 2, 2) // Optional: Add padding around text +} +// Style the popup container background +selector("selector.popup") { + background = new QuadBackgroundComponent(new ColorRGBA(1, 1, 1, 0.8f)) // Translucent white background + insets = new Insets3f(5, 5, 5, 5) // Padding inside the popup container +} + +// Style the text of dropdown options +selector("selector.item.label") { + color = color(0, 0, 0, 1) // Black text + fontSize = 16 // Optional: Adjust font size + textHAlignment = HAlignment.Left // Align text to the left + insets = new Insets3f(2, 5, 2, 5) // Add padding for each option +} + +// Style the hover state of dropdown options +selector("selector.item.label", "hover") { + color = color(1, 1, 1, 1) // White text when hovered + background = new QuadBackgroundComponent(new ColorRGBA(0.2f, 0.6f, 1.0f, 0.9f)) // Highlighted background +} + diff --git a/Projekte/monopoly/client/build.gradle b/Projekte/monopoly/client/build.gradle index 66985e3..85ddd4b 100644 --- a/Projekte/monopoly/client/build.gradle +++ b/Projekte/monopoly/client/build.gradle @@ -9,7 +9,12 @@ dependencies { implementation project(":monopoly:model") implementation project(":monopoly:server") + implementation 'com.simsilica:lemur-proto:1.13.0' implementation libs.jme3.desktop + implementation libs.lemur + implementation libs.lemurproto + + implementation libs.selenium runtimeOnly libs.jme3.awt.dialogs runtimeOnly libs.jme3.plugins diff --git a/Projekte/monopoly/client/client.properties b/Projekte/monopoly/client/client.properties index 4403fa3..fd98968 100644 --- a/Projekte/monopoly/client/client.properties +++ b/Projekte/monopoly/client/client.properties @@ -5,47 +5,13 @@ ## (c) Mark Minas (mark.minas@unibw.de) ######################################## # -# Battleship client configuration -# -# Specifies the map used by the opponent in single mode. -# Single mode is activated if this property is set. -#map.opponent=maps/map2.json -# -# Specifies the map used by the player in single mode. -# The player must define their own map if this property is not set. -map.own=maps/map1.json -# -# Coordinates of the shots fired by the RobotClient in the order listed. -# Example: -# 2, 0,\ -# 2, 1,\ -# 2, 2,\ -# 2, 3 -# defines four shots, namely at the coordinates -# (x=2, y=0), (x=2, y=1), (x=2, y=2), and (x=2, y=3) -robot.targets=2, 0,\ - 2, 1,\ - 2, 2,\ - 2, 3 -# -# Delay in milliseconds between each shot fired by the RobotClient. -robot.delay=500 +# Monopoly client configuration # # The dimensions of the game map used in single mode. # 'map.width' defines the number of columns, and 'map.height' defines the number of rows. map.width=10 map.height=10 # -# The number of ships of each length available in single mode. -# The value is a comma-separated list where each element corresponds to the number of ships -# with a specific length. For example: -# ship.nums=4, 3, 2, 1 -# This configuration means: -# - 4 ships of length 1 -# - 3 ships of length 2 -# - 2 ships of length 3 -# - 1 ship of length 4 -ship.nums=4, 3, 2, 1 # # Screen settings # @@ -58,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=1200 +settings.resolution.width=1920 # # Specifies the height of the application window in pixels. -settings.resolution.height=800 +settings.resolution.height=1080 # # Determines whether the application runs in full-screen mode. settings.full-screen=false diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameMusic.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameMusic.java new file mode 100644 index 0000000..791b604 --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameMusic.java @@ -0,0 +1,122 @@ +package pp.monopoly.client; + +import static pp.util.PreferencesUtils.getPreferences; + +import java.lang.System.Logger; +import java.lang.System.Logger.Level; +import java.util.prefs.Preferences; + +import com.jme3.app.Application; +import com.jme3.app.state.AbstractAppState; +import com.jme3.app.state.AppStateManager; +import com.jme3.asset.AssetLoadException; +import com.jme3.asset.AssetNotFoundException; +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioNode; + +/** + * Handles the background music beeing played. Is able to start and stop the music. Set the Volume of the Audio. + */ +public class GameMusic extends AbstractAppState{ + private static final Logger LOGGER = System.getLogger(GameMusic.class.getName()); + private static final Preferences PREFERENCES = getPreferences(GameMusic.class); + private static final String ENABLED_PREF = "enabled"; //NON-NLS + private static final String VOLUME_PREF = "volume"; //NON-NLS + + private AudioNode music; + + /** + * Checks if sound is enabled in the preferences. + * + * @return {@code true} if sound is enabled, {@code false} otherwise. + */ + public static boolean enabledInPreferences() { + return PREFERENCES.getBoolean(ENABLED_PREF, true); + } + + /** + * Checks if sound is enabled in the preferences. + * + * @return float to which the volume is set + */ + public static float volumeInPreferences() { + return PREFERENCES.getFloat(VOLUME_PREF, 0.5f); + } + + /** + * Initializes the sound effects for the game. + * Overrides {@link AbstractAppState#initialize(AppStateManager, Application)} + * + * @param stateManager The state manager + * @param app The application + */ + @Override + public void initialize(AppStateManager stateManager, Application app) { + super.initialize(stateManager, app); + music = loadSound(app, "Sound/background.ogg"); + setVolume(volumeInPreferences()); + music.setLooping(true); + if (isEnabled() && music != null) { + music.play(); + } + } + + /** + * Loads a sound from the specified file. + * + * @param app The application + * @param name The name of the sound file. + * @return The loaded AudioNode. + */ + private AudioNode loadSound(Application app, String name) { + try { + final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer); + sound.setLooping(false); + sound.setPositional(false); + return sound; + } + catch (AssetLoadException | AssetNotFoundException ex) { + LOGGER.log(Level.ERROR, ex.getMessage(), ex); + } + return null; + } + + /** + * Sets the enabled state of this AppState. + * Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)} + * + * @param enabled {@code true} to enable the AppState, {@code false} to disable it. + */ + @Override + public void setEnabled(boolean enabled) { + if (isEnabled() == enabled) return; + + if (music != null) { + if (enabled) { + music.play(); + } else { + music.stop(); + } + } + + super.setEnabled(enabled); + LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS + PREFERENCES.putBoolean(ENABLED_PREF, enabled); + } + + /** + * Toggles the game sound on or off. + */ + public void toggleSound() { + setEnabled(!isEnabled()); + } + + /** + * Sets the volume of music + * @param vol the volume to which the music should be set + */ + public void setVolume(float vol){ + music.setVolume(vol); + PREFERENCES.putFloat(VOLUME_PREF, vol); + } +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java index bf5d649..f2bb02a 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java @@ -31,9 +31,17 @@ public class GameSound extends AbstractAppState implements GameEventListener { private static final Preferences PREFERENCES = getPreferences(GameSound.class); private static final String ENABLED_PREF = "enabled"; //NON-NLS - private AudioNode splashSound; - private AudioNode shipDestroyedSound; - private AudioNode explosionSound; + private AudioNode passStartSound; + private AudioNode eventCardSound; + private AudioNode gulagSound; + private AudioNode diceRollSound; + private AudioNode moneyCollectSound; + private AudioNode moneyLostSound; + private AudioNode tradeAcceptedSound; + private AudioNode tradeRejectedSound; + private AudioNode winnerSound; + private AudioNode looserSound; + private AudioNode buttonSound; /** * Checks if sound is enabled in the preferences. @@ -75,6 +83,17 @@ public class GameSound extends AbstractAppState implements GameEventListener { @Override public void initialize(AppStateManager stateManager, Application app) { super.initialize(stateManager, app); + passStartSound = loadSound(app, "Sound/Effects/passStart.ogg"); + eventCardSound = loadSound(app, "Sound/Effects/eventCard.ogg"); + gulagSound = loadSound(app, "Sound/Effects/gulag.ogg"); + diceRollSound = loadSound(app, "Sound/Effects/diceRoll.ogg"); + moneyCollectSound = loadSound(app, "Sound/Effects/moneyCollect.ogg"); + moneyLostSound = loadSound(app, "Sound/Effects/moneyLost.ogg"); + tradeAcceptedSound = loadSound(app, "Sound/Effects/tradeAccepted.ogg"); + tradeRejectedSound = loadSound(app, "Sound/Effects/tradeRejected.ogg"); + winnerSound = loadSound(app, "Sound/Effects/winner.ogg"); + looserSound = loadSound(app, "Sound/Effects/looser.ogg"); + buttonSound = loadSound(app, "Sound/Effects/button.ogg"); } /** @@ -98,32 +117,97 @@ public class GameSound extends AbstractAppState implements GameEventListener { } /** - * Plays the splash sound effect. + * Plays the passStart sound effect. */ - public void splash() { - if (isEnabled() && splashSound != null) - splashSound.playInstance(); + public void passStart() { + if (isEnabled() && passStartSound != null) + passStartSound.playInstance(); } - /** - * Plays the explosion sound effect. + * Plays the eventCard sound effect. */ - public void explosion() { - if (isEnabled() && explosionSound != null) - explosionSound.playInstance(); + public void eventCard() { + if (isEnabled() && eventCardSound != null) + eventCardSound.playInstance(); } - /** - * Plays sound effect when a ship has been destroyed. + * Plays the gulag sound effect. */ - public void shipDestroyed() { - if (isEnabled() && shipDestroyedSound != null) - shipDestroyedSound.playInstance(); + public void gulag() { + if (isEnabled() && gulagSound != null) + gulagSound.playInstance(); + } + /** + * Plays the diceRoll sound effect. + */ + public void diceRoll() { + if (isEnabled() && diceRollSound != null) + diceRollSound.playInstance(); + } + /** + * Plays the moneyCollect sound effect. + */ + public void moneyCollect() { + if (isEnabled() && moneyCollectSound != null) + moneyCollectSound.playInstance(); + } + /** + * Plays the moneyLost sound effect. + */ + public void moneyLost() { + if (isEnabled() && moneyLostSound != null) + moneyLostSound.playInstance(); + } + /** + * Plays the tradeAccepted sound effect. + */ + public void tradeAccepted() { + if (isEnabled() && tradeAcceptedSound != null) + tradeAcceptedSound.playInstance(); + } + /** + * Plays the tradeRejected sound effect. + */ + public void tradeRejected() { + if (isEnabled() && tradeRejectedSound != null) + tradeRejectedSound.playInstance(); + } + /** + * Plays the winner sound effect. + */ + public void winner() { + if (isEnabled() && winnerSound != null) + winnerSound.playInstance(); + } + /** + * Plays the looser sound effect. + */ + public void looser() { + if (isEnabled() && looserSound != null) + looserSound.playInstance(); + } + /** + * Plays the button sound effect. + */ + public void button() { + if (isEnabled() && buttonSound != null) + buttonSound.playInstance(); } @Override public void receivedEvent(SoundEvent event) { switch (event.sound()) { + case PASS_START -> passStart(); + case EVENT_CARD -> eventCard(); + case GULAG -> eventCard(); + case DICE_ROLL -> eventCard(); + case MONEY_COLLECTED -> eventCard(); + case MONEY_LOST -> eventCard(); + case TRADE_ACCEPTED -> eventCard(); + case TRADE_REJECTED -> eventCard(); + case WINNER -> eventCard(); + case LOSER -> eventCard(); + case BUTTON -> eventCard(); } } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java index 0a7df7d..8ade0d1 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java @@ -9,25 +9,25 @@ import com.jme3.font.BitmapText; import com.jme3.input.KeyInput; import com.jme3.input.controls.ActionListener; import com.jme3.input.controls.KeyTrigger; - import com.jme3.system.AppSettings; import com.simsilica.lemur.GuiGlobals; -import com.simsilica.lemur.Label; import com.simsilica.lemur.style.BaseStyles; import pp.dialog.DialogBuilder; import pp.dialog.DialogManager; import pp.graphics.Draw; -import pp.monopoly.client.gui.SettingsMenu; -import pp.monopoly.client.gui.TestWorld; +import pp.monopoly.client.gui.*; +import pp.monopoly.client.gui.popups.*; 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; public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener { + private BitmapText topText; private final ServerConnection serverConnection; private final ClientGameLogic logic; @@ -41,16 +41,27 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga 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 EventCard eventCard; + private BuildingPropertyCard buildingProperty; + private FoodFieldCard foodField; + private GateFieldCard gateField; + private BuyCard buyCard; + private boolean isBuyCardPopupOpen = false; + private final ActionListener BListener = (name, isPressed, tpf) -> handleB(isPressed); /** * 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 public static void main(String[] args) { new MonopolyApp().start(); @@ -59,7 +70,8 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga public MonopolyApp() { this.draw = new Draw(assetManager); config = new MonopolyAppConfig(); - serverConnection = new NetworkSupport(this); + networkSupport = new NetworkSupport(this); // Initialize NetworkSupport + serverConnection = networkSupport; logic = new ClientGameLogic(serverConnection); logic.addListener(this); setShowSettings(config.getShowSettings()); @@ -76,6 +88,14 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga 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"); @@ -88,8 +108,10 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga public void simpleInitApp() { GuiGlobals.initialize(this); BaseStyles.loadStyleResources(STYLES_SCRIPT); - GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS - final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS + 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 setupInput(); setupGui(); @@ -110,6 +132,9 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga 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"); } private void handleEscape(boolean isPressed) { @@ -129,18 +154,35 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga } } } - - + + //logik zum wechselnden erscheinen und verschwinden beim drücken von B //TODO süäter entfernen + private void handleB(boolean isPressed) { + if (isPressed) { + if (eventCard != null && isBuyCardPopupOpen) { + // Schließe das SettingsMenu + System.out.println("Schließe BuyCardPopup..."); + eventCard.close(); + eventCard = null; + setBuyCardPopupOpen(false); + } else { + // Öffne das SettingsMenu + System.out.println("Öffne BuyCardPopup..."); + eventCard = new EventCard(this); + eventCard.open(); + setBuyCardPopupOpen(true); + } + } + } private void blockInputs() { if (!inputBlocked) { System.out.println("Blockiere Eingaben..."); inputManager.setCursorVisible(true); // Cursor sichtbar machen - inputManager.clearMappings(); // Alle Mappings entfernen + inputManager.clearMappings(); // Alle Mappings entfernen inputBlocked = true; } } - + public void unblockInputs() { if (inputBlocked) { System.out.println("Aktiviere Eingaben..."); @@ -194,6 +236,12 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga this.isSettingsMenuOpen = isOpen; } + // TODO später entfernen + + public void setBuyCardPopupOpen(boolean isOpen) { + this.isBuyCardPopupOpen = isOpen; + } + @Override public void simpleUpdate(float tpf) { if (testWorld != null) { @@ -204,7 +252,12 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga public void startTestWorld() { guiNode.detachAllChildren(); // Entferne GUI testWorld = new TestWorld(this); // Erstelle eine Instanz von TestWorld - testWorld.initializeScene(); // Initialisiere die Szene + testWorld.initializeScene(); // Initialisiere die Szene + } + + // TODO später entfernen + + public void startBuyCard() { } public void returnToMenu() { @@ -218,9 +271,9 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga public void startServer() { new Thread(() -> { try { - monopolyServer = new MonopolyServer(); // Erstelle Serverinstanz + MonopolyServer.main(new String[0]); // Startet den MonopolyServer } catch (Exception e) { - e.printStackTrace(); + errorDialog("Fehler: Server konnte nicht gestartet werden."); } }).start(); } @@ -228,4 +281,8 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga public MonopolyServer getMonopolyServer() { return monopolyServer; } + + public ServerConnection getServerConnection() { + return serverConnection; + } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java index d399636..23bf5e6 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java @@ -21,7 +21,7 @@ import pp.dialog.SimpleDialog; class NetworkDialog extends SimpleDialog { private static final Logger LOGGER = System.getLogger(NetworkDialog.class.getName()); private static final String LOCALHOST = "localhost"; - private static final String DEFAULT_PORT = "1234"; + private 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); diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java index 3ea11b0..40897de 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java @@ -18,7 +18,7 @@ import pp.monopoly.message.server.ServerMessage; * Manages the network connection for the Monopoly application. * Handles connecting to and disconnecting from the server, and sending messages. */ -class NetworkSupport implements MessageListener, ClientStateListener, ServerConnection { +public class NetworkSupport implements MessageListener, ClientStateListener, ServerConnection { private static final Logger LOGGER = System.getLogger(NetworkSupport.class.getName()); private final MonopolyApp app; private Client client; @@ -41,6 +41,11 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se return app; } + public int getId() { + if (client == null) return 0; + return client.getId(); + } + /** * Checks if there is a connection to the game server. * @@ -80,7 +85,7 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se * @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 { + public void initNetwork(String host, int port) throws IOException { if (client != null) { throw new IllegalStateException("Already connected to the game server."); } @@ -141,4 +146,40 @@ class NetworkSupport implements MessageListener, ClientStateListener, Se 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."); + } + } } \ No newline at end of file diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraController.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraController.java index 314ebb6..a2d04cf 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraController.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CameraController.java @@ -39,21 +39,22 @@ public class CameraController { * @param tpf Zeit pro Frame */ public void update(float tpf) { - // Aktualisiere den Winkel basierend auf der Geschwindigkeit - angle += speed * tpf; - if (angle >= FastMath.TWO_PI) { - angle -= FastMath.TWO_PI; // Winkel zurücksetzen, um Überläufe zu vermeiden - } - - // Berechne die neue Position der Kamera - float x = center.x + radius * FastMath.cos(angle); - float z = center.z + radius * FastMath.sin(angle); - float y = center.y + height; - - // Setze die Kameraposition - camera.setLocation(new Vector3f(x, y, z)); - - // Lasse die Kamera auf den Fokuspunkt blicken camera.lookAt(center, Vector3f.UNIT_Y); } + + public void setPosition(int fieldID) { + camera.setLocation(fieldIdToVector(fieldID)); + } + + public void setPosition(float x, float y) { + camera.setLocation(new Vector3f(x,height,y)); + } + + private Vector3f fieldIdToVector(int fieldID) { + if (fieldID <= 10) return new Vector3f(30,height,0); + if (fieldID <= 20) return new Vector3f(0, height, 30); + if (fieldID <= 30) return new Vector3f(-30, height, 0); + if (fieldID <= 40) return new Vector3f(0, height, -30); + else throw new IllegalArgumentException(); + } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java index d3529b0..b4c0ca0 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java @@ -1,11 +1,7 @@ package pp.monopoly.client.gui; -import javax.swing.JOptionPane; - import com.jme3.material.Material; import com.jme3.math.Vector3f; -import com.jme3.network.Client; -import com.jme3.network.Network; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; import com.jme3.texture.Texture; @@ -16,9 +12,10 @@ import com.simsilica.lemur.Label; import com.simsilica.lemur.TextField; import com.simsilica.lemur.component.SpringGridLayout; +import com.simsilica.lemur.style.ElementId; import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.StartMenu; -import pp.monopoly.server.MonopolyServer; + /** * CreateGameMenu class represents the menu for creating a new game. @@ -41,8 +38,10 @@ public class CreateGameMenu { menuContainer.setPreferredSize(new Vector3f(600, 400, 0)); // Feste Größe des Containers // Titel - Label title = menuContainer.addChild(new Label("Neues Spiel")); - title.setFontSize(48); + 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))); @@ -70,11 +69,26 @@ public class CreateGameMenu { // "Selber hosten"-Button Button hostButton = buttonContainer.addChild(new Button("Selber hosten")); hostButton.setPreferredSize(new Vector3f(120, 40, 0)); - hostButton.addClickCommands(source -> app.startServer()); + hostButton.addClickCommands(source -> app.getNetworkSupport().startServerAndJoin()); - // "Beitreten"-Button (vorerst funktionslos) + // "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")); @@ -86,7 +100,6 @@ public class CreateGameMenu { (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 @@ -97,6 +110,18 @@ public class CreateGameMenu { } }, "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); } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/GameMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/GameMenu.java deleted file mode 100644 index da390c8..0000000 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/GameMenu.java +++ /dev/null @@ -1,51 +0,0 @@ -package pp.monopoly.client.gui; - - -import com.jme3.math.ColorRGBA; -import com.simsilica.lemur.Button; -import com.simsilica.lemur.Label; -import com.simsilica.lemur.style.ElementId; - -import pp.dialog.Dialog; -import pp.monopoly.client.MonopolyApp; - -public class GameMenu extends Dialog { - private final MonopolyApp app; - - /** - * Constructs the SettingsMenu dialog for the Monopoly application. - * - * @param app the MonopolyApp instance - */ - public GameMenu(MonopolyApp app) { - super(app.getDialogManager()); - this.app = app; - - // Add a title label for Settings - Label settingsTitle = new Label("Einstellungen", new ElementId("settings-title")); - settingsTitle.setFontSize(48); // Set font size for the title - settingsTitle.setColor(ColorRGBA.White); - - // Add any settings-related components here, such as volume control, toggles, etc. - - // Add a back button to return to StartMenu - Button backButton = new Button("Zurück", new ElementId("menu-button")); - backButton.setColor(ColorRGBA.White); - backButton.setFontSize(24); - backButton.addClickCommands(source -> returnToStartMenu()); - - // Add components to this dialog - addChild(settingsTitle); - addChild(backButton); - - // You can add more settings components here, like checkboxes or sliders. - } - - /** - * Returns to the StartMenu when the back button is clicked. - */ - private void returnToStartMenu() { - app.getDialogManager().close(this); // Close the current settings dialog - //TODO return zum Ausgangsmenü - } -} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/LobbyMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/LobbyMenu.java new file mode 100644 index 0000000..30f8731 --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/LobbyMenu.java @@ -0,0 +1,398 @@ +package pp.monopoly.client.gui; + +import com.jme3.app.Application; +import com.jme3.app.state.BaseAppState; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Quad; +import com.jme3.scene.shape.Sphere; +import com.jme3.texture.Texture; +import com.simsilica.lemur.Axis; +import com.simsilica.lemur.Button; +import com.simsilica.lemur.Container; +import com.simsilica.lemur.Insets3f; +import com.simsilica.lemur.Label; +import com.simsilica.lemur.Selector; +import com.simsilica.lemur.TextField; +import com.simsilica.lemur.component.QuadBackgroundComponent; +import com.simsilica.lemur.component.SpringGridLayout; + +import com.simsilica.lemur.core.VersionedList; +import com.simsilica.lemur.core.VersionedReference; +import com.simsilica.lemur.style.ElementId; +import pp.monopoly.client.MonopolyApp; +import pp.monopoly.game.client.ClientGameLogic; +import pp.monopoly.game.server.Player; +import pp.monopoly.game.server.PlayerColor; +import pp.monopoly.game.server.PlayerHandler; +import pp.monopoly.model.Figure; +import pp.monopoly.model.Rotation; + +import java.util.Set; + +public class LobbyMenu { + + 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 figureDropdown; + + + public LobbyMenu(MonopolyApp app) { + this.app = app; + this.playerHandler = ClientGameLogic.getPlayerHandler(); // Initialize PlayerHandler + + int playerID = app.getNetworkSupport().getId(); // Retrieve the player ID + assignPlayerColor(playerID); //set the Players Color + + app.getGuiNode().detachAllChildren(); // Entfernt das CreateGameMenu (inklusive Hintergrund) + + 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)); + 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)); + horizontalContainer.setBackground(null); + + Label title = horizontalContainer.addChild(new Label("Startkapital:", new ElementId("label-Bold"))); + title.setFontSize(40); + + // Add a spacer between the title and the input field + Label spacerBeforeInput = horizontalContainer.addChild(new Label("")); // Invisible spacer + spacerBeforeInput.setPreferredSize(new Vector3f(20, 1, 0)); // Width of the spacer + + // Add an input field (TextField) + TextField startingCapital = horizontalContainer.addChild(new TextField("15 000")); + 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 + + // Add a spacer after the input field + Label spacerAfterInput = horizontalContainer.addChild(new Label("")); // Invisible spacer + spacerAfterInput.setPreferredSize(new Vector3f(20, 1, 0)); // Width of the spacer + + menuContainer.setLocalTranslation( + (app.getCamera().getWidth() - menuContainer.getPreferredSize().x) / 2, + (app.getCamera().getHeight() + menuContainer.getPreferredSize().y) / 2, + 1 + ); + app.getGuiNode().attachChild(menuContainer); + + // Dropdowns and Labels + Container dropdownContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y))); + dropdownContainer.setPreferredSize(new Vector3f(800, 200, 0)); + dropdownContainer.setBackground(null); + dropdownContainer.setInsets(new Insets3f(10, 0, 0, 0)); + // Player Input Field + Container playerInputContainer = dropdownContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X))); + playerInputContainer.addChild(new Label("Spieler:")); + playerInputContainer.setBackground(null); + + + TextField playerInputField = new TextField("Spieler 1"); + playerInputField.setPreferredSize(new Vector3f(100, 20, 0)); + 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)); + + // 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 figures = new VersionedList<>(); + figures.add("Laptop"); + figures.add("Flugzeug"); + figures.add("Jägermeister"); + figures.add("Katze"); + figures.add("OOP"); + figures.add("Handyholster"); + + Selector figureDropdown = new Selector<>(figures, "glass"); + figureDropdown.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray)); + 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); + + Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y))); + buttonContainer.setPreferredSize(new Vector3f(100, 40, 0)); + buttonContainer.setInsets(new Insets3f(20, 0, 10, 0)); // Add spacing above the buttons + buttonContainer.setBackground(null); + // Lower-left container for "Abbrechen" button + lowerLeftMenu = new Container(); + Button cancelButton = new Button("Abbrechen"); + 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 + lowerLeftMenu.addChild(cancelButton); + + // 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 + 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 -> applyStartingCapital(playerID)); + readyButton.addClickCommands(source -> applyPlayerName(playerID)); + readyButton.addClickCommands(source -> applyFigure(playerID)); + 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 + 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 + 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 + 2 // Ensure it's in front of the background but behind the dropdown + )); + app.getGuiNode().attachChild(circle); // Attach to the GUI node + + // 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.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. + */ + private void addBackgroundImage() { + Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/lobby.png"); + Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); + background = new Geometry("Background", quad); + Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + backgroundMaterial.setTexture("ColorMap", backgroundImage); + background.setMaterial(backgroundMaterial); + background.setLocalTranslation(0, 0, -1); // Hintergrundebene + + app.getGuiNode().attachChild(background); + } + + 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", playerColor); // Set the desired color + circleGeometry.setMaterial(material); + + return circleGeometry; + } + 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); + } + } + + /** + * Assigns a color to the player based on their ID. + * + * @param playerID the player's ID + */ + private void assignPlayerColor(int playerID) { + switch (playerID) { + case 0: + playerColor = PlayerColor.RED.getColor(); + break; + case 1: + playerColor = PlayerColor.GREEN_LIGHT.getColor(); + break; + case 2: + playerColor = PlayerColor.BLUE.getColor(); + break; + case 3: + playerColor = PlayerColor.PINK.getColor(); + break; + case 4: + playerColor = PlayerColor.GREEN_DARK.getColor(); + break; + case 5: + playerColor = PlayerColor.YELLOW.getColor(); + break; + default: + playerColor = ColorRGBA.White; // Default color if ID is unknown + } + } + + /** + * Geht zurück zum CreateGameMenu. + */ + private void goBackToCreateGame() { + app.getGuiNode().detachChild(menuContainer); + app.getGuiNode().detachChild(background); + app.getGuiNode().detachChild(circle); + app.getGuiNode().detachChild(lowerLeftMenu); + app.getGuiNode().detachChild(lowerRightMenu); + new CreateGameMenu(app); + } + + /** + * Adds a custom action listener to the Selector. + */ + private void addSelectionActionListener(Selector selector, SelectionActionListener listener) { + VersionedReference> selectionRef = selector.getSelectionModel().createReference(); + + app.getStateManager().attach(new BaseAppState() { + @Override + public void update(float tpf) { + if (selectionRef.update()) { + String selected = selectionRef.get().toString(); + System.out.println(selected); + listener.onSelectionChanged(selected); + } + } + + @Override + protected void initialize(Application app) { + } + + @Override + protected void cleanup(Application app) { + } + + @Override + protected void onEnable() { + + } + + @Override + protected void onDisable() { + + } + }); + } + + /** + * Callback for when the dropdown selection changes. + */ + private void onDropdownSelectionChanged(String selected) { + System.out.println("Selected: " + selected); + switch (selected) { + case "[0]": + System.out.println("Laptop selected"); + break; + case "[1]": + System.out.println("Flugzeug selected"); + break; + case "[2]": + System.out.println("Jägermeister selected"); + break; + case "[3]": + System.out.println("Katze selected"); + break; + case "[4]": + System.out.println("OOP selected"); + break; + case "[5]": + System.out.println("Handyholster selected"); + break; + default: + System.out.println("Unknown selection"); + } + } + + /** + * Functional interface for a selection action listener. + */ + @FunctionalInterface + private interface SelectionActionListener { + void onSelectionChanged(T selection); + } +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapView.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapView.java deleted file mode 100644 index f93c1d5..0000000 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapView.java +++ /dev/null @@ -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; - } -} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapViewSynchronizer.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapViewSynchronizer.java deleted file mode 100644 index 4853356..0000000 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/MapViewSynchronizer.java +++ /dev/null @@ -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); - } -} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/ServerScreen.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/ServerScreen.java deleted file mode 100644 index c2794ab..0000000 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/ServerScreen.java +++ /dev/null @@ -1,89 +0,0 @@ -package pp.monopoly.client.gui; - -import java.awt.BorderLayout; -import java.awt.FlowLayout; - -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; - -public class ServerScreen { - private JFrame frame; - private JTextField inputField; - private JLabel label; - private JButton startButton; - private JButton stopButton; - - public ServerScreen() { - initialize(); - } - - private void initialize() { - // Erstelle das Hauptfenster - frame = new JFrame("Server Placeholder"); // Setze den Titel - frame.setSize(400, 200); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setLayout(new BorderLayout()); - - // Eingabefeld und Label im oberen Bereich - JPanel topPanel = new JPanel(); - topPanel.setLayout(new FlowLayout()); - - label = new JLabel("Server-Port:"); - inputField = new JTextField("42069", 10); - topPanel.add(label); - topPanel.add(inputField); - - // Buttons im unteren Bereich - JPanel bottomPanel = new JPanel(); - bottomPanel.setLayout(new FlowLayout()); - - startButton = new JButton("Start Server"); - stopButton = new JButton("Stop Server"); - stopButton.setEnabled(false); // Stop-Button ist anfangs deaktiviert - - bottomPanel.add(startButton); - bottomPanel.add(stopButton); - - // Füge die Panels zum Hauptfenster hinzu - frame.add(topPanel, BorderLayout.NORTH); - frame.add(bottomPanel, BorderLayout.SOUTH); - - // Aktion für Start-Button - startButton.addActionListener(e -> startServer()); - - // Aktion für Stop-Button - stopButton.addActionListener(e -> stopServer()); - - // Zeige das Fenster - frame.setVisible(true); - } - - private void startServer() { - String port = inputField.getText(); - try { - int portNumber = Integer.parseInt(port); - // Server-Startlogik hier einfügen - JOptionPane.showMessageDialog(frame, "Server gestartet auf Port " + portNumber); - startButton.setEnabled(false); // Deaktiviere den Start-Button - stopButton.setEnabled(true); // Aktiviere den Stop-Button - } catch (NumberFormatException e) { - JOptionPane.showMessageDialog(frame, "Ungültiger Port: " + port, "Fehler", JOptionPane.ERROR_MESSAGE); - } - } - - private void stopServer() { - // Server-Stoplogik hier einfügen - JOptionPane.showMessageDialog(frame, "Server gestoppt."); - startButton.setEnabled(true); // Aktiviere den Start-Button - stopButton.setEnabled(false); // Deaktiviere den Stop-Button - } - - public static void main(String[] args) { - SwingUtilities.invokeLater(ServerScreen::new); - } -} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java index 74d320b..5fabf92 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java @@ -3,6 +3,7 @@ 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 com.simsilica.lemur.Button; @@ -12,7 +13,9 @@ 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 pp.monopoly.client.MonopolyApp; @@ -23,6 +26,7 @@ public class SettingsMenu extends Dialog { private final MonopolyApp app; private final Geometry overlayBackground; private final Container settingsContainer; + private final Container backgroundContainer; public SettingsMenu(MonopolyApp app) { super(app.getDialogManager()); @@ -32,10 +36,17 @@ public class SettingsMenu extends Dialog { overlayBackground = createOverlayBackground(); app.getGuiNode().attachChild(overlayBackground); + // Create the background container + backgroundContainer = new Container(); + backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background + app.getGuiNode().attachChild(backgroundContainer); + // Hauptcontainer für das Menü settingsContainer = new Container(); settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f))); + + // Titel Label settingsTitle = settingsContainer.addChild(new Label("Einstellungen", new ElementId("settings-title"))); settingsTitle.setFontSize(48); @@ -45,24 +56,34 @@ public class SettingsMenu extends Dialog { 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, - 1 + 4 + ); + + backgroundContainer.setLocalTranslation( + (app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2, + (app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2, + 3 ); app.getGuiNode().attachChild(settingsContainer); @@ -91,6 +112,7 @@ public class SettingsMenu extends Dialog { 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 diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/TestWorld.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/TestWorld.java index 50a2a23..e88b030 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/TestWorld.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/TestWorld.java @@ -1,5 +1,9 @@ package pp.monopoly.client.gui; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; @@ -43,15 +47,18 @@ public class TestWorld { cameraController = new CameraController( app.getCamera(), // Die Kamera der App Vector3f.ZERO, // Fokus auf die Mitte des Spielfelds - 5, // Radius des Kreises - 3, // Höhe der Kamera - 0.5f // Geschwindigkeit der Bewegung + 4, // Radius des Kreises + 15, // Höhe der Kamera + 0 // Geschwindigkeit der Bewegung ); // Füge die Toolbar hinzu new Toolbar(app, cube); + + cameraController.setPosition(0); } + /** * Aktualisiert die Kameraposition. * @@ -75,12 +82,12 @@ public class TestWorld { */ private void createBoard() { // Erstelle ein Quadrat - Box box = new Box(1, 0.01f, 1); // Dünnes Quadrat für die Textur + Box box = new Box(10, 0.1f, 10); // Dünnes Quadrat für die Textur Geometry geom = new Geometry("Board", box); // Setze das Material mit Textur Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); - Texture texture = app.getAssetManager().loadTexture("Pictures/board.png"); + Texture texture = app.getAssetManager().loadTexture("Pictures/board2.png"); mat.setTexture("ColorMap", texture); geom.setMaterial(mat); diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java index 5a9a3f0..bd49ccf 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java @@ -1,22 +1,25 @@ + package pp.monopoly.client.gui; import java.util.Random; import com.jme3.font.BitmapText; +import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; -import com.simsilica.lemur.Axis; -import com.simsilica.lemur.Button; -import com.simsilica.lemur.Container; +import com.simsilica.lemur.*; +import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.SpringGridLayout; +import com.simsilica.lemur.style.ElementId; +import pp.dialog.Dialog; import pp.monopoly.client.MonopolyApp; /** * Toolbar Klasse, die am unteren Rand der Szene angezeigt wird. * Die Buttons bewegen den Würfel auf dem Spielfeld. */ -public class Toolbar { +public class Toolbar extends Dialog { private final MonopolyApp app; private final Container toolbarContainer; @@ -35,22 +38,64 @@ public class Toolbar { * @param cube Der Würfel, der bewegt werden soll */ public Toolbar(MonopolyApp app, Geometry cube) { + super(app.getDialogManager()); this.app = app; this.cube = cube; // Erstelle die Toolbar - toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y)); + toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y), "toolbar"); // Setze die Position am unteren Rand und die Breite toolbarContainer.setLocalTranslation( 0, // Links bündig - 100, // Höhe über dem unteren Rand + 200, // Höhe über dem unteren Rand 0 // Z-Ebene ); - toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 100, 0)); // Volle Breite + toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 200, 0)); // Volle Breite + // Füge Buttons zur Toolbar hinzu - initializeButtons(); + //initializeButtons(); + + + // Menü-Container: Ein Nested-Container für Kontostand und "Meine Gulag Frei Karten" + Container accountContainer = toolbarContainer.addChild(new Container()); + accountContainer.addChild(new Label("Kontostand", new ElementId("label-Bold"))); + accountContainer.addChild(new Label("6666€", new ElementId("label-Text"))); //TODO Variable hier einsetzen + accountContainer.addChild(new Label("Gulag Frei Karten", new ElementId("label-Bold"))); + accountContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); + + // Add a spacer between accountContainer and overviewContainer + Panel spacer = new Panel(); // Create an empty panel as a spacer + spacer.setPreferredSize(new Vector3f(5, 0, 0)); // Adjust the width as needed + spacer.setBackground(null); + toolbarContainer.addChild(spacer); + + // Menü-Container: Ein Container für Übersicht + Container overviewContainer = toolbarContainer.addChild(new Container()); + overviewContainer.addChild(new Label("Übersicht", new ElementId("label-Bold"))); + overviewContainer.addChild(new Label("„Spieler 1“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen + overviewContainer.addChild(new Label("„Spieler 2“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen + overviewContainer.addChild(new Label("„Spieler 3“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen + overviewContainer.addChild(new Label("„Spieler 4“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen + overviewContainer.addChild(new Label("„Spieler 5“: 1244€", new ElementId("label-Text")));//TODO Variable hier einsetzen + overviewContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); + + // Menü-Container: Ein Container für Würfel + Container diceContainer = toolbarContainer.addChild(new Container()); + + diceContainer.setPreferredSize(new Vector3f(400, 150, 0)); + diceContainer.addChild(new Label("Wo Würfel?", new ElementId("label"))); + diceContainer.addChild(addDiceRollButton()); + diceContainer.setBackground(null); + + + // Menü-Container: Ein Nested-Container für Handeln, Grundstücke und Zug beenden + Container menuContainer = toolbarContainer.addChild(new Container()); + menuContainer.addChild(new Button("Handeln")); + menuContainer.addChild(new Button("Grundstücke")); + menuContainer.addChild(new Button("Zug beenden")); + menuContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); // Füge die Toolbar zur GUI hinzu app.getGuiNode().attachChild(toolbarContainer); @@ -64,9 +109,10 @@ public class Toolbar { * Initialisiert die Buttons in der Toolbar. */ private void initializeButtons() { - addButton("Vorwärts", 1); // Bewegung nach vorne - addButton("Rückwärts", -1); // Bewegung nach hinten + addTradeMenuButton(); // Bewegung nach vorne + addEndTurnButton(); // Bewegung nach hinten addDiceRollButton(); // Würfel-Button + } /** @@ -75,18 +121,41 @@ public class Toolbar { * @param label Der Text des Buttons * @param step Schrittweite (+1 für vorwärts, -1 für rückwärts) */ - private void addButton(String label, int step) { + + /*private void addButton(String label, int step) { Button button = new Button(label); button.setPreferredSize(new Vector3f(150, 50, 0)); // Größe der Buttons button.addClickCommands(source -> moveCube(step)); toolbarContainer.addChild(button); - } + }*/ /** * Fügt den Würfel-Button hinzu, der die Figur entsprechend der gewürfelten Zahl bewegt. */ - private void addDiceRollButton() { + private Button addDiceRollButton() { Button diceButton = new Button("Würfeln"); + diceButton.setPreferredSize(new Vector3f(50, 20, 0)); + diceButton.addClickCommands(source -> rollDice()); + toolbarContainer.addChild(diceButton); + return diceButton; + } + + private void addTradeMenuButton() { + Button diceButton = new Button("Handeln"); + diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons + diceButton.addClickCommands(source -> rollDice()); + 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()); + 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()); toolbarContainer.addChild(diceButton); diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar2.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar2.java new file mode 100644 index 0000000..bc86e17 --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar2.java @@ -0,0 +1,168 @@ +package pp.monopoly.client.gui; + +import java.util.Random; + +import com.jme3.font.BitmapText; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.simsilica.lemur.Axis; +import com.simsilica.lemur.Button; +import com.simsilica.lemur.Container; +import com.simsilica.lemur.component.SpringGridLayout; + +import pp.monopoly.client.MonopolyApp; + +/** + * Toolbar Klasse, die am unteren Rand der Szene angezeigt wird. + * Die Buttons bewegen den Würfel auf dem Spielfeld. + */ +public class Toolbar2 { + + private final MonopolyApp app; + private final Container toolbarContainer; + private final Geometry cube; // Referenz auf den Würfel + private final BitmapText positionText; // Anzeige für die aktuelle Position + private final float boardLimit = 0.95f; // Grenzen des Bretts + private final float stepSize = 0.18f; // Schrittgröße pro Bewegung + private int currentPosition = 0; // Aktuelle Position auf dem Spielfeld + private final int positionsPerSide = 10; // Anzahl der Positionen pro Seite + private final Random random = new Random(); // Zufallsgenerator für den Würfelwurf + + /** + * Konstruktor für die Toolbar. + * + * @param app Die Hauptanwendung (MonopolyApp) + * @param cube Der Würfel, der bewegt werden soll + */ + public Toolbar2(MonopolyApp app, Geometry cube) { + this.app = app; + this.cube = cube; + + // Erstelle die Toolbar + toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y)); + + // Setze die Position am unteren Rand und die Breite + toolbarContainer.setLocalTranslation( + 0, // Links bündig + 100, // Höhe über dem unteren Rand + 0 // Z-Ebene + ); + toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 100, 0)); // Volle Breite + + // Füge Buttons zur Toolbar hinzu + initializeButtons(); + + // Füge die Toolbar zur GUI hinzu + app.getGuiNode().attachChild(toolbarContainer); + + // Erstelle die Position-Anzeige + positionText = createPositionDisplay(); + updatePositionDisplay(); // Initialisiere die Anzeige mit der Startposition + } + + /** + * Initialisiert die Buttons in der Toolbar. + */ + private void initializeButtons() { + addButton("Vorwärts", 1); // Bewegung nach vorne + addButton("Rückwärts", -1); // Bewegung nach hinten + addDiceRollButton(); // Würfel-Button + } + + /** + * Fügt einen Button mit einer Bewegung hinzu. + * + * @param label Der Text des Buttons + * @param step Schrittweite (+1 für vorwärts, -1 für rückwärts) + */ + private void addButton(String label, int step) { + Button button = new Button(label); + button.setPreferredSize(new Vector3f(150, 50, 0)); // Größe der Buttons + button.addClickCommands(source -> moveCube(step)); + toolbarContainer.addChild(button); + } + + /** + * Fügt den Würfel-Button hinzu, der die Figur entsprechend der gewürfelten Zahl bewegt. + */ + private void addDiceRollButton() { + Button diceButton = new Button("Würfeln"); + diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons + diceButton.addClickCommands(source -> rollDice()); + toolbarContainer.addChild(diceButton); + } + + /** + * Simuliert einen Würfelwurf und bewegt die Figur entsprechend. + */ + private void rollDice() { + int diceRoll = random.nextInt(6) + 1; // Zahl zwischen 1 und 6 + System.out.println("Gewürfelt: " + diceRoll); + moveCube(diceRoll); // Bewege die Figur um die gewürfelte Zahl + } + + /** + * Bewegt den Würfel basierend auf der aktuellen Position auf dem Brett. + * + * @param step Schrittweite (+1 für vorwärts, -1 für rückwärts oder andere Werte) + */ + private void moveCube(int step) { + currentPosition = (currentPosition + step + 4 * positionsPerSide) % (4 * positionsPerSide); + Vector3f newPosition = calculatePosition(currentPosition); + cube.setLocalTranslation(newPosition); + updatePositionDisplay(); // Aktualisiere die Positionsanzeige + System.out.println("Würfelposition: " + newPosition + " (Feld-ID: " + currentPosition + ")"); + } + + /** + * Berechnet die neue Position des Würfels basierend auf der aktuellen Brettseite und Position. + * + * @param position Aktuelle Position auf dem Spielfeld + * @return Die berechnete Position als Vector3f + */ + private Vector3f calculatePosition(int position) { + int side = position / positionsPerSide; // Seite des Bretts (0 = unten, 1 = rechts, 2 = oben, 3 = links) + int offset = position % positionsPerSide; // Position auf der aktuellen Seite + + switch (side) { + case 0: // Unten (positive x-Achse) + return new Vector3f(-boardLimit + offset * stepSize, 0.1f, -boardLimit + 0.05f); + case 1: // Rechts (positive z-Achse) + return new Vector3f(boardLimit - 0.05f, 0.1f, -boardLimit + offset * stepSize); + case 2: // Oben (negative x-Achse) + return new Vector3f(boardLimit - offset * stepSize, 0.1f, boardLimit - 0.05f); + case 3: // Links (negative z-Achse) + return new Vector3f(-boardLimit + 0.05f, 0.1f, boardLimit - offset * stepSize); + default: + throw new IllegalArgumentException("Ungültige Position: " + position); + } + } + + /** + * Erstellt die Anzeige für die aktuelle Position. + * + * @return Das BitmapText-Objekt für die Anzeige + */ + private BitmapText createPositionDisplay() { + BitmapText text = new BitmapText(app.getAssetManager().loadFont("Interface/Fonts/Default.fnt"), false); + text.setSize(20); // Schriftgröße + text.setLocalTranslation(10, app.getCamera().getHeight() - 10, 0); // Oben links + app.getGuiNode().attachChild(text); + return text; + } + + /** + * Aktualisiert die Anzeige für die aktuelle Position. + */ + private void updatePositionDisplay() { + positionText.setText("Feld-ID: " + currentPosition); + } + + /** + * Entfernt die Toolbar. + */ + public void remove() { + app.getGuiNode().detachChild(toolbarContainer); + app.getGuiNode().detachChild(positionText); + } +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuildingPropertyCard.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuildingPropertyCard.java new file mode 100644 index 0000000..85426cd --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuildingPropertyCard.java @@ -0,0 +1,133 @@ +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.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; + +/** + * TODO Kommentare fixen + * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann. + */ +public class BuildingPropertyCard extends Dialog { + private final MonopolyApp app; + private final Geometry overlayBackground; + private final Container buildingPropertyContainer; + private final Container backgroundContainer; + 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); + + // 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 + buildingPropertyContainer = new Container(); + buildingPropertyContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor())); + + + Label settingsTitle = buildingPropertyContainer.addChild(new Label( field.getName(), new ElementId("settings-title"))); + settingsTitle.setFontSize(48); + + // Text, der auf der Karte steht + // Die Preise werden dynamisch dem BoardManager entnommen + Container propertyValuesContainer = buildingPropertyContainer.addChild(new Container()); + propertyValuesContainer.addChild(new Label("„Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile + propertyValuesContainer.addChild(new Label("„Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 1 Haus: " + field.getAllRent().get(1) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 2 Häuser: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 3 Häuser: " + field.getAllRent().get(3) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 4 Häuser: " + field.getAllRent().get(4) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 1 Hotel: " + field.getAllRent().get(5) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile + propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); + + //TODO eventuell diese Stelle löschen, da nur die BuyCard Kaufen und beenden hat + + /* + // Beenden-Button + Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button"))); + quitButton.setFontSize(32); + // Kaufen-Button + Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button"))); + buyButton.setFontSize(32); + */ + + float padding = 10; // Padding around the settingsContainer for the background + backgroundContainer.setPreferredSize(buildingPropertyContainer.getPreferredSize().addLocal(padding, padding, 0)); + + + // Zentriere das Menü + buildingPropertyContainer.setLocalTranslation( + (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x) / 2, + (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y) / 2, + 8 + ); + + backgroundContainer.setLocalTranslation( + (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x - padding) / 2, + (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y+ padding) / 2, + 7 + ); + + app.getGuiNode().attachChild(buildingPropertyContainer); + } + + /** + * 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(buildingPropertyContainer); // Entferne das Menü + app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand + app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay + 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 + } + + public void setIndex(int index) { + this.index = index; + } + +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuyCard.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuyCard.java new file mode 100644 index 0000000..88a5dc1 --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuyCard.java @@ -0,0 +1,122 @@ +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.*; +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. + */ +public class BuyCard extends Dialog { + private final MonopolyApp app; + private final Geometry overlayBackground; + private final Container buyCardContainer; + private final Container backgroundContainer; + + private int index = 37; + + public BuyCard(MonopolyApp app) { + super(app.getDialogManager()); + this.app = app; + + //Generate the corresponfing field + BuildingProperty field = (BuildingProperty) app.getBoardManager().getFieldAtIndex(index); + + // Halbtransparentes Overlay hinzufügen + overlayBackground = createOverlayBackground(); + app.getGuiNode().attachChild(overlayBackground); + + // Create the background container + backgroundContainer = new Container(); + backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background + app.getGuiNode().attachChild(backgroundContainer); + + // Hauptcontainer für die Gebäudekarte + buyCardContainer = new Container(); + buyCardContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor())); + + + Label settingsTitle = buyCardContainer.addChild(new Label( field.getName(), new ElementId("settings-title"))); + settingsTitle.setFontSize(48); + + // Text, der auf der Karte steht + // Die Preise werden dynamisch dem BoardManager entnommen + Container propertyValuesContainer = buyCardContainer.addChild(new Container()); + propertyValuesContainer.addChild(new Label("„Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile + propertyValuesContainer.addChild(new Label("„Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 1 Haus: " + field.getAllRent().get(1) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 2 Häuser: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 3 Häuser: " + field.getAllRent().get(3) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 4 Häuser: " + field.getAllRent().get(4) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-mit 1 Hotel: " + field.getAllRent().get(5) + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„-1 Haus kostet: " + field.getHousePrice()+ " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile + propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); + + // Beenden-Button + Button quitButton = buyCardContainer.addChild(new Button("Beenden", new ElementId("button"))); + quitButton.setFontSize(32); + // Kaufen-Button + Button buyButton = buyCardContainer.addChild(new Button("Kaufen", new ElementId("button"))); + buyButton.setFontSize(32); + + float padding = 10; // Padding around the settingsContainer for the background + backgroundContainer.setPreferredSize(buyCardContainer.getPreferredSize().addLocal(padding, padding, 0)); + + + // Zentriere das Menü + buyCardContainer.setLocalTranslation( + (app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x) / 2, + (app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y) / 2, + 8 + ); + + backgroundContainer.setLocalTranslation( + (app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x - padding) / 2, + (app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y+ padding) / 2, + 7 + ); + + app.getGuiNode().attachChild(buyCardContainer); + } + + /** + * Erstellt einen halbtransparenten Hintergrund für das Menü. + * + * @return Geometrie des Overlays + */ + private Geometry createOverlayBackground() { + Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); + Geometry overlay = new Geometry("Overlay", quad); + Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent + material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + overlay.setMaterial(material); + overlay.setLocalTranslation(0, 0, 0); + return overlay; + } + + /** + * Schließt das Menü und entfernt die GUI-Elemente. + */ + @Override + public void close() { + System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe + 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 TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp + app.unblockInputs(); // Eingaben wieder aktivieren + System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe + } +} \ No newline at end of file diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/EventCard.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/EventCard.java new file mode 100644 index 0000000..60e4cb3 --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/EventCard.java @@ -0,0 +1,119 @@ +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.fields.BuildingProperty; + +/** + * 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; + + private int index = 37; + + public EventCard(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); + + // 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("Hier könnte ihre Beschreibung stehen ", 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 + } +} \ No newline at end of file diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/FoodFieldCard.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/FoodFieldCard.java new file mode 100644 index 0000000..05bf891 --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/FoodFieldCard.java @@ -0,0 +1,137 @@ +package pp.monopoly.client.gui.popups; + +import com.jme3.material.Material; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.math.ColorRGBA; +import com.jme3.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.fields.FoodField; + +/** + * FoodFieldCard erstellt die Geböudekarte vom Brandl und der Truppenküche + */ +public class FoodFieldCard extends Dialog { + private final MonopolyApp app; + private final Geometry overlayBackground; + private final Container foodFieldContainer; + private final Container backgroundContainer; + private int index = 12; + + public FoodFieldCard(MonopolyApp app) { + super(app.getDialogManager()); + this.app = app; + + //Generate the corresponfing field + FoodField field = (FoodField) app.getBoardManager().getFieldAtIndex(index); + + // Halbtransparentes Overlay hinzufügen + overlayBackground = createOverlayBackground(); + app.getGuiNode().attachChild(overlayBackground); + + // Create the background container + backgroundContainer = new Container(); + backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background + app.getGuiNode().attachChild(backgroundContainer); + + // Hauptcontainer für die Gebäudekarte + foodFieldContainer = new Container(); + foodFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f))); + + + + // Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe + Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title"))); + settingsTitle.setFontSize(48); + + // Text, der auf der Karte steht + Container propertyValuesContainer = foodFieldContainer.addChild(new Container()); + propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile + propertyValuesContainer.addChild(new Label("„Wenn man Besitzer des", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label(field.getName()+" ist, so ist die", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("Miete 40-mal so hoch, wie", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("Augen auf den zwei Würfeln sind.", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile + propertyValuesContainer.addChild(new Label("„Wenn man Besitzer beider", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("Restaurants ist, so ist die", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("Miete 100-mal so hoch, wie", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("Augen auf den zwei Würfeln sind.", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile + propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); + + + //TODO eventuell diese Stelle löschen, da nur die BuyCard Kaufen und beenden hat + + /* + // Beenden-Button + Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button"))); + quitButton.setFontSize(32); + // Kaufen-Button + Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button"))); + buyButton.setFontSize(32); + */ + + float padding = 10; // Padding around the settingsContainer for the background + backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0)); + + + // Zentriere das Menü + foodFieldContainer.setLocalTranslation( + (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x) / 2, + (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y) / 2, + 8 + ); + + backgroundContainer.setLocalTranslation( + (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x - padding) / 2, + (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y+ padding) / 2, + 7 + ); + + app.getGuiNode().attachChild(foodFieldContainer); + } + + /** + * 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(foodFieldContainer); // Entferne das Menü + app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand + app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay + 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 + } + + public void setIndex(int index) { + this.index = index; + } + +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/GateFieldCard.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/GateFieldCard.java new file mode 100644 index 0000000..373440b --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/GateFieldCard.java @@ -0,0 +1,129 @@ +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.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.GateField; + +/** + * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann. + */ +public class GateFieldCard extends Dialog { + private final MonopolyApp app; + private final Geometry overlayBackground; + private final Container gateFieldContainer; + private final Container backgroundContainer; + private int index = 5; + + public GateFieldCard(MonopolyApp app) { + super(app.getDialogManager()); + this.app = app; + + //Generate the corresponfing field + GateField field = (GateField) app.getBoardManager().getFieldAtIndex(index); + + // Halbtransparentes Overlay hinzufügen + overlayBackground = createOverlayBackground(); + app.getGuiNode().attachChild(overlayBackground); + + // Create the background container + backgroundContainer = new Container(); + backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background + app.getGuiNode().attachChild(backgroundContainer); + + // Hauptcontainer für die Gebäudekarte + gateFieldContainer = new Container(); + gateFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); + + // Titel + // Die Namen werden dynamisch dem BoardManager entnommen + Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title"))); + gateFieldTitle.setFontSize(48); + gateFieldTitle.setColor(ColorRGBA.Black); + + // Text, der auf der Karte steht + // Die Preise werden dynamisch dem BoardManager entnommen + Container propertyValuesContainer = gateFieldContainer.addChild(new Container()); + propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("Wenn man 1 Bahnhof besitzt: 250 EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("Wenn man 2 Bahnhöfe besitzt: 500 EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("Wenn man 3 Bahnhöfe besitzt: 1000 EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("Wenn man 4 Bahnhöfe besitzt: 2000 EUR", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); + propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", new ElementId("label-Text"))); + propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); + + //TODO eventuell diese Stelle löschen, da nur die BuyCard Kaufen und beenden hat + + /* + // Beenden-Button + Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button"))); + quitButton.setFontSize(32); + // Kaufen-Button + Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button"))); + buyButton.setFontSize(32); + */ + + float padding = 10; // Padding around the settingsContainer for the background + backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0)); + + + // Zentriere das Menü + gateFieldContainer.setLocalTranslation( + (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2, + (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2, + 8 + ); + + backgroundContainer.setLocalTranslation( + (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x - padding) / 2, + (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y+ padding) / 2, + 7 + ); + + app.getGuiNode().attachChild(gateFieldContainer); + } + + /** + * 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(gateFieldContainer); // Entferne das Menü + app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand + app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay + 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 + } + + public void setIndex(int index) { + this.index = index; + } +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/SelectionListener.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/SelectionListener.java new file mode 100644 index 0000000..e668df5 --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/SelectionListener.java @@ -0,0 +1,49 @@ +package pp.monopoly.client.gui.popups; + +/* + * $Id$ + * + * Copyright (c) 2013-2013 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +import com.jme3.scene.Spatial; + + +/** + * Notified when the current selection changes. + * + * @author Paul Speed + */ +public interface SelectionListener { + + public void selectionChanged( Spatial selection, Spatial previous ); +} diff --git a/Projekte/monopoly/client/src/main/resources/Pictures/board2.png b/Projekte/monopoly/client/src/main/resources/Pictures/board2.png new file mode 100644 index 0000000..4cd3bdc Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Pictures/board2.png differ diff --git a/Projekte/monopoly/client/src/main/resources/Pictures/lobby.png b/Projekte/monopoly/client/src/main/resources/Pictures/lobby.png new file mode 100644 index 0000000..da2cfc5 Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Pictures/lobby.png differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/button.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/button.ogg new file mode 100644 index 0000000..c95c40b Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/button.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/diceRoll.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/diceRoll.ogg new file mode 100644 index 0000000..0b0eb1d Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/diceRoll.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/eventCard.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/eventCard.ogg new file mode 100644 index 0000000..1ba649f Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/eventCard.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/gulag.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/gulag.ogg new file mode 100644 index 0000000..b0a118a Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/gulag.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/loser.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/loser.ogg new file mode 100644 index 0000000..d695688 Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/loser.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/moneyCollect.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/moneyCollect.ogg new file mode 100644 index 0000000..4a2c662 Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/moneyCollect.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/moneyLost.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/moneyLost.ogg new file mode 100644 index 0000000..fc1a68e Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/moneyLost.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/passStart.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/passStart.ogg new file mode 100644 index 0000000..45d6fec Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/passStart.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/tradeAccepted.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/tradeAccepted.ogg new file mode 100644 index 0000000..06bca39 Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/tradeAccepted.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/tradeRejected.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/tradeRejected.ogg new file mode 100644 index 0000000..b3d8d09 Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/tradeRejected.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/Effects/winner.ogg b/Projekte/monopoly/client/src/main/resources/Sound/Effects/winner.ogg new file mode 100644 index 0000000..7648cce Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/Effects/winner.ogg differ diff --git a/Projekte/monopoly/client/src/main/resources/Sound/background.ogg b/Projekte/monopoly/client/src/main/resources/Sound/background.ogg new file mode 100644 index 0000000..b47ec29 Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Sound/background.ogg differ diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/MonopolyConfig.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/MonopolyConfig.java index 3a5da01..2fe9495 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/MonopolyConfig.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/MonopolyConfig.java @@ -28,19 +28,19 @@ public class MonopolyConfig extends Config { * The default port number for the Monopoly server. */ @Property("port") - private int port = 42069; + private int port = 4321; /** * The width of the game map in terms of grid units. */ @Property("map.width") - private int mapWidth = 10; + private int mapWidth = 12; /** * The height of the game map in terms of grid units. */ @Property("map.height") - private int mapHeight = 10; + private int mapHeight = 12; /** * Creates an instance of {@code MonopolyConfig} with default settings. diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ActiveState.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ActiveState.java new file mode 100644 index 0000000..78dfed1 --- /dev/null +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ActiveState.java @@ -0,0 +1,8 @@ +package pp.monopoly.game.client; + +public class ActiveState extends ClientState{ + + ActiveState(ClientGameLogic logic) { + super(logic); + } +} diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ClientGameLogic.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ClientGameLogic.java index f972be6..dda8499 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ClientGameLogic.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ClientGameLogic.java @@ -1,19 +1,11 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - package pp.monopoly.game.client; -import java.io.File; -import java.io.IOException; import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.util.ArrayList; import java.util.List; +import pp.monopoly.game.server.PlayerHandler; import pp.monopoly.message.client.ClientMessage; import pp.monopoly.message.server.BuyPropertyResponse; import pp.monopoly.message.server.DiceResult; @@ -21,6 +13,7 @@ import pp.monopoly.message.server.EventDrawCard; import pp.monopoly.message.server.GameOver; import pp.monopoly.message.server.GameStart; import pp.monopoly.message.server.JailEvent; +import pp.monopoly.message.server.NextPlayerTurn; import pp.monopoly.message.server.PlayerStatusUpdate; import pp.monopoly.message.server.ServerInterpreter; import pp.monopoly.message.server.TimeOutWarning; @@ -37,26 +30,28 @@ import pp.monopoly.notification.InfoTextEvent; import pp.monopoly.notification.Sound; import pp.monopoly.notification.SoundEvent; -import java.io.File; -import java.io.IOException; -import java.lang.System.Logger; -import java.lang.System.Logger.Level; -import java.util.ArrayList; -import java.util.List; - /** * Controls the client-side game logic for Monopoly. - * Manages the player's placement, interactions with the map, and response to server messages. + * Handles interactions with the server and game state management on the client side. */ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { + + /** Logger for the client-side game logic. */ static final Logger LOGGER = System.getLogger(ClientGameLogic.class.getName()); + + /** The object responsible for sending messages to the server. */ private final ClientSender clientSender; + + /** A list of listeners to receive game events. */ private final List listeners = new ArrayList<>(); + + /** The game board representing the player's current state. */ private Board board; - private ClientState state = new ClientState(this) { - - }; + /** The current state of the client game logic. */ + private ClientState state = new LobbyState(this); + + private static PlayerHandler playerHandler; /** * Constructs a ClientGameLogic with the specified sender object. @@ -69,6 +64,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { /** * Returns the current state of the game logic. + * + * @return the current state */ ClientState getState() { return state; @@ -86,10 +83,14 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { state.entry(); } + public static PlayerHandler getPlayerHandler() { + return playerHandler; + } + /** - * Returns the player's own map. + * Returns the player's game board. * - * @return the player's own map + * @return the player's game board */ public Board getBoard() { return board; @@ -116,32 +117,23 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { /** * Emits an event to play the specified sound. * - * @param sound the sound to be played. + * @param sound the sound to be played */ public void playSound(Sound sound) { notifyListeners(new SoundEvent(sound)); } - /** - * Loads a map from the specified file. - * - * @param file the file to load the map from - * @throws IOException if an I/O error occurs - */ - public void loadMap(File file) throws IOException { - state.loadMap(file); - } - /** * Sends a message to the server. * * @param msg the message to be sent */ void send(ClientMessage msg) { - if (clientSender == null) + if (clientSender == null) { LOGGER.log(Level.ERROR, "trying to send {0} with sender==null", msg); //NON-NLS - else + } else { clientSender.send(msg); + } } /** @@ -173,12 +165,13 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { synchronized (this) { copy = new ArrayList<>(listeners); } - for (GameEventListener listener : copy) + for (GameEventListener listener : copy) { event.notifyListener(listener); + } } /** - * Called once per frame by the update loop. + * Updates the game logic once per frame in the update loop. * * @param delta time in seconds since the last update call */ @@ -186,6 +179,11 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { state.update(delta); } + /** + * Handles the response for buying a property. + * + * @param msg the message containing the buy property response + */ @Override public void received(BuyPropertyResponse msg) { if (msg.isSuccessful()) { @@ -195,35 +193,66 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { setInfoText("Unable to buy " + msg.getPropertyName() + ". Reason: " + msg.getReason()); } } - + + /** + * Handles the result of a dice roll. + * + * @param msg the message containing the dice roll result + */ @Override public void received(DiceResult msg) { setInfoText("You rolled a " + msg.calcTotal() + "!"); + //Set the dice images playSound(Sound.DICE_ROLL); } - + + /** + * Handles drawing an event card. + * + * @param msg the message containing the drawn card details + */ @Override public void received(EventDrawCard msg) { setInfoText("Event card drawn: " + msg.getCardDescription()); + //event card logic playSound(Sound.EVENT_CARD); } - + + /** + * Handles the game over message. + * + * @param msg the message containing game over details + */ @Override public void received(GameOver msg) { if (msg.isWinner()) { setInfoText("Congratulations! You have won the game!"); + //Winner popup playSound(Sound.WINNER); } else { setInfoText("Game over. Better luck next time!"); + // Looser popup playSound(Sound.LOSER); } } - + + /** + * Handles the start of the game. + * + * @param msg the game start message + */ @Override public void received(GameStart msg) { + playerHandler = msg.getPlayerHandler(); setInfoText("The game has started! Good luck!"); + setState(new WaitForTurnState(this)); } - + + /** + * Handles jail-related events. + * + * @param msg the message containing jail event details + */ @Override public void received(JailEvent msg) { if (msg.isGoingToJail()) { @@ -233,28 +262,74 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { setInfoText("You are out of jail!"); } } - + + /** + * Updates the status of a player. + * + * @param msg the message containing player status update details + */ @Override public void received(PlayerStatusUpdate msg) { + setInfoText("Player " + msg.getPlayerName() + " status updated: " + msg.getStatus()); } - + + /** + * Handles timeout warnings. + * + * @param msg the message containing timeout warning details + */ @Override public void received(TimeOutWarning msg) { setInfoText("Warning! Time is running out. You have " + msg.getRemainingTime() + " seconds left."); } - + + /** + * Displays the player's assets in response to a server query. + * + * @param msg the message containing the player's assets + */ @Override public void received(ViewAssetsResponse msg) { setInfoText("Your current assets are being displayed."); } - + + /** + * Handles trade replies from other players. + * + * @param msg the message containing the trade reply + */ @Override public void received(TradeReply msg) { + if (msg.getTradeHandler().getStatus()) { + setInfoText("Trade accepted by " + msg.getTradeHandler().getReceiver().getName() + "."); + playSound(Sound.TRADE_ACCEPTED); + } else { + setInfoText("Trade rejected by " + msg.getTradeHandler().getReceiver().getName() + "."); + playSound(Sound.TRADE_REJECTED); + } } - + + /** + * Handles trade requests from other players. + * + * @param msg the message containing the trade request details + */ @Override public void received(TradeRequest msg) { + setInfoText("Trade offer received from " + msg.getTradeHandler().getSender().getName()); + // playSound(Sound.TRADE_REQUEST); no sound effect + // notifyListeners(); + } + + /** + * Handles the transition to the next player's turn. + * + * @param msg the message indicating it's the next player's turn + */ + @Override + public void received(NextPlayerTurn msg) { + setInfoText("It's your turn!"); + setState(new ActiveState(this)); } - } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/LobbyState.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/LobbyState.java new file mode 100644 index 0000000..5fc6bd0 --- /dev/null +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/LobbyState.java @@ -0,0 +1,8 @@ +package pp.monopoly.game.client; + +public class LobbyState extends ClientState{ + + LobbyState(ClientGameLogic logic) { + super(logic); + } +} diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/WaitForTurnState.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/WaitForTurnState.java new file mode 100644 index 0000000..d6c6407 --- /dev/null +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/WaitForTurnState.java @@ -0,0 +1,8 @@ +package pp.monopoly.game.client; + +public class WaitForTurnState extends ClientState{ + + WaitForTurnState(ClientGameLogic logic) { + super(logic); + } +} diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/Player.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/Player.java index a8701cb..eddbe2a 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/Player.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/Player.java @@ -13,7 +13,7 @@ import java.util.Random; import pp.monopoly.message.server.DiceResult; import pp.monopoly.model.FieldVisitor; import pp.monopoly.model.Figure; -import pp.monopoly.model.card.DeckHelper; +import pp.monopoly.model.card.Card; import pp.monopoly.model.fields.BuildingProperty; import pp.monopoly.model.fields.EventField; import pp.monopoly.model.fields.FineField; @@ -31,8 +31,7 @@ import pp.monopoly.model.fields.WacheField; public class Player implements FieldVisitor{ private final int id; private String name; - private PlayerColor color; - private int accountBalance = 0; + private int accountBalance = 15000; private Figure figure; private List properties; private int getOutOfJailCard; @@ -63,20 +62,38 @@ public class Player implements FieldVisitor{ this.handler = handler; } + public void setFigure(Figure figure) { + this.figure = figure; + } + + public PlayerColor getColor() { + switch ((id%6)+1) { + case 1: return PlayerColor.BLUE; + case 2: return PlayerColor.GREEN_DARK; + case 3: return PlayerColor.GREEN_LIGHT; + case 4: return PlayerColor.PINK; + case 5: return PlayerColor.RED; + case 6: return PlayerColor.YELLOW; + + default: + return null; + } + } + /** * Set the name of the Player * @param name the new name */ - void setName(String name) { + public void setName(String name) { this.name = name; } /** - * Set the PlayerColor - * @param color the color to be set to + * Retuns the Playerhandler + * @return the Playerhandler */ - void setColor(PlayerColor color) { - this.color = color; + public PlayerHandler getHandler() { + return handler; } /** @@ -94,6 +111,21 @@ public class Player implements FieldVisitor{ 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 @@ -115,9 +147,11 @@ public class Player implements FieldVisitor{ fieldID = fieldID%40; earnMoney(2000); } + figure.moveTo(fieldID); return fieldID; } + /** * Gets all the properties owned by this player * @return List of all properties owned by this player @@ -134,6 +168,7 @@ public class Player implements FieldVisitor{ public void buyProperty(PropertyField property) { if (property.getOwner() == null && accountBalance >= property.getPrice()) { properties.add(property); + property.setOwner(this); pay(property.getPrice()); } } @@ -149,6 +184,14 @@ public class Player implements FieldVisitor{ } } + /** + * Set the account Balance + * @param accountBalance the amount to be set to + */ + public void setAccountBalance(int accountBalance) { + this.accountBalance = accountBalance; + } + /** * Gets this players current accountBalanece * @return the amount of money currently owned by this player @@ -264,7 +307,8 @@ public class Player implements FieldVisitor{ @Override public Void visit(EventField field) { - DeckHelper.drawCard(); + Card c = getHandler().getLogic().getDeckHelper().drawCard(); + getHandler().getLogic().getDeckHelper().visit(c, this); return null; } @@ -307,6 +351,26 @@ public class Player implements FieldVisitor{ 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. @@ -440,47 +504,19 @@ public class Player implements FieldVisitor{ } } - - 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'"); } } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/PlayerHandler.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/PlayerHandler.java index d7bbe10..285e707 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/PlayerHandler.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/PlayerHandler.java @@ -2,17 +2,22 @@ package pp.monopoly.game.server; import java.util.LinkedList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; + +import pp.monopoly.model.LimitedLinkedList; /** * A class for helping with player actions and managing thier turns */ public class PlayerHandler { - private List players = new LinkedList<>(); + private List players = new LimitedLinkedList<>(6); private Set readyPlayers = new HashSet<>(); private ServerGameLogic logic; + private Player hostPlayer; + private Player extra = null; /** * Contructs a PlayerHandler @@ -42,6 +47,14 @@ public class PlayerHandler { players.addAll(players); } + /** + * Return the host player + * @return the host player + */ + public Player getHostPlayer() { + return hostPlayer; + } + /** * Return the number of players * @return number of players in the game @@ -50,6 +63,14 @@ public class PlayerHandler { return players.size(); } + /** + * Retuns all players + * @return List of all players + */ + public List getPlayers() { + return players; + } + /** * Chechs if all players are ready to start the game * @return {@code true} if all players are ready, otherwise {@code false} @@ -85,6 +106,9 @@ public class PlayerHandler { throw new IllegalArgumentException("Player already registered"); } players.add(player); + if(hostPlayer == null) { + hostPlayer = player; + } } /** @@ -108,8 +132,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); @@ -119,7 +148,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; } @@ -128,10 +157,32 @@ 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; } throw new NoSuchElementException("Player mit id "+id+" existiert nicht"); } + + /** + * 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(); + } + + public void setStartBalance(int amount) { + for (Player player : players) { + player.setAccountBalance(amount); + } + } + + public void extraTurn(Player player) { + if (players.contains(player)) extra = player; + } } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/ServerGameLogic.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/ServerGameLogic.java index 0685b39..53555a5 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/ServerGameLogic.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/ServerGameLogic.java @@ -1,20 +1,30 @@ package pp.monopoly.game.server; -import pp.monopoly.MonopolyConfig; -import pp.monopoly.message.client.*; -import pp.monopoly.message.server.ServerMessage; -import pp.monopoly.message.server.TradeReply; -import pp.monopoly.message.server.TradeRequest; -import pp.monopoly.message.server.ViewAssetsResponse; -import pp.monopoly.model.fields.BoardManager; -import pp.monopoly.model.fields.PropertyField; - import java.lang.System.Logger; import java.lang.System.Logger.Level; import pp.monopoly.MonopolyConfig; +import pp.monopoly.message.client.BuyPropertyRequest; import pp.monopoly.message.client.ClientInterpreter; +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.PlayerStatusUpdate; import pp.monopoly.message.server.ServerMessage; +import pp.monopoly.message.server.TradeReply; +import pp.monopoly.message.server.TradeRequest; +import pp.monopoly.message.server.ViewAssetsResponse; +import pp.monopoly.model.Board; +import pp.monopoly.model.Figure; +import pp.monopoly.model.Rotation; +import pp.monopoly.model.card.DeckHelper; +import pp.monopoly.model.fields.BoardManager; +import pp.monopoly.model.fields.PropertyField; /** * Controls the server-side game logic for Monopoly. @@ -26,9 +36,11 @@ public class ServerGameLogic implements ClientInterpreter { private final MonopolyConfig config; private final PlayerHandler playerHandler = new PlayerHandler(this); private final ServerSender serverSender; - private ServerState state = ServerState.CREATEGAME; + 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; /** * Constructs a ServerGameLogic instance with the specified sender and configuration. @@ -120,6 +132,7 @@ public class ServerGameLogic implements ClientInterpreter { playerHandler.addPlayer(player); LOGGER.log(Level.DEBUG, "Player added: {0}", player.getId()); + System.out.println("Anzahl Spieler verbunden:"+ playerHandler.getPlayerCount()); return player; } @@ -158,8 +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()); - playerHandler.nextPlayer(); + 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)); + } } } @@ -172,12 +189,26 @@ public class ServerGameLogic implements ClientInterpreter { @Override public void received(PlayerReady msg, int from) { Player player = playerHandler.getPlayerById(from); + if(player == playerHandler.getHostPlayer()) { + startMoney = msg.getStartMoney(); + } + if (player != null) { player.setName(msg.getName()); - player.setColor(msg.getColor()); - player.setName(msg.getName()); + player.setFigure(new Figure(1, -10, -10, Rotation.LEFT, msg.getFigure())); + //TODO add figure to the map + playerHandler.setPlayerReady(player, true); LOGGER.log(Level.DEBUG, "Player {0} is ready", player.getName()); } + + if(playerHandler.allPlayersReady()) { + playerHandler.setStartBalance(startMoney); + for (Player p : playerHandler.getPlayers()) { + send(p, new GameStart(playerHandler)); + } + playerHandler.randomOrder(); + send(playerHandler.getPlayerAtIndex(0), new NextPlayerTurn(playerHandler.getPlayerAtIndex(0))); + } } /** @@ -236,11 +267,12 @@ public class ServerGameLogic implements ClientInterpreter { */ @Override public void received(ViewAssetsRequest msg, int from) { - Player player = playerHandler.getPlayerById(from); - if (player != null) { - LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", player.getName()); + Player sender = playerHandler.getPlayerById(from); + Player player = msg.getPlayer(); + if (sender != null && player != null) { + LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", sender.getName()); - send(player, new ViewAssetsResponse(player.getProperties(), player.getAccountBalance(), player.getNumJailCard())); + send(sender, new ViewAssetsResponse(boardManager, player.getProperties(), player.getAccountBalance(), player.getNumJailCard())); } } @@ -256,4 +288,8 @@ public class ServerGameLogic implements ClientInterpreter { public Player getPlayerById(int id) { return playerHandler.getPlayerById(id); } + + public DeckHelper getDeckHelper() { + return deckHelper; + } } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/PlayerReady.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/PlayerReady.java index 6324b9e..42aa0d6 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/PlayerReady.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/PlayerReady.java @@ -1,49 +1,43 @@ package pp.monopoly.message.client; -import pp.monopoly.game.server.PlayerColor; - /** * Represents a message indicating the player is ready to play. */ -public class PlayerReady extends ClientMessage{ - private boolean isReady; - private String name; - private PlayerColor color; +public class PlayerReady extends ClientMessage { + private final boolean isReady; + private final String name; + private final String figure; + private final int startMoney; /** * Constructs a PlayerReady message. * * @param isReady true if the player is ready, false otherwise + * @param name the name of the player + * @param color the color of the player (can be null) */ - public PlayerReady(boolean isReady) { + public PlayerReady(boolean isReady, String name, String figure, int startMoney) { this.isReady = isReady; + this.name = name; + this.figure = figure; + this.startMoney = startMoney; } - /** - * Getter for the Name - * @return the Name - */ public String getName() { return name; } - /** - * Getter for the Playercolor - * @return the Playercolor - */ - public PlayerColor getColor() { - return color; + public String getFigure() { + return figure; } - /** - * Checks if the player is ready. - * - * @return true if ready, false otherwise - */ public boolean isReady() { return isReady; } + public int getStartMoney() { + return startMoney; + } @Override public void accept(ClientInterpreter interpreter, int from) { diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/ViewAssetsRequest.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/ViewAssetsRequest.java index f78d778..afbdc79 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/ViewAssetsRequest.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/ViewAssetsRequest.java @@ -1,12 +1,25 @@ package pp.monopoly.message.client; + +import pp.monopoly.game.server.Player; + /** * Represents a request from a player to view their assets. */ public class ViewAssetsRequest extends ClientMessage{ + private final Player player; + + public ViewAssetsRequest(Player player) { + this.player = player; + } + @Override public void accept(ClientInterpreter interpreter, int from) { interpreter.received(this, from); } + public Player getPlayer() { + return player; + } + } \ No newline at end of file diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameStart.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameStart.java index bf39031..17679e5 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameStart.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameStart.java @@ -1,7 +1,19 @@ package pp.monopoly.message.server; +import pp.monopoly.game.server.PlayerHandler; + public class GameStart extends ServerMessage{ + private final PlayerHandler ph; + + public GameStart(PlayerHandler ph) { + this.ph = ph; + } + + public PlayerHandler getPlayerHandler() { + return ph; + } + @Override public void accept(ServerInterpreter interpreter) { interpreter.received(this); diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/NextPlayerTurn.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/NextPlayerTurn.java new file mode 100644 index 0000000..f047f90 --- /dev/null +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/NextPlayerTurn.java @@ -0,0 +1,28 @@ +package pp.monopoly.message.server; + +import pp.monopoly.game.server.Player; + +public class NextPlayerTurn extends ServerMessage{ + + private final Player player; + + public NextPlayerTurn(Player player) { + this.player = player; + } + + @Override + public void accept(ServerInterpreter interpreter) { + interpreter.received(this); + } + + @Override + public String getInfoTextKey() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'"); + } + + public Player getPlayer() { + return player; + } + +} diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ServerInterpreter.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ServerInterpreter.java index 1f78ba7..4817e2a 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ServerInterpreter.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ServerInterpreter.java @@ -89,4 +89,11 @@ public interface ServerInterpreter { * @param msg the TradeRequest message received */ void received(TradeRequest msg); + + /** + * Handles a NextPlayerTurn message received from the server. + * + * @param msg the NextPlayerTurn message received + */ + void received(NextPlayerTurn msg); } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ViewAssetsResponse.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ViewAssetsResponse.java index 9a00833..be75108 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ViewAssetsResponse.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ViewAssetsResponse.java @@ -2,13 +2,16 @@ package pp.monopoly.message.server; import java.util.List; +import pp.monopoly.model.fields.BoardManager; import pp.monopoly.model.fields.PropertyField; + /** * Represents a response containing the player's assets. */ public class ViewAssetsResponse extends ServerMessage{ private final List properties; + private final BoardManager board; private final int accountBalance; private final int jailCards; @@ -18,7 +21,8 @@ public class ViewAssetsResponse extends ServerMessage{ * @param properties a List of PropertyField objects representing the player's properties * @param accountBalance the player's current account balance */ - public ViewAssetsResponse(List properties, int accountBalance, int jailCards) { + public ViewAssetsResponse(BoardManager board, List properties, int accountBalance, int jailCards) { + this.board = board; this.properties = properties; this.accountBalance = accountBalance; this.jailCards = jailCards; @@ -47,4 +51,7 @@ public class ViewAssetsResponse extends ServerMessage{ return jailCards; } + public BoardManager getboard() { + return board; + } } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Board.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Board.java index 31ee634..e46308f 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Board.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Board.java @@ -57,7 +57,6 @@ public class Board { this.width = width; this.height = height; this.eventBroker = eventBroker; - addItem(new Figure(5, 5, 5, Rotation.LEFT)); } /** diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/CardVisitor.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/CardVisitor.java deleted file mode 100644 index 257f81f..0000000 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/CardVisitor.java +++ /dev/null @@ -1,7 +0,0 @@ -package pp.monopoly.model; - -import pp.monopoly.model.card.Card; - -public interface CardVisitor { - T visit(Card c); -} diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Figure.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Figure.java index d076acd..99e6ab9 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Figure.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Figure.java @@ -8,31 +8,11 @@ import static java.lang.Math.max; import static java.lang.Math.min; public class Figure implements Item{ - /** - * Enumeration representing the different statuses a Figure can have during the game. - */ - public enum Status { - /** - * The ship is in its normal state, not being previewed for placement. - */ - NORMAL, - - /** - * The ship is being previewed in a valid position for placement. - */ - VALID_PREVIEW, - - /** - * The ship is being previewed in an invalid position for placement. - */ - INVALID_PREVIEW - } - + private final String type; private final int length; // The length of the Figure private int x; // The x-coordinate of the Figure's position private int y; // The y-coordinate of the Figure's position private Rotation rot; // The rotation of the Figure - private Status status; // The current status of the Figure private final Set damaged = new HashSet<>(); // The set of positions that have been hit on this ship /** @@ -40,7 +20,7 @@ public class Figure implements Item{ * at position (0, 0), with a default rotation of RIGHT. */ private Figure() { - this(0, 0, 0, Rotation.RIGHT); + this(0, 0, 0, Rotation.RIGHT, "cube"); } /** @@ -51,12 +31,12 @@ public class Figure implements Item{ * @param y the y-coordinate of the Figure's initial position * @param rot the rotation of the Figure */ - public Figure(int length, int x, int y, Rotation rot) { + public Figure(int length, int x, int y, Rotation rot, String type) { this.x = x; this.y = y; this.rot = rot; this.length = length; - this.status = Status.NORMAL; + this.type = type; } /** @@ -87,7 +67,7 @@ public class Figure implements Item{ this.x = x; this.y = y; } - + /** * Moves the Figure to the specified position. * @@ -98,21 +78,46 @@ public class Figure implements Item{ } /** - * Returns the current status of the Figure. + * Moves the Figure to the specified coordinates. * - * @return the status of the Figure + * @param x the new x-coordinate of the Figure's position + * @param y the new y-coordinate of the Figure's position */ - public Status getStatus() { - return status; + public void moveTo(int fieldId) { + moveTo(fieldIdToPosition(fieldId)); } - /** - * Sets the status of the Figure. - * - * @param status the new status to be set for the Figure - */ - public void setStatus(Status status) { - this.status = status; + private IntPoint fieldIdToPosition(int fieldId) { + if (fieldId < 0 || fieldId > 39) { + throw new IllegalArgumentException("Invalid fieldId: " + fieldId); + } + + // Determine which edge and position along the edge + if (fieldId <= 9) { + // Bottom edge: From (-10, -10) to (10, -10) + int x = -10 + fieldId * 2; + return new IntPoint(x, -10); + } else if (fieldId <= 19) { + // Right edge: From (10, -10) to (10, 10) + int y = -10 + (fieldId - 10) * 2; + return new IntPoint(10, y); + } else if (fieldId <= 29) { + // Top edge: From (10, 10) to (-10, 10) + int x = 10 - (fieldId - 20) * 2; + return new IntPoint(x, 10); + } else { + // Left edge: From (-10, 10) to (-10, -10) + int y = 10 - (fieldId - 30) * 2; + return new IntPoint(-10, y); + } + } + + private Rotation fieldIdToRotation(int fieldId) { + if (fieldId >= 0 && fieldId <= 10) return Rotation.DOWN; + else if (fieldId <= 20) return Rotation.LEFT; + else if (fieldId <= 30) return Rotation.UP; + else if (fieldId <= 39) return Rotation.RIGHT; + else throw new IllegalArgumentException(); } /** diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/LimitedLinkedList.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/LimitedLinkedList.java new file mode 100644 index 0000000..5a0285e --- /dev/null +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/LimitedLinkedList.java @@ -0,0 +1,49 @@ +package pp.monopoly.model; + +import java.util.LinkedList; + +/** + * A LinkedList with a maximum size limit. + * + * @param the type of elements held in this collection + */ +public class LimitedLinkedList extends LinkedList { + + private final int maxSize; + + /** + * Constructs a LimitedLinkedList with the specified maximum size. + * + * @param maxSize the maximum number of elements this list can hold + */ + public LimitedLinkedList(int maxSize) { + if (maxSize <= 0) { + throw new IllegalArgumentException("Max size must be greater than 0"); + } + this.maxSize = maxSize; + } + + /** + * Adds an element to the list. If the list exceeds its maximum size, + * the oldest element (first) is removed. + * + * @param element the element to be added + * @return true if the element was added successfully + */ + @Override + public boolean add(E element) { + if (size() >= maxSize) { + return false; + } + return super.add(element); + } + + /** + * Gets the maximum size of this list. + * + * @return the maximum size + */ + public int getMaxSize() { + return maxSize; + } +} diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/TradeHandler.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/TradeHandler.java index fc1f65f..6f63d8e 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/TradeHandler.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/TradeHandler.java @@ -6,66 +6,112 @@ import pp.monopoly.model.fields.PropertyField; import java.util.List; /** - * Helper class that handles the trade logic between two players. - * Manages trade initiation, validation, acceptance, and rejection involving multiple properties, money, and jail cards. + * Handles a single trade between two players. + * Encapsulates trade details, validation, acceptance, and rejection. */ public class TradeHandler { + private final Player sender; + private final Player receiver; + private final int offeredAmount; + private final List offeredProperties; + private final int offeredJailCards; + private final int requestedAmount; + private final List requestedProperties; + private final int requestedJailCards; + private Boolean status = null; + /** - * Initiates a trade offer between two players involving properties, money, and jail cards. + * Constructs a TradeHandler for a single trade instance. * - * @param sender the Player who is initiating the trade - * @param receiver the Player who is the target of the trade offer - * @param offeredAmount the amount of money the sender offers - * @param offeredProperties the list of properties the sender offers - * @param offeredJailCards the number of jail cards the sender offers - * @param requestedAmount the amount of money the sender requests from the receiver - * @param requestedProperties the list of properties the sender requests from the receiver - * @param requestedJailCards the number of jail cards the sender requests from the receiver - * @return true if the trade offer is valid and initiated, false otherwise + * @param sender the Player initiating the trade + * @param receiver the Player receiving the trade offer + * @param offeredAmount the amount of money offered by the sender + * @param offeredProperties the properties offered by the sender + * @param offeredJailCards the jail cards offered by the sender + * @param requestedAmount the amount of money requested from the receiver + * @param requestedProperties the properties requested from the receiver + * @param requestedJailCards the jail cards requested from the receiver */ - public boolean initiateTrade(Player sender, Player receiver, int offeredAmount, List offeredProperties, - int offeredJailCards, int requestedAmount, List requestedProperties, int requestedJailCards) { - // Validate the trade offer - if (!validateTrade(sender, offeredAmount, offeredProperties, offeredJailCards, receiver, requestedAmount, requestedProperties, requestedJailCards)) { + public TradeHandler(Player sender, Player receiver, int offeredAmount, List offeredProperties, + int offeredJailCards, int requestedAmount, List requestedProperties, int requestedJailCards) { + this.sender = sender; + this.receiver = receiver; + this.offeredAmount = offeredAmount; + this.offeredProperties = offeredProperties; + this.offeredJailCards = offeredJailCards; + this.requestedAmount = requestedAmount; + this.requestedProperties = requestedProperties; + this.requestedJailCards = requestedJailCards; + } + + public int getOfferedAmount() { + return offeredAmount; + } + + public int getOfferedJailCards() { + return offeredJailCards; + } + + public List getOfferedProperties() { + return offeredProperties; + } + + public Player getReceiver() { + return receiver; + } + + public int getRequestedAmount() { + return requestedAmount; + } + + public int getRequestedJailCards() { + return requestedJailCards; + } + + public List getRequestedProperties() { + return requestedProperties; + } + + public Player getSender() { + return sender; + } + + public Boolean getStatus() { + return status; + } + + /** + * Initiates the trade and validates its terms. + * + * @return true if the trade is valid and can proceed, false otherwise + */ + public boolean initiateTrade() { + if (!validateTrade()) { System.out.println("Trade offer is invalid."); return false; } - - // Notify the receiver about the trade offer (this would be an actual message in a real implementation) - System.out.println("Trade offer initiated by " + sender.getName() + " to " + receiver.getName()); + System.out.println("Trade initiated by " + sender.getName() + " to " + receiver.getName()); return true; } /** - * Accepts the trade offer and completes the trade between two players. - * - * @param sender the Player who initiated the trade - * @param receiver the Player who accepted the trade - * @param offeredAmount the amount of money to transfer from the sender to the receiver - * @param offeredProperties the list of properties to transfer from the sender to the receiver - * @param offeredJailCards the number of jail cards to transfer from the sender to the receiver - * @param requestedAmount the amount of money to transfer from the receiver to the sender - * @param requestedProperties the list of properties to transfer from the receiver to the sender - * @param requestedJailCards the number of jail cards to transfer from the receiver to the sender + * Completes the trade by transferring money, properties, and jail cards. */ - public void acceptTrade(Player sender, Player receiver, int offeredAmount, List offeredProperties, - int offeredJailCards, int requestedAmount, List requestedProperties, int requestedJailCards) { + public void acceptTrade() { // Transfer money - sender.earnMoney(-offeredAmount); // Deduct money from the sender - receiver.earnMoney(offeredAmount); // Add money to the receiver + sender.earnMoney(-offeredAmount); + receiver.earnMoney(offeredAmount); - receiver.earnMoney(-requestedAmount); // Deduct money from the receiver - sender.earnMoney(requestedAmount); // Add money to the sender + receiver.earnMoney(-requestedAmount); + sender.earnMoney(requestedAmount); - // Transfer ownership of the properties from sender to receiver + // Transfer properties if (offeredProperties != null) { for (PropertyField property : offeredProperties) { transferProperty(sender, receiver, property); } } - - // Transfer ownership of the properties from receiver to sender if (requestedProperties != null) { for (PropertyField property : requestedProperties) { transferProperty(receiver, sender, property); @@ -76,73 +122,57 @@ public class TradeHandler { transferJailCards(sender, receiver, offeredJailCards); transferJailCards(receiver, sender, requestedJailCards); - System.out.println("Trade accepted. " + sender.getName() + " and " + receiver.getName() + " completed the trade."); + System.out.println("Trade completed between " + sender.getName() + " and " + receiver.getName()); } /** - * Rejects the trade offer. - * - * @param receiver the Player who is rejecting the trade + * Rejects the trade. */ - public void rejectTrade(Player receiver) { - System.out.println("Trade rejected by " + receiver.getName()); + public void rejectTrade() { + System.out.println(receiver.getName() + " rejected the trade."); } /** - * Validates a trade offer by checking if the sender and receiver own the properties involved, - * have sufficient funds for the money involved in the trade, and have enough jail cards. + * Validates the trade offer by checking ownership, balances, and jail cards. * - * @param sender the Player initiating the trade - * @param offeredAmount the amount of money the sender is offering - * @param offeredProperties the list of properties the sender is offering - * @param offeredJailCards the number of jail cards the sender is offering - * @param receiver the Player receiving the trade offer - * @param requestedAmount the amount of money the sender is requesting - * @param requestedProperties the list of properties the sender is requesting from the receiver - * @param requestedJailCards the number of jail cards the sender is requesting from the receiver - * @return true if the trade offer is valid, false otherwise + * @return true if the trade is valid, false otherwise */ - private boolean validateTrade(Player sender, int offeredAmount, List offeredProperties, int offeredJailCards, - Player receiver, int requestedAmount, List requestedProperties, int requestedJailCards) { - // Check if sender has enough money to offer + private boolean validateTrade() { + // Validate sender's ability to offer money if (sender.getAccountBalance() < offeredAmount) { - System.out.println("Sender does not have enough balance to make this offer."); + System.out.println("Sender does not have enough money to offer."); return false; } - // Check if receiver has enough money to offer + // Validate receiver's ability to fulfill the requested amount if (receiver.getAccountBalance() < requestedAmount) { - System.out.println("Receiver does not have enough balance to fulfill requested amount."); + System.out.println("Receiver does not have enough money to fulfill the request."); return false; } - // Check if sender owns all the offered properties + // Validate property ownership if (offeredProperties != null) { for (PropertyField property : offeredProperties) { if (!sender.getProperties().contains(property)) { - System.out.println("Sender does not own the property " + property.getName() + " being offered."); + System.out.println("Sender does not own property: " + property.getName()); return false; } } } - - // Check if receiver owns all the requested properties if (requestedProperties != null) { for (PropertyField property : requestedProperties) { if (!receiver.getProperties().contains(property)) { - System.out.println("Receiver does not own the property " + property.getName() + " requested."); + System.out.println("Receiver does not own property: " + property.getName()); return false; } } } - // Check if sender has enough jail cards to offer + // Validate jail cards if (sender.getNumJailCard() < offeredJailCards) { System.out.println("Sender does not have enough jail cards to offer."); return false; } - - // Check if receiver has enough jail cards to fulfill the request if (receiver.getNumJailCard() < requestedJailCards) { System.out.println("Receiver does not have enough jail cards to fulfill the request."); return false; @@ -152,17 +182,16 @@ public class TradeHandler { } /** - * Transfers a property from one player to another. + * Transfers a property between players. * - * @param from the Player transferring the property - * @param to the Player receiving the property + * @param from the Player transferring the property + * @param to the Player receiving the property * @param property the PropertyField being transferred */ private void transferProperty(Player from, Player to, PropertyField property) { from.sellProperty(property); to.buyProperty(property); - property.setOwner(to); // Update the property's owner - + property.setOwner(to); System.out.println("Property " + property.getName() + " transferred from " + from.getName() + " to " + to.getName()); } @@ -178,6 +207,6 @@ public class TradeHandler { from.removeJailCard(); to.addJailCard(); } - System.out.println("Transferred " + numCards + " jail card(s) from " + from.getName() + " to " + to.getName()); + System.out.println(numCards + " jail card(s) transferred from " + from.getName() + " to " + to.getName()); } } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/Card.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/Card.java index 95e07d1..8a25f5e 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/Card.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/Card.java @@ -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,8 +11,8 @@ 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() { diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/DeckHelper.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/DeckHelper.java index a270fd6..c967efd 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/DeckHelper.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/card/DeckHelper.java @@ -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{ +public class DeckHelper{ - private static Queue cards; + private Queue cards; + private List drawn = new ArrayList<>(); - private DeckHelper() { + public DeckHelper() { + cards = new LinkedList(); + 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 cardList = new ArrayList<>(cards); @@ -28,7 +321,13 @@ public class DeckHelper implements CardVisitor{ 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; } } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/BoardManager.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/BoardManager.java index 0cb7c0c..d3dafe8 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/BoardManager.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/BoardManager.java @@ -22,49 +22,49 @@ public class BoardManager { * Creates a Monopoly GameBoard * @return the List of Fields in correct Order */ - private static List createBoard() { + public static List createBoard() { ArrayList fields = new ArrayList<>(); fields.add(new GoField()); - fields.add(new BuildingProperty("Gym", 1, 600, 20)); + fields.add(new BuildingProperty("Gym", 1, 600, 20, 500, FieldColor.BROWN)); fields.add(new EventField("Hausfeier", 2)); - fields.add(new BuildingProperty("Sportplatz", 3, 600, 40)); + fields.add(new BuildingProperty("Sportplatz", 3, 600, 40, 500, FieldColor.BROWN)); fields.add(new FineField("Diszi", 4, 2000)); fields.add(new GateField("Südtor", 5)); - fields.add(new BuildingProperty("Studium+", 6, 1000, 60)); + fields.add(new BuildingProperty("Studium+", 6, 1000, 60, 500, FieldColor.BLUE_LIGHT)); fields.add(new EventField("Üvas", 7)); - fields.add(new BuildingProperty("PhysikHörsaal", 8, 1000, 60)); - fields.add(new BuildingProperty("Audimax", 9, 1200, 80)); + fields.add(new BuildingProperty("PhysikHörsaal", 8, 1000, 60, 500, FieldColor.BLUE_LIGHT)); + fields.add(new BuildingProperty("Audimax", 9, 1200, 80, 500, FieldColor.BLUE_LIGHT)); fields.add(new GulagField()); - fields.add(new BuildingProperty("99er", 11, 1400, 100)); + fields.add(new BuildingProperty("99er", 11, 1400, 100, 1000, FieldColor.PINK)); fields.add(new FoodField("Brandl", 12)); - fields.add(new BuildingProperty("12er", 13, 1400, 100)); - fields.add(new BuildingProperty("23er", 14, 1600, 120)); + fields.add(new BuildingProperty("12er", 13, 1400, 100, 1000, FieldColor.PINK)); + fields.add(new BuildingProperty("23er", 14, 1600, 120, 1000, FieldColor.PINK)); fields.add(new GateField("HauptWache", 15)); - fields.add(new BuildingProperty("Schwimmhalle", 16, 1800, 140)); - fields.add(new BuildingProperty("CISM-Bahn", 17, 1800, 140)); + fields.add(new BuildingProperty("Schwimmhalle", 16, 1800, 140, 1000, FieldColor.ORANGE)); + fields.add(new BuildingProperty("CISM-Bahn", 17, 1800, 140, 1000, FieldColor.ORANGE)); fields.add(new EventField("Marine-Welcome-Party", 18)); - fields.add(new BuildingProperty("Kletterturm", 19, 2000, 160)); + fields.add(new BuildingProperty("Kletterturm", 19, 2000, 160, 1000, FieldColor.ORANGE)); fields.add(new TestStreckeField()); - fields.add(new BuildingProperty("StudFBer C", 21, 2200, 180)); + fields.add(new BuildingProperty("StudFBer C", 21, 2200, 180, 1500, FieldColor.RED)); fields.add(new EventField("Üvas", 22)); - fields.add(new BuildingProperty("StudFBer B", 23, 2200, 180)); - fields.add(new BuildingProperty("StudFBer A", 24, 2400, 200)); + fields.add(new BuildingProperty("StudFBer B", 23, 2200, 180, 1500, FieldColor.RED)); + fields.add(new BuildingProperty("StudFBer A", 24, 2400, 200, 1500, FieldColor.RED)); fields.add(new GateField("Nordtor", 25)); - fields.add(new BuildingProperty("Cascada", 26, 2600, 220)); - fields.add(new BuildingProperty("Fakultätsgebäude", 27, 2600, 220)); + fields.add(new BuildingProperty("Cascada", 26, 2600, 220, 1500, FieldColor.YELLOW)); + fields.add(new BuildingProperty("Fakultätsgebäude", 27, 2600, 220, 1500, FieldColor.YELLOW)); fields.add(new FoodField("Truppenküche", 28)); - fields.add(new BuildingProperty("Prüfungsamt", 29, 2800, 240)); + fields.add(new BuildingProperty("Prüfungsamt", 29, 2800, 240, 1500, FieldColor.YELLOW)); fields.add(new WacheField()); - fields.add(new BuildingProperty("Feuerwehr", 31, 3000, 260)); - fields.add(new BuildingProperty("SanZ", 32, 300, 260)); + fields.add(new BuildingProperty("Feuerwehr", 31, 3000, 260, 2000, FieldColor.GREEN)); + fields.add(new BuildingProperty("SanZ", 32, 300, 260, 2000, FieldColor.GREEN)); fields.add(new EventField("Maibock", 33)); - fields.add(new BuildingProperty("Rechenzentrum", 34, 3200, 280)); + fields.add(new BuildingProperty("Rechenzentrum", 34, 3200, 280, 2000, FieldColor.GREEN)); fields.add(new GateField("Osttor", 35)); fields.add(new EventField("Üvas", 36)); - fields.add(new BuildingProperty("2er", 37, 3500, 350)); + fields.add(new BuildingProperty("2er", 37, 3500, 350, 2000, FieldColor.BLUE_DARK)); fields.add(new FineField("EZM", 38, 1000)); - fields.add(new BuildingProperty("20er", 39, 4000, 500)); + fields.add(new BuildingProperty("20er", 39, 4000, 500, 2000, FieldColor.BLUE_DARK)); return fields; } @@ -88,4 +88,8 @@ public class BoardManager { if (board.contains(field)) return field.getId(); else throw new NoSuchElementException(); } + + public List getBoard() { + return board; + } } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/BuildingProperty.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/BuildingProperty.java index ae73cb8..118d0ed 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/BuildingProperty.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/BuildingProperty.java @@ -1,30 +1,42 @@ package pp.monopoly.model.fields; +import java.util.ArrayList; +import java.util.List; + import pp.monopoly.game.server.Player; public class BuildingProperty extends PropertyField { private int houses; private boolean hotel = false; + private final int housePrice; + private final FieldColor color; + private final int rentFactor1 = 5; + private final int rentFactor2 = 15; + private final int rentFactor3 = 40; + private final int rentFactor4 = 55; + private final int rentFactorHotel = 70; - BuildingProperty(String name, int id, int price, int rent) { + BuildingProperty(String name, int id, int price, int rent, int housePrice, FieldColor color) { super(name, id, price, rent); + this.housePrice = housePrice; + this.color = color; } @Override public int calcRent() { if (hotel) { - return (int) Math.round(rent*70/10)*10; + return (int) Math.round(rent*rentFactorHotel/10)*10; } switch (houses) { case 1: - return (int) Math.round(rent*5/10)*10; + return (int) Math.round(rent*rentFactor1/10)*10; case 2: - return (int) Math.round(rent*15/10)*10; + return (int) Math.round(rent*rentFactor2/10)*10; case 3: - return (int) Math.round(rent*40/10)*10; + return (int) Math.round(rent*rentFactor3/10)*10; case 4: - return (int) Math.round(rent*55/10)*10; + return (int) Math.round(rent*rentFactor4/10)*10; default: return rent; @@ -67,4 +79,31 @@ public class BuildingProperty extends PropertyField { public void accept(Player player) { player.visit(this); } + + public List getAllRent() { + List list = new ArrayList<>(); + list.add(rent); + list.add((int) Math.round(rent*rentFactor1/10)*10); + list.add((int) Math.round(rent*rentFactor2/10)*10); + list.add((int) Math.round(rent*rentFactor3/10)*10); + list.add((int) Math.round(rent*rentFactor4/10)*10); + list.add((int) Math.round(rent*rentFactorHotel/10)*10); + return list; + } + + public FieldColor getColor() { + return color; + } + + public int getHousePrice() { + return housePrice; + } + + public int getHouses() { + return houses; + } + + public int getHotel() { + return hotel ? 1:0; + } } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/EventField.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/EventField.java index fc2ca57..cad2dde 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/EventField.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/EventField.java @@ -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(); - } - } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/FieldColor.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/FieldColor.java new file mode 100644 index 0000000..f0a9bd0 --- /dev/null +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/FieldColor.java @@ -0,0 +1,37 @@ +package pp.monopoly.model.fields; + +import com.jme3.math.ColorRGBA; + +/** + * Enum representing eight distinct colors for properties in the game. + */ +public enum FieldColor { + BROWN(new ColorRGBA(148 / 255f, 86 / 255f, 57 / 255f, 1)), + GREEN(new ColorRGBA(30 / 255f, 179 / 255f, 90 / 255f, 1)), + YELLOW(new ColorRGBA(252 / 255f, 241 / 255f, 1 / 255f, 1)), + BLUE_LIGHT(new ColorRGBA(170 / 255f, 223 / 255f, 246 / 255f, 1)), + PINK(new ColorRGBA(214 / 255f, 60 / 255f, 153 / 255f, 1)), + ORANGE(new ColorRGBA(244 / 255f, 147 / 255f, 32 / 255f, 1)), + RED(new ColorRGBA(232 / 255f, 27 / 255f, 30 / 255f, 1)), + BLUE_DARK(new ColorRGBA(2 / 255f, 112 / 255f, 191 / 255f, 1)); + + private final ColorRGBA color; + + /** + * Constructs a FieldColor with the specified ColorRGBA value. + * + * @param color the ColorRGBA value associated with the field color + */ + FieldColor(ColorRGBA color) { + this.color = color; + } + + /** + * Gets the ColorRGBA value of the field color. + * + * @return the ColorRGBA value + */ + public ColorRGBA getColor() { + return color; + } +} diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/GulagField.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/GulagField.java index 172a1f4..08c3a2c 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/GulagField.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/GulagField.java @@ -15,4 +15,8 @@ public class GulagField extends Field{ player.visit(this); } + public int getBailCost() { + return bailCost; + } + } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/TestStreckeField.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/TestStreckeField.java index 89da7dc..1ea6ae7 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/TestStreckeField.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/fields/TestStreckeField.java @@ -19,6 +19,8 @@ public class TestStreckeField extends Field{ } public int collectMoney() { - return money = 0; + int tmp = money; + money = 0; + return tmp; } } diff --git a/Projekte/monopoly/server/server.properties b/Projekte/monopoly/server/server.properties index 2439842..53a2737 100644 --- a/Projekte/monopoly/server/server.properties +++ b/Projekte/monopoly/server/server.properties @@ -10,5 +10,5 @@ # This file defines the configuration settings for the Battleship server. # # The port number on which the server will listen for incoming connections. -port=1234 +port=42069 diff --git a/Projekte/monopoly/server/src/main/java/pp/monopoly/server/MonopolyServer.java b/Projekte/monopoly/server/src/main/java/pp/monopoly/server/MonopolyServer.java index f02f48d..f4bfa7e 100644 --- a/Projekte/monopoly/server/src/main/java/pp/monopoly/server/MonopolyServer.java +++ b/Projekte/monopoly/server/src/main/java/pp/monopoly/server/MonopolyServer.java @@ -7,21 +7,6 @@ package pp.monopoly.server; -import com.jme3.network.ConnectionListener; -import com.jme3.network.HostedConnection; -import com.jme3.network.Message; -import com.jme3.network.MessageListener; -import com.jme3.network.Network; -import com.jme3.network.Server; -import com.jme3.network.serializing.Serializer; -import pp.monopoly.MonopolyConfig; -import pp.monopoly.game.server.Player; -import pp.monopoly.game.server.ServerGameLogic; -import pp.monopoly.game.server.ServerSender; -import pp.monopoly.message.client.ClientMessage; -import pp.monopoly.message.server.ServerMessage; -import pp.monopoly.model.IntPoint; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -31,6 +16,22 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.LogManager; +import com.jme3.network.ConnectionListener; +import com.jme3.network.HostedConnection; +import com.jme3.network.Message; +import com.jme3.network.MessageListener; +import com.jme3.network.Network; +import com.jme3.network.Server; +import com.jme3.network.serializing.Serializer; + +import pp.monopoly.MonopolyConfig; +import pp.monopoly.game.server.Player; +import pp.monopoly.game.server.ServerGameLogic; +import pp.monopoly.game.server.ServerSender; +import pp.monopoly.message.client.ClientMessage; +import pp.monopoly.message.server.ServerMessage; +import pp.monopoly.model.IntPoint; + /** * Server implementing the visitor pattern as MessageReceiver for ClientMessages */ @@ -119,8 +120,9 @@ public class MonopolyServer implements MessageListener, Connec @Override public void connectionAdded(Server server, HostedConnection hostedConnection) { - LOGGER.log(Level.INFO, "new connection {0}", hostedConnection); //NON-NLS + LOGGER.log(Level.INFO, "New connection established: {0}", hostedConnection); //NON-NLS logic.addPlayer(hostedConnection.getId()); + System.out.println("Spieler verbunden: ID = " + hostedConnection.getId()); } @Override diff --git a/Projekte/settings.gradle b/Projekte/settings.gradle index 92a7ec5..928fed6 100644 --- a/Projekte/settings.gradle +++ b/Projekte/settings.gradle @@ -25,7 +25,9 @@ dependencyResolutionManagement { library('jme3-effects', 'org.jmonkeyengine', 'jme3-effects').versionRef('jme') library('lemur', 'com.simsilica:lemur:1.16.0') - library('lemur-proto', 'com.simsilica:lemur-proto:1.13.0') + library('lemurproto', 'com.simsilica:lemur-proto:1.13.0') + + library('selenium', 'org.seleniumhq.selenium:selenium-java:4.11.0') library('junit4', 'junit:junit:4.13.2') library('gson', 'com.google.code.gson:gson:2.11.0')