70 Commits

Author SHA1 Message Date
Johannes Schmelz
4ecccc5951 Merge branch 'gui' into 'connect'
# Conflicts:
#   Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java
#   Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/LobbyMenu.java
#   Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuildingPropertyCard.java
#   Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuyCard.java
#   Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/FoodFieldCard.java
#   Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/GateFieldCard.java
#   Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/WinnerPopUp.java
#   Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ClientGameLogic.java
2024-11-25 02:45:02 +00:00
Johannes Schmelz
f90ce5aa81 all button sounds now 2024-11-25 03:35:32 +01:00
Yvonne Schmidt
4a9eba255b restyled selector 2024-11-25 03:24:00 +01:00
Johannes Schmelz
4713a526b3 Merge branch 'connect' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into connect 2024-11-25 03:08:01 +01:00
Johannes Schmelz
362c0e5679 added serialisables 2024-11-25 03:07:57 +01:00
Yvonne Schmidt
fab2457715 added header to CreateGameMenu 2024-11-25 02:51:43 +01:00
Yvonne Schmidt
7b3f31f099 Merge remote-tracking branch 'origin/connect' into connect
# Conflicts:
#	Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java
2024-11-25 02:48:26 +01:00
Johannes Schmelz
ed105f1b70 cleanup 2024-11-25 02:43:58 +01:00
Yvonne Schmidt
cd4331aee3 added header to CreateGameMenu 2024-11-25 02:43:08 +01:00
Yvonne Schmidt
acc797f2ff Merge remote-tracking branch 'origin/connect' into connect 2024-11-25 02:12:01 +01:00
Yvonne Schmidt
853c32a5b8 fixed Buttons 2024-11-25 02:11:05 +01:00
Johannes Schmelz
72bef7143a serialize messages 2024-11-25 02:05:56 +01:00
Yvonne Schmidt
b1ed571950 added background to CreateGameMenu 2024-11-25 02:01:38 +01:00
Johannes Schmelz
1a75d6d6a8 buttons now work as intended 2024-11-25 01:51:27 +01:00
Yvonne Schmidt
c990e7b562 added button sounds 2024-11-25 01:50:52 +01:00
Johannes Schmelz
c87406f60e fixed esc menu 2024-11-25 00:52:10 +01:00
Johannes Schmelz
21914a1294 fixed startmenu 2024-11-25 00:33:05 +01:00
Johannes Schmelz
a344145732 fixed sounds 2024-11-25 00:28:42 +01:00
Yvonne Schmidt
a27ac31086 Merge remote-tracking branch 'origin/connect' into connect 2024-11-25 00:24:43 +01:00
Yvonne Schmidt
9a7f75b76b added effect sound slider 2024-11-25 00:24:25 +01:00
Simon Wilkening
687d1621fc EventCard erweitert 2024-11-25 00:06:12 +01:00
Johannes Schmelz
a6944aa6e3 added dice images 2024-11-24 23:38:22 +01:00
Johannes Schmelz
3e487c00d5 accidentally deleted volumeSlider 2024-11-24 23:29:59 +01:00
Johannes Schmelz
4820b8cf46 added looser popup 2024-11-24 23:28:04 +01:00
Johannes Schmelz
caa4cb5262 winner popup 2024-11-24 23:23:56 +01:00
Johannes Schmelz
b8365c76a1 fix mac executable 2024-11-24 22:58:47 +01:00
Johannes Schmelz
19216cc174 refactor 2024-11-24 22:57:19 +01:00
Johannes Schmelz
c6a23b9b8e execute for apple 2024-11-24 22:56:52 +01:00
Johannes Schmelz
c0f42fb1eb refactor 2024-11-24 22:50:52 +01:00
Tamino Mueller
160873e2cc added pictures and popups fixed 2024-11-24 22:42:32 +01:00
Johannes Schmelz
1b2a7d73b5 extend dialog 2024-11-24 22:41:53 +01:00
Tamino Mueller
8df859bbef Merge remote-tracking branch 'origin/gui' into gui 2024-11-24 22:34:54 +01:00
Tamino Mueller
e30d10a85d Pop-Up hinzugefügt 2024-11-24 22:34:19 +01:00
Johannes Schmelz
55778dbcea removed the buttons on start 2024-11-24 22:29:19 +01:00
Johannes Schmelz
422faec281 send player ready 2024-11-24 22:06:19 +01:00
Johannes Schmelz
dcf10e0819 automatically join lobby when selfhosting 2024-11-24 21:36:03 +01:00
Johannes Schmelz
6b78733a5d fixed server join 2024-11-24 21:30:18 +01:00
Johannes Schmelz
c124a99901 fixed screen size 2024-11-24 21:29:41 +01:00
Johannes Schmelz
d7df4002da lobby menu 2024-11-24 21:01:57 +01:00
Johannes Schmelz
8b0ef97a82 connect menu cow working 2024-11-24 20:52:29 +01:00
Johannes Schmelz
75d3bef5c8 move start menu 2024-11-24 20:42:07 +01:00
Yvonne Schmidt
bafc3f1db6 Merge remote-tracking branch 'origin/gui' into gui 2024-11-24 19:25:12 +01:00
Yvonne Schmidt
03571fcf74 code cleanup in der lobby 2024-11-24 19:24:51 +01:00
Johannes Schmelz
e7a6802488 fixed buyProperty 2024-11-24 19:14:56 +01:00
Johannes Schmelz
c2d5611ab9 changed settings menu to match 2024-11-24 19:10:59 +01:00
Yvonne Schmidt
a6e6b5e158 lobby übergibt figur 2024-11-24 19:05:28 +01:00
Simon Wilkening
74c3d925e6 TODOs und Kommentare ergänst 2024-11-24 19:04:58 +01:00
Johannes Schmelz
fb28f3fefc tmp settings menu fix 2024-11-24 19:02:56 +01:00
Yvonne Schmidt
f67fa4d7f0 lobby übergibt namen 2024-11-24 18:39:32 +01:00
Johannes Schmelz
6a34dab00c changed app to match battleship 2024-11-24 18:27:41 +01:00
Simon Wilkening
225a8c0e08 BuildingPropertyCard adjusted 2024-11-24 18:11:42 +01:00
Yvonne Schmidt
9a6ce27fe1 lobby uebergibt farbe und startgeld 2024-11-24 18:07:39 +01:00
Johannes Schmelz
c7bd7d18b7 removed bodged server connection 2024-11-24 18:03:22 +01:00
Johannes Schmelz
437114704a get client id 2024-11-24 17:20:35 +01:00
Johannes Schmelz
9b4cac4e56 send PlayerHandler when starting game 2024-11-24 16:51:00 +01:00
Johannes Schmelz
e780513b35 saving the players 2024-11-24 00:32:16 +01:00
Johannes Schmelz
d582c59a7d added playerState changes 2024-11-24 00:29:48 +01:00
Johannes Schmelz
7d2c85f617 fixed card bug 2024-11-24 00:13:32 +01:00
Johannes Schmelz
4a882bc4ac Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-24 00:11:18 +01:00
Johannes Schmelz
3c4eac1fcd added logic for visiting event field 2024-11-24 00:11:14 +01:00
Yvonne Schmidt
75d5a15bdb defaultwerte in die Lobby eingefügt 2024-11-23 23:19:53 +01:00
Yvonne Schmidt
17f121f7d1 Merge remote-tracking branch 'origin/gui' into gui 2024-11-23 23:15:04 +01:00
Johannes Schmelz
a66c570b51 remove 2d map view 2024-11-23 23:09:02 +01:00
Yvonne Schmidt
e1e7f2eaf6 überschneidungen von elementen beseitigt 2024-11-23 23:07:42 +01:00
Johannes Schmelz
46d2dce372 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-11-23 22:12:39 +01:00
Johannes Schmelz
c39f1f6d4c tweaked camera params 2024-11-23 22:12:34 +01:00
Yvonne Schmidt
738b04f2d9 oberfläche der lobby fertig 2024-11-23 21:29:14 +01:00
Simon Wilkening
ecba1c3135 GateField korrigiert 2024-11-23 21:22:54 +01:00
Johannes Schmelz
748226f4ed added Move Camera based on player position 2024-11-23 19:27:04 +01:00
Johannes Schmelz
f658f53ba9 refactor 2024-11-23 19:26:36 +01:00
72 changed files with 2148 additions and 1204 deletions

View File

@@ -0,0 +1,18 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="MonopolyApp (Mac)" type="Application" factoryName="Application"
singleton="false">
<option name="MAIN_CLASS_NAME" value="pp.monopoly.client.MonopolyApp"/>
<module name="Projekte.monopoly.client.main"/>
<option name="VM_PARAMETERS" value="-XstartOnFirstThread"/>
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$"/>
<extension name="coverage">
<pattern>
<option name="PATTERN" value="pp.monopoly.client.*"/>
<option name="ENABLED" value="true"/>
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true"/>
</method>
</configuration>
</component>

View File

@@ -18,10 +18,11 @@ import com.simsilica.lemur.style.ElementId;
import static pp.battleship.Resources.lookup; import static pp.battleship.Resources.lookup;
import pp.battleship.client.gui.GameMusic; import pp.battleship.client.gui.GameMusic;
import pp.battleship.client.gui.VolumeSlider;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.dialog.StateCheckboxModel; import pp.dialog.StateCheckboxModel;
import pp.dialog.TextInputDialog; import pp.dialog.TextInputDialog;
import pp.battleship.client.gui.VolumeSlider;
import static pp.util.PreferencesUtils.getPreferences; import static pp.util.PreferencesUtils.getPreferences;
/** /**

View File

@@ -1,6 +1,7 @@
package pp.battleship.client.gui; package pp.battleship.client.gui;
import com.simsilica.lemur.Slider; import com.simsilica.lemur.Slider;
/** /**
* The VolumeSlider class represents the Volume Slider in the Menu. * The VolumeSlider class represents the Volume Slider in the Menu.
* It extends the Slider class and provides functionalities for setting the music volume, * It extends the Slider class and provides functionalities for setting the music volume,

View File

@@ -21,9 +21,11 @@ def sliderColor = color(0.6, 0.8, 0.8, 1)
def sliderBgColor = color(0.5, 0.75, 0.75, 1) def sliderBgColor = color(0.5, 0.75, 0.75, 1)
def gradientColor = color(0.5, 0.75, 0.85, 0.5) def gradientColor = color(0.5, 0.75, 0.85, 0.5)
def tabbuttonEnabledColor = color(0.4, 0.45, 0.5, 1) def tabbuttonEnabledColor = color(0.4, 0.45, 0.5, 1)
def solidWhiteBackground = new QuadBackgroundComponent(color(1, 1, 1, 1)) // Solid white def solidWhiteBackground = new QuadBackgroundComponent(new ColorRGBA(1, 1, 1, 1))
def greyBackground = color(0.8, 0.8, 0.8, 1) // Grey background color def greyBackground = new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 1.0f));
def redBorderColor = color(1, 0, 0, 1) // Red border color def lightGreyBackground = new QuadBackgroundComponent(new ColorRGBA(0.4f, 0.4f, 0.4f, 1.0f));
def lightGrey = color(0.6, 0.6, 0.6, 1.0)
@@ -246,7 +248,12 @@ selector("tab.button", "pp") {
buttonCommands = stdButtonCommands buttonCommands = stdButtonCommands
} }
selector("settings-title", "pp") { selector("settings-title", "pp") {
fontSize = 48 // Set font size def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Grey inner border
def innerBackground = new QuadBackgroundComponent(buttonBgColor) // White outer border background
background = outerBackground
fontSize = 40
insets = new Insets3f(3, 3, 3, 3)
textHAlignment = HAlignment.Center textHAlignment = HAlignment.Center
textVAlignment = VAlignment.Center textVAlignment = VAlignment.Center
} }

View File

@@ -5,47 +5,13 @@
## (c) Mark Minas (mark.minas@unibw.de) ## (c) Mark Minas (mark.minas@unibw.de)
######################################## ########################################
# #
# Battleship client configuration # Monopoly client configuration
#
# Specifies the map used by the opponent in single mode.
# Single mode is activated if this property is set.
#map.opponent=maps/map2.json
#
# Specifies the map used by the player in single mode.
# The player must define their own map if this property is not set.
map.own=maps/map1.json
#
# Coordinates of the shots fired by the RobotClient in the order listed.
# Example:
# 2, 0,\
# 2, 1,\
# 2, 2,\
# 2, 3
# defines four shots, namely at the coordinates
# (x=2, y=0), (x=2, y=1), (x=2, y=2), and (x=2, y=3)
robot.targets=2, 0,\
2, 1,\
2, 2,\
2, 3
#
# Delay in milliseconds between each shot fired by the RobotClient.
robot.delay=500
# #
# The dimensions of the game map used in single mode. # 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' defines the number of columns, and 'map.height' defines the number of rows.
map.width=10 map.width=10
map.height=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 # Screen settings
# #

View File

@@ -30,6 +30,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
private static final Logger LOGGER = System.getLogger(GameSound.class.getName()); private static final Logger LOGGER = System.getLogger(GameSound.class.getName());
private static final Preferences PREFERENCES = getPreferences(GameSound.class); private static final Preferences PREFERENCES = getPreferences(GameSound.class);
private static final String ENABLED_PREF = "enabled"; //NON-NLS private static final String ENABLED_PREF = "enabled"; //NON-NLS
private static final String VOLUME_PREF = "volume"; //NON-NLS
private AudioNode passStartSound; private AudioNode passStartSound;
private AudioNode eventCardSound; private AudioNode eventCardSound;
@@ -59,6 +60,15 @@ public class GameSound extends AbstractAppState implements GameEventListener {
setEnabled(!isEnabled()); setEnabled(!isEnabled());
} }
/**
* Checks if sound is enabled in the preferences.
*
* @return float to which the volume is set
*/
public static float volumeInPreferences() {
return PREFERENCES.getFloat(VOLUME_PREF, 0.5f);
}
/** /**
* Sets the enabled state of this AppState. * Sets the enabled state of this AppState.
* Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)} * Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)}
@@ -92,7 +102,7 @@ public class GameSound extends AbstractAppState implements GameEventListener {
tradeAcceptedSound = loadSound(app, "Sound/Effects/tradeAccepted.ogg"); tradeAcceptedSound = loadSound(app, "Sound/Effects/tradeAccepted.ogg");
tradeRejectedSound = loadSound(app, "Sound/Effects/tradeRejected.ogg"); tradeRejectedSound = loadSound(app, "Sound/Effects/tradeRejected.ogg");
winnerSound = loadSound(app, "Sound/Effects/winner.ogg"); winnerSound = loadSound(app, "Sound/Effects/winner.ogg");
looserSound = loadSound(app, "Sound/Effects/looser.ogg"); looserSound = loadSound(app, "Sound/Effects/loser.ogg");
buttonSound = loadSound(app, "Sound/Effects/button.ogg"); buttonSound = loadSound(app, "Sound/Effects/button.ogg");
} }
@@ -193,21 +203,40 @@ public class GameSound extends AbstractAppState implements GameEventListener {
if (isEnabled() && buttonSound != null) if (isEnabled() && buttonSound != null)
buttonSound.playInstance(); buttonSound.playInstance();
} }
/**
* Sets the volume of the sounds
* @param vol the volume to which the sounds should be set
*/
public void setVolume(float vol){
passStartSound.setVolume(vol);
eventCardSound.setVolume(vol);
gulagSound.setVolume(vol);
diceRollSound.setVolume(vol);
moneyCollectSound.setVolume(vol);
moneyLostSound.setVolume(vol);
tradeAcceptedSound.setVolume(vol);
tradeRejectedSound.setVolume(vol);
winnerSound.setVolume(vol);
looserSound.setVolume(vol);
buttonSound.setVolume(vol);
PREFERENCES.putFloat(VOLUME_PREF, vol);
}
@Override @Override
public void receivedEvent(SoundEvent event) { public void receivedEvent(SoundEvent event) {
switch (event.sound()) { switch (event.sound()) {
case PASS_START -> passStart(); case PASS_START -> passStart();
case EVENT_CARD -> eventCard(); case EVENT_CARD -> eventCard();
case GULAG -> eventCard(); case GULAG -> gulag();
case DICE_ROLL -> eventCard(); case DICE_ROLL -> diceRoll();
case MONEY_COLLECTED -> eventCard(); case MONEY_COLLECTED -> moneyCollect();
case MONEY_LOST -> eventCard(); case MONEY_LOST -> moneyLost();
case TRADE_ACCEPTED -> eventCard(); case TRADE_ACCEPTED -> tradeAccepted();
case TRADE_REJECTED -> eventCard(); case TRADE_REJECTED -> tradeRejected();
case WINNER -> eventCard(); case WINNER -> winner();
case LOSER -> eventCard(); case LOSER -> looser();
case BUTTON -> eventCard(); case BUTTON -> button();
} }
} }
} }

View File

@@ -1,51 +0,0 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client;
import java.util.prefs.Preferences;
import pp.dialog.Dialog;
import static pp.util.PreferencesUtils.getPreferences;
/**
* The Menu class represents the main menu in the Battleship game application.
* It extends the Dialog class and provides functionalities for loading, saving,
* returning to the game, and quitting the application.
*/
class Menu extends Dialog {
private static final Preferences PREFERENCES = getPreferences(Menu.class);
private static final String LAST_PATH = "last.file.path";
private final MonopolyApp app;
/**
* Constructs the Menu dialog for the Battleship application.
*
* @param app the BattleshipApp instance
*/
public Menu(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
}
/**
* Updates the state of the load and save buttons based on the game logic.
*/
@Override
public void update() {
}
/**
* As an escape action, this method closes the menu if it is the top dialog.
*/
@Override
public void escape() {
close();
}
}

View File

@@ -1,290 +1,446 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client; package pp.monopoly.client;
import java.util.concurrent.ExecutorService; import com.jme3.app.DebugKeysAppState;
import java.util.concurrent.Executors;
import com.jme3.app.SimpleApplication; import com.jme3.app.SimpleApplication;
import com.jme3.app.StatsAppState;
import com.jme3.font.BitmapFont; import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText; import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput; import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener; import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger; import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.system.AppSettings; import com.jme3.system.AppSettings;
import com.simsilica.lemur.GuiGlobals; import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.style.BaseStyles; import com.simsilica.lemur.style.BaseStyles;
import pp.monopoly.game.client.MonopolyClient;
import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.client.gui.StartMenu;
import pp.monopoly.game.client.ClientGameLogic;
import pp.monopoly.game.client.ServerConnection;
import pp.monopoly.notification.ClientStateEvent;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent;
import pp.monopoly.notification.Sound;
import pp.dialog.DialogBuilder; import pp.dialog.DialogBuilder;
import pp.dialog.DialogManager; import pp.dialog.DialogManager;
import pp.graphics.Draw; import pp.graphics.Draw;
import pp.monopoly.client.gui.*;
import pp.monopoly.client.gui.popups.BuildingPropertyCard;
import pp.monopoly.client.gui.popups.BuyCard;
import pp.monopoly.client.gui.popups.FoodFieldCard;
import pp.monopoly.client.gui.popups.GateFieldCard;
import pp.monopoly.game.client.ClientGameLogic;
import pp.monopoly.game.client.MonopolyClient;
import pp.monopoly.game.client.ServerConnection;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent;
import pp.monopoly.server.MonopolyServer;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.LogManager;
import static pp.monopoly.Resources.lookup;
/**
* The main class for the Battleship client application.
* It manages the initialization, input setup, GUI setup, and game states for the client.
*/
public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener { public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener {
private BitmapText topText; /**
private final ServerConnection serverConnection; * Logger for logging messages within the application.
private final ClientGameLogic logic; */
private final MonopolyAppConfig config; private static final Logger LOGGER = System.getLogger(MonopolyApp.class.getName());
private final ActionListener escapeListener = (name, isPressed, tpf) -> handleEscape(isPressed);
private final DialogManager dialogManager = new DialogManager(this);
private final ExecutorService executor = Executors.newCachedThreadPool();
private final Draw draw;
private SettingsMenu settingsMenu;
private TestWorld testWorld;
private boolean isSettingsMenuOpen = false;
private boolean inputBlocked = false;
private MonopolyServer monopolyServer;
private NetworkSupport networkSupport;
private BoardManager boardManager = new BoardManager();
// TODO Temp später entfernen
private BuildingPropertyCard buildingProperty;
private FoodFieldCard foodField;
private GateFieldCard gateField;
private BuyCard buyCard;
private boolean isBuyCardPopupOpen = false;
private final ActionListener BListener = (name, isPressed, tpf) -> handleB(isPressed);
/** /**
* Path to the styles script for GUI elements. * 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. * Path to the font resource used in the GUI.
*/ */
private static final String FONT = "Interface/Fonts/Default.fnt"; // NON-NLS private static final String FONT = "Interface/Fonts/Default.fnt"; //NON-NLS
/**
* Path to the client configuration file, if one exists.
*/
private static final File CONFIG_FILE = new File("client.properties");
/**
* Input mapping name for mouse clicks.
*/
public static final String CLICK = "CLICK";
/**
* Input mapping name for the Escape key.
*/
private static final String ESC = "ESC";
/**
* Manager for handling dialogs within the application.
*/
private final DialogManager dialogManager = new DialogManager(this);
/**
* The server connection instance, used for communicating with the game server.
*/
private final ServerConnection serverConnection;
/**
* Instance of the {@link Draw} class for rendering graphics.
*/
private Draw draw;
/**
* Text display at the top of the GUI for showing information to the user.
*/
private BitmapText topText;
/**
* Executor service for handling asynchronous tasks within the application.
*/
private ExecutorService executor;
/**
* Handler for managing the client's game logic.
*/
private final ClientGameLogic logic;
/**
* Configuration settings for the Battleship client application.
*/
private final MonopolyAppConfig config;
/**
* Listener for handling actions triggered by the Escape key.
*/
private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
static {
// Configure logging
LogManager manager = LogManager.getLogManager();
try {
manager.readConfiguration(new FileInputStream("logging.properties"));
LOGGER.log(Level.INFO, "Successfully read logging properties"); //NON-NLS
}
catch (IOException e) {
LOGGER.log(Level.INFO, e.getMessage());
}
}
/**
* Starts the Battleship application.
*
* @param args Command-line arguments for launching the application.
*/
public static void main(String[] args) { public static void main(String[] args) {
new MonopolyApp().start(); new MonopolyApp().start();
} }
public MonopolyApp() { /**
this.draw = new Draw(assetManager); * Constructs a new {@code MonopolyApp} instance.
* Initializes the configuration, server connection, and game logic listeners.
*/
private MonopolyApp() {
config = new MonopolyAppConfig(); config = new MonopolyAppConfig();
networkSupport = new NetworkSupport(this); // Initialize NetworkSupport config.readFromIfExists(CONFIG_FILE);
serverConnection = networkSupport; serverConnection = makeServerConnection();
logic = new ClientGameLogic(serverConnection); logic = new ClientGameLogic(serverConnection);
logic.addListener(this); logic.addListener(this);
setShowSettings(config.getShowSettings()); setShowSettings(config.getShowSettings());
setSettings(makeSettings()); setSettings(makeSettings());
} }
@Override /**
public MonopolyAppConfig getConfig() { * Creates and configures application settings from the client configuration.
return config; *
* @return A configured {@link AppSettings} object.
*/
private AppSettings makeSettings() {
final AppSettings settings = new AppSettings(true);
settings.setTitle(lookup("monopoly.name"));
settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight());
settings.setFullscreen(config.fullScreen());
settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer());
settings.setGammaCorrection(config.useGammaCorrection());
return settings;
} }
/**
* Factory method for creating a server connection based on the current
* client configuration.
*
* @return A {@link ServerConnection} instance, which could be a real or mock server.
*/
private ServerConnection makeServerConnection() {
return new NetworkSupport(this);
}
/**
* Returns the dialog manager responsible for managing in-game dialogs.
*
* @return The {@link DialogManager} instance.
*/
public DialogManager getDialogManager() {
return dialogManager;
}
/**
* Returns the game logic handler for the client.
*
* @return The {@link ClientGameLogic} instance.
*/
@Override @Override
public ClientGameLogic getGameLogic() { public ClientGameLogic getGameLogic() {
return logic; return logic;
} }
public BoardManager getBoardManager() { /**
return boardManager; * Returns the current configuration settings for the Battleship client.
} *
* @return The {@link BattleshipClientConfig} instance.
public NetworkSupport getNetworkSupport() { */
return networkSupport; @Override
} public MonopolyAppConfig getConfig() {
return config;
private AppSettings makeSettings() {
final AppSettings settings = new AppSettings(true);
settings.setTitle("Monopoly Game");
settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight());
settings.setFullscreen(config.fullScreen());
return settings;
} }
/**
* Initializes the application.
* Sets up input mappings, GUI, game states, and connects to the server.
*/
@Override @Override
public void simpleInitApp() { public void simpleInitApp() {
GuiGlobals.initialize(this); setPauseOnLostFocus(false);
BaseStyles.loadStyleResources(STYLES_SCRIPT); draw = new Draw(assetManager);
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(); setupInput();
setupStates();
setupGui(); setupGui();
new StartMenu(this).open();
// Zeige das Startmenü
StartMenu.createStartMenu(this);
} }
/**
* Sets up the graphical user interface (GUI) for the application.
*/
private void setupGui() { private void setupGui() {
BitmapFont normalFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); GuiGlobals.initialize(this);
BaseStyles.loadStyleResources(STYLES_SCRIPT);
BaseStyles.loadGlassStyle();
GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS
final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
topText = new BitmapText(normalFont); topText = new BitmapText(normalFont);
topText.setLocalTranslation(10, settings.getHeight() - 10, 0); final int height = context.getSettings().getHeight();
topText.setLocalTranslation(10f, height - 10f, 0f);
topText.setColor(config.getTopColor());
guiNode.attachChild(topText); guiNode.attachChild(topText);
} }
/**
* Configures input mappings and sets up listeners for user interactions.
*/
private void setupInput() { private void setupInput() {
inputManager.deleteMapping(INPUT_MAPPING_EXIT); inputManager.deleteMapping(INPUT_MAPPING_EXIT);
inputManager.setCursorVisible(true); inputManager.setCursorVisible(false);
inputManager.addMapping("ESC", new KeyTrigger(KeyInput.KEY_ESCAPE)); inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addListener(escapeListener, "ESC"); inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(escapeListener, ESC);
inputManager.addMapping("B", new KeyTrigger(KeyInput.KEY_B));
inputManager.addListener(BListener, "B");
} }
private void handleEscape(boolean isPressed) { /**
if (isPressed) { * Initializes and attaches the necessary application states for the game.
if (settingsMenu != null && isSettingsMenuOpen) { */
// Schließe das SettingsMenu private void setupStates() {
System.out.println("Schließe SettingsMenu..."); if (config.getShowStatistics()) {
settingsMenu.close(); final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS
settingsMenu = null; final StatsAppState stats = new StatsAppState(guiNode, normalFont);
setSettingsMenuOpen(false); stateManager.attach(stats);
} else {
// Öffne das SettingsMenu
System.out.println("Öffne SettingsMenu...");
settingsMenu = new SettingsMenu(this);
settingsMenu.open();
setSettingsMenuOpen(true);
}
} }
flyCam.setEnabled(false);
stateManager.detach(stateManager.getState(StatsAppState.class));
stateManager.detach(stateManager.getState(DebugKeysAppState.class));
attachGameSound();
attachGameMusic();
} }
//logik zum wechselnden erscheinen und verschwinden beim drücken von B //TODO süäter entfernen /**
private void handleB(boolean isPressed) { * Attaches the game sound state and sets its initial enabled state.
if (isPressed) { */
if (foodField != null && isBuyCardPopupOpen) { private void attachGameSound() {
// Schließe das SettingsMenu final GameSound gameSound = new GameSound();
System.out.println("Schließe BuyCardPopup..."); logic.addListener(gameSound);
foodField.close(); gameSound.setEnabled(GameSound.enabledInPreferences());
foodField = null; stateManager.attach(gameSound);
setBuyCardPopupOpen(false);
} else {
// Öffne das SettingsMenu
System.out.println("Öffne BuyCardPopup...");
foodField = new FoodFieldCard(this);
foodField.open();
setBuyCardPopupOpen(true);
}
}
} }
private void blockInputs() { /**
if (!inputBlocked) { * Attaches the background music state and sets its initial enabled state.
System.out.println("Blockiere Eingaben..."); */
inputManager.setCursorVisible(true); // Cursor sichtbar machen private void attachGameMusic() {
inputManager.clearMappings(); // Alle Mappings entfernen final GameMusic gameSound = new GameMusic();
inputBlocked = true; gameSound.setEnabled(GameMusic.enabledInPreferences());
} stateManager.attach(gameSound);
}
public void unblockInputs() {
if (inputBlocked) {
System.out.println("Aktiviere Eingaben...");
setupInput(); // Standard-Eingaben neu registrieren
inputBlocked = false;
}
}
public void setInfoText(String text) {
topText.setText(text);
} }
/**
* Updates the application state every frame.
* This method is called once per frame during the game loop.
*
* @param tpf Time per frame in seconds.
*/
@Override @Override
public void receivedEvent(InfoTextEvent event) { public void simpleUpdate(float tpf) {
setInfoText(event.key()); super.simpleUpdate(tpf);
dialogManager.update(tpf);
logic.update(tpf);
} }
@Override /**
public void stop(boolean waitFor) { * Handles the Escape key action to either close the top dialog or show the main menu.
if (executor != null) executor.shutdownNow(); *
serverConnection.disconnect(); * @param isPressed Indicates whether the Escape key is pressed.
super.stop(waitFor); */
} public void escape(boolean isPressed) {
if (!isPressed) return;
public DialogManager getDialogManager() { if (dialogManager.showsDialog())
return dialogManager; dialogManager.escape();
else
new SettingsMenu(this).open();
} }
/**
* Returns the {@link Draw} instance used for rendering graphical elements in the game.
*
* @return The {@link Draw} instance.
*/
public Draw getDraw() { public Draw getDraw() {
return draw; return draw;
} }
public ExecutorService getExecutor() { /**
return executor; * Tries to connect
*/
public void connect() {
serverConnection.connect();
} }
/**
* Handles a request to close the application.
* If the request is initiated by pressing ESC, this parameter is true.
*
* @param esc If true, the request is due to the ESC key being pressed.
*/
@Override
public void requestClose(boolean esc) { /* do nothing */ }
/**
* Closes the application, displaying a confirmation dialog if the client is connected to a server.
*/
public void closeApp() { public void closeApp() {
if (serverConnection.isConnected())
confirmDialog(lookup("confirm.leaving"), this::close);
else
close();
}
/**
* Closes the application, disconnecting from the server and stopping the application.
*/
private void close() {
serverConnection.disconnect();
stop(); stop();
} }
public void errorDialog(String errorMessage) { /**
* Updates the informational text displayed in the GUI.
*
* @param text The information text to display.
*/
public void setInfoText(String text) {
LOGGER.log(Level.DEBUG, "setInfoText {0}", text); //NON-NLS
topText.setText(text);
}
/**
* Updates the informational text in the GUI based on the key received in an {@link InfoTextEvent}.
*
* @param event The {@link InfoTextEvent} containing the key for the text to display.
*/
@Override
public void receivedEvent(InfoTextEvent event) {
LOGGER.log(Level.DEBUG, "received info text {0}", event.key()); //NON-NLS
setInfoText(lookup(event.key()));
}
/**
* Handles client state events to update the game states accordingly.
*
* @param event The {@link ClientStateEvent} representing the state change.
*/
@Override
public void receivedEvent(ClientStateEvent event) {
}
/**
* Returns the executor service used for handling multithreaded tasks.
*
* @return The {@link ExecutorService} instance.
*/
public ExecutorService getExecutor() {
if (executor == null)
executor = Executors.newCachedThreadPool();
return executor;
}
/**
* Stops the application, shutting down the executor service and halting execution.
*
* @param waitFor If true, waits for the application to stop before returning.
*/
@Override
public void stop(boolean waitFor) {
if (executor != null) executor.shutdownNow();
super.stop(waitFor);
}
/**
* Displays a confirmation dialog with a specified question and action for the "Yes" button.
*
* @param question The question to display in the dialog.
* @param yesAction The action to perform if "Yes" is selected.
*/
public void confirmDialog(String question, Runnable yesAction) {
DialogBuilder.simple(dialogManager) DialogBuilder.simple(dialogManager)
.setTitle("Fehler") .setTitle(lookup("dialog.question"))
.setText(errorMessage) .setText(question)
.setOkButton("OK") .setOkButton(lookup("button.yes"), d -> {
getGameLogic().playSound(Sound.BUTTON); // Play sound
yesAction.run(); // Execute the original yesAction
})
.setNoButton(lookup("button.no"), d -> getGameLogic().playSound(Sound.BUTTON))
.build() .build()
.open(); .open();
} }
public void setSettingsMenuOpen(boolean isOpen) {
this.isSettingsMenuOpen = isOpen;
}
// TODO später entfernen
public void setBuyCardPopupOpen(boolean isOpen) {
this.isBuyCardPopupOpen = isOpen;
}
@Override
public void simpleUpdate(float tpf) {
if (testWorld != null) {
testWorld.update(tpf); // Aktualisiere die Kamera in der TestWorld
}
}
public void startTestWorld() {
guiNode.detachAllChildren(); // Entferne GUI
testWorld = new TestWorld(this); // Erstelle eine Instanz von TestWorld
testWorld.initializeScene(); // Initialisiere die Szene
}
// TODO später entfernen
public void startBuyCard() {
}
public void returnToMenu() {
guiNode.detachAllChildren(); // Entferne die GUI
StartMenu.createStartMenu(this); // Zeige das Startmenü erneut
}
/** /**
* Startet den Server in einem neuen Thread. * Displays an error dialog with the specified error message.
*
* @param errorMessage The error message to display in the dialog.
*/ */
public void startServer() { public void errorDialog(String errorMessage) {
new Thread(() -> { DialogBuilder.simple(dialogManager)
try { .setTitle(lookup("dialog.error"))
MonopolyServer.main(new String[0]); // Startet den MonopolyServer .setText(errorMessage)
} catch (Exception e) { .setOkButton(lookup("button.ok"), d -> getGameLogic().playSound(Sound.BUTTON))
errorDialog("Fehler: Server konnte nicht gestartet werden."); .build()
} .open();
}).start();
} }
public MonopolyServer getMonopolyServer() { public void disconnect() {
return monopolyServer; serverConnection.disconnect();
}
public ServerConnection getServerConnection() {
return serverConnection;
} }
} }

View File

@@ -1,146 +0,0 @@
package pp.monopoly.client;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.TextField;
import pp.dialog.Dialog;
import pp.dialog.DialogBuilder;
import pp.dialog.SimpleDialog;
/**
* Represents a dialog for setting up a network connection in the Monopoly game.
* Allows users to specify the host and port for connecting to a game server.
*/
class NetworkDialog extends SimpleDialog {
private static final Logger LOGGER = System.getLogger(NetworkDialog.class.getName());
private static final String LOCALHOST = "localhost";
private static final String DEFAULT_PORT = "42069";
private final NetworkSupport network;
private final TextField host = new TextField(LOCALHOST);
private final TextField port = new TextField(DEFAULT_PORT);
private String hostname;
private int portNumber;
private Future<Object> connectionFuture;
private Dialog progressDialog;
/**
* Constructs a new NetworkDialog.
*
* @param network The NetworkSupport instance to be used for network operations.
*/
NetworkDialog(NetworkSupport network) {
super(network.getApp().getDialogManager());
this.network = network;
initializeDialog();
}
/**
* Initializes the dialog with input fields and connection buttons.
*/
private void initializeDialog() {
final MonopolyApp app = network.getApp();
Container inputContainer = new Container();
// Titel und Eingabefelder für Host und Port
inputContainer.addChild(new Label("Server-Adresse"));
inputContainer.addChild(host);
inputContainer.addChild(new Label("Port"));
inputContainer.addChild(port);
Button connectButton = inputContainer.addChild(new Button("Verbinden"));
connectButton.addClickCommands(source -> connect());
Button cancelButton = inputContainer.addChild(new Button("Abbrechen"));
cancelButton.addClickCommands(source -> app.closeApp());
app.getGuiNode().attachChild(inputContainer);
}
/**
* Initiates the connection attempt based on the entered host and port.
*/
private void connect() {
LOGGER.log(Level.INFO, "Connecting to host={0}, port={1}", host, port);
try {
hostname = host.getText().trim().isEmpty() ? LOCALHOST : host.getText();
portNumber = Integer.parseInt(port.getText());
openProgressDialog();
connectionFuture = network.getApp().getExecutor().submit(this::initNetwork);
} catch (NumberFormatException e) {
network.getApp().errorDialog("Port muss eine Zahl sein.");
}
}
/**
* Opens a progress dialog while connecting.
*/
private void openProgressDialog() {
progressDialog = DialogBuilder.simple(network.getApp().getDialogManager())
.setText("Verbinde zum Server...")
.build();
progressDialog.open();
}
/**
* Attempts to initialize the network connection.
*
* @throws RuntimeException If an error occurs when creating the client.
*/
private Object initNetwork() {
try {
network.initNetwork(hostname, portNumber);
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Updates the connection status and handles completion or failure.
*/
@Override
public void update(float delta) {
if (connectionFuture != null && connectionFuture.isDone()) {
try {
connectionFuture.get();
onSuccess();
} catch (ExecutionException e) {
onFailure(e.getCause());
} catch (InterruptedException e) {
LOGGER.log(Level.WARNING, "Connection interrupted.", e);
Thread.currentThread().interrupt();
}
}
}
/**
* Handles a successful connection to the game server.
*/
private void onSuccess() {
connectionFuture = null;
progressDialog.close();
this.close();
network.getApp().setInfoText("Warte auf einen Gegner...");
}
/**
* Handles a failed connection attempt.
*
* @param e The cause of the failure.
*/
private void onFailure(Throwable e) {
connectionFuture = null;
progressDialog.close();
network.getApp().errorDialog("Verbindung zum Server fehlgeschlagen.");
network.getApp().setInfoText(e.getLocalizedMessage());
}
}

View File

@@ -1,8 +1,11 @@
package pp.monopoly.client; ////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
import java.io.IOException; package pp.monopoly.client;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import com.jme3.network.Client; import com.jme3.network.Client;
import com.jme3.network.ClientStateListener; import com.jme3.network.ClientStateListener;
@@ -10,12 +13,19 @@ import com.jme3.network.Message;
import com.jme3.network.MessageListener; import com.jme3.network.MessageListener;
import com.jme3.network.Network; import com.jme3.network.Network;
import pp.monopoly.client.gui.CreateGameMenu;
import pp.monopoly.game.client.ServerConnection; import pp.monopoly.game.client.ServerConnection;
import pp.monopoly.message.client.ClientMessage; import pp.monopoly.message.client.ClientMessage;
import pp.monopoly.message.server.ServerMessage; import pp.monopoly.message.server.ServerMessage;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import static pp.monopoly.Resources.lookup;
/** /**
* Manages the network connection for the Monopoly application. * Manages the network connection for the Battleship application.
* Handles connecting to and disconnecting from the server, and sending messages. * Handles connecting to and disconnecting from the server, and sending messages.
*/ */
public class NetworkSupport implements MessageListener<Client>, ClientStateListener, ServerConnection { public class NetworkSupport implements MessageListener<Client>, ClientStateListener, ServerConnection {
@@ -24,20 +34,29 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
private Client client; private Client client;
/** /**
* Constructs a NetworkSupport instance for the Monopoly application. * Constructs a NetworkSupport instance for the given Battleship application.
* *
* @param app The Monopoly application instance. * @param app The Battleship application instance.
*/ */
public NetworkSupport(MonopolyApp app) { public NetworkSupport(MonopolyApp app) {
this.app = app; this.app = app;
} }
/** /**
* Returns the Monopoly application instance. * Return the client connections Id
* * @return the client id
* @return Monopoly application instance
*/ */
MonopolyApp getApp() { public int getId() {
if (client == null) return 0;
return client.getId();
}
/**
* Returns the Battleship application instance.
*
* @return Battleship application instance
*/
public MonopolyApp getApp() {
return app; return app;
} }
@@ -57,9 +76,8 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/ */
@Override @Override
public void connect() { public void connect() {
if (client == null) { if (client == null)
new NetworkDialog(this).open(); new CreateGameMenu(this).open();
}
} }
/** /**
@@ -70,7 +88,7 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
if (client == null) return; if (client == null) return;
client.close(); client.close();
client = null; client = null;
LOGGER.log(Level.INFO, "Client connection closed."); LOGGER.log(Level.INFO, "client closed"); //NON-NLS
} }
/** /**
@@ -80,10 +98,9 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
* @param port The server's port. * @param port The server's port.
* @throws IOException If an I/O error occurs when creating the client. * @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) { if (client != null)
throw new IllegalStateException("Already connected to the game server."); throw new IllegalStateException("trying to join a game again");
}
client = Network.connectToServer(host, port); client = Network.connectToServer(host, port);
client.start(); client.start();
client.addMessageListener(this); client.addMessageListener(this);
@@ -98,11 +115,10 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/ */
@Override @Override
public void messageReceived(Client client, Message message) { public void messageReceived(Client client, Message message) {
LOGGER.log(Level.INFO, "Message received from server: {0}", message); LOGGER.log(Level.INFO, "message received from server: {0}", message); //NON-NLS
if (message instanceof ServerMessage serverMessage) { if (message instanceof ServerMessage serverMessage)
app.enqueue(() -> serverMessage.accept(app.getGameLogic())); app.enqueue(() -> serverMessage.accept(app.getGameLogic()));
} }
}
/** /**
* Called when the client has successfully connected to the server. * Called when the client has successfully connected to the server.
@@ -111,7 +127,7 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/ */
@Override @Override
public void clientConnected(Client client) { public void clientConnected(Client client) {
LOGGER.log(Level.INFO, "Successfully connected to server: {0}", client); LOGGER.log(Level.INFO, "Client connected: {0}", client); //NON-NLS
} }
/** /**
@@ -122,9 +138,13 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/ */
@Override @Override
public void clientDisconnected(Client client, DisconnectInfo disconnectInfo) { public void clientDisconnected(Client client, DisconnectInfo disconnectInfo) {
LOGGER.log(Level.INFO, "Disconnected from server: {0}", disconnectInfo); LOGGER.log(Level.INFO, "Client {0} disconnected: {1}", client, disconnectInfo); //NON-NLS
if (this.client != client)
throw new IllegalArgumentException("parameter value must be client");
LOGGER.log(Level.INFO, "client still connected: {0}", client.isConnected()); //NON-NLS
this.client = null; this.client = null;
app.enqueue(() -> app.setInfoText("Verbindung zum Server verloren.")); disconnect();
app.enqueue(() -> app.setInfoText(lookup("lost.connection.to.server")));
} }
/** /**
@@ -134,47 +154,10 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
*/ */
@Override @Override
public void send(ClientMessage message) { public void send(ClientMessage message) {
LOGGER.log(Level.INFO, "Sending message to server: {0}", message); LOGGER.log(Level.INFO, "sending {0}", message); //NON-NLS
if (client == null) { if (client == null)
app.errorDialog("Verbindung zum Server verloren."); app.errorDialog(lookup("lost.connection.to.server"));
} else { else
client.send(message); 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.");
}
}
} }

View File

@@ -39,21 +39,22 @@ public class CameraController {
* @param tpf Zeit pro Frame * @param tpf Zeit pro Frame
*/ */
public void update(float tpf) { 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); 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();
}
} }

View File

@@ -1,151 +1,226 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client.gui; package pp.monopoly.client.gui;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button; import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.TextField; import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
import static pp.monopoly.Resources.lookup;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.StartMenu; import pp.monopoly.client.NetworkSupport;
import pp.monopoly.notification.Sound;
import pp.monopoly.server.MonopolyServer;
import pp.dialog.Dialog;
import pp.dialog.DialogBuilder;
/** /**
* CreateGameMenu class represents the menu for creating a new game. * Represents a dialog for setting up a network connection in the Battleship game.
* Allows users to specify the host and port for connecting to a game server.
*/ */
public class CreateGameMenu { public class CreateGameMenu extends Dialog {
private static final Logger LOGGER = System.getLogger(CreateGameMenu.class.getName());
private final MonopolyApp app; private static final String LOCALHOST = "localhost"; //NON-NLS
private final Container menuContainer; private static final String DEFAULT_PORT = "42069"; //NON-NLS
private Geometry background; private final NetworkSupport network;
private Label serverStatusLabel; private final TextField host = new TextField(LOCALHOST);
private final TextField port = new TextField(DEFAULT_PORT);
public CreateGameMenu(MonopolyApp app) { private final Button serverButton = new Button("Selber hosten");
this.app = app; private final Button cancelButton = new Button("Abbrechen");
private final Button joinButton = new Button("Beitreten");
// Hintergrundbild laden und hinzufügen private String hostname;
addBackgroundImage(); private int portNumber;
private Future<Object> connectionFuture;
// Hauptcontainer für das Menü private Dialog progressDialog;
menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
menuContainer.setPreferredSize(new Vector3f(600, 400, 0)); // Feste Größe des Containers
// Titel
Label title = menuContainer.addChild(new Label("Neues Spiel", new ElementId("header")));
title.setFont(app.getAssetManager().loadFont("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt"));
title.setFontSize(50);
// Eingabefelder-Container
Container inputContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X)));
inputContainer.setPreferredSize(new Vector3f(200, 150, 0)); // Eingabefelder nicht ganz so breit
inputContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand
inputContainer.addChild(new Label("Server-Adresse:"));
TextField playerNameField = inputContainer.addChild(new TextField("localhost"));
playerNameField.setPreferredWidth(400); // Breite des Textfelds
inputContainer.addChild(new Label("Port:"));
TextField serverAddressField = inputContainer.addChild(new TextField("42069"));
serverAddressField.setPreferredWidth(400); // Breite des Textfelds
// Button-Container
Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
buttonContainer.setPreferredSize(new Vector3f(400, 50, 0));
buttonContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand
// "Abbrechen"-Button
Button cancelButton = buttonContainer.addChild(new Button("Abbrechen"));
cancelButton.setPreferredSize(new Vector3f(120, 40, 0));
cancelButton.addClickCommands(source -> goBackToStartMenu());
// "Selber hosten"-Button
Button hostButton = buttonContainer.addChild(new Button("Selber hosten"));
hostButton.setPreferredSize(new Vector3f(120, 40, 0));
hostButton.addClickCommands(source -> app.getNetworkSupport().startServerAndJoin());
// "Beitreten"-Button
Button joinButton = buttonContainer.addChild(new Button("Beitreten"));
joinButton.setPreferredSize(new Vector3f(120, 40, 0));
joinButton.addClickCommands(source -> {
try {
String host = playerNameField.getText().trim();
int port = Integer.parseInt(serverAddressField.getText().trim());
app.getNetworkSupport().connectToServer(host, port);
// LobbyMenu öffnen
app.enqueue(() -> {
app.getGuiNode().detachAllChildren(); // Bestehende GUI entfernen
new LobbyMenu(app); // LobbyMenu erstellen
});
} catch (NumberFormatException e) {
app.errorDialog("Port muss eine Zahl sein.");
}
});
// Serverstatus-Label
serverStatusLabel = menuContainer.addChild(new Label("Serverstatus: Noch nicht gestartet"));
serverStatusLabel.setFontSize(24);
// Zentrierung des Containers
menuContainer.setLocalTranslation(
(app.getCamera().getWidth() - menuContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + menuContainer.getPreferredSize().y) / 2,
1 // Höhere Z-Ebene für den Vordergrund
);
app.getInputManager().addMapping("OpenTestWorld", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_T));
app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("OpenTestWorld") && isPressed) {
app.startTestWorld(); // Öffnet die TestWorld
}
}
}, "OpenTestWorld");
// TODO später entfernen
app.getInputManager().addMapping("OpenBuyCard", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_B));
app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("OpenBuyCard") && isPressed) {
app.startBuyCard(); // Öffnet die TestWorld
}
}
}, "OpenBuyCard");
app.getGuiNode().attachChild(menuContainer);
}
/** /**
* Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu. * Constructs a new CreateGameMenu.
*
* @param network The NetworkSupport instance to be used for network operations.
*/ */
private void addBackgroundImage() { public CreateGameMenu(NetworkSupport network) {
super(network.getApp().getDialogManager());
this.network = network;
host.setSingleLine(true);
host.setPreferredWidth(400f);
port.setSingleLine(true);
final MonopolyApp app = network.getApp();
int screenWidth = app.getContext().getSettings().getWidth();
int screenHeight = app.getContext().getSettings().getHeight();
// Set up the background image
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png"); Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png");
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(screenWidth, screenHeight);
background = new Geometry("Background", quad); Geometry background = new Geometry("Background", quad);
Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
backgroundMaterial.setTexture("ColorMap", backgroundImage); backgroundMaterial.setTexture("ColorMap", backgroundImage);
background.setMaterial(backgroundMaterial); background.setMaterial(backgroundMaterial);
background.setLocalTranslation(0, 0, -1); // Hintergrundebene background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
app.getGuiNode().attachChild(background); app.getGuiNode().attachChild(background);
addChild(new Label("Spiel erstellen", new ElementId("header"))); //NON-NLS
final Container input = new Container(new SpringGridLayout());
input.addChild(new Label(lookup("host.name") + ": "));
input.addChild(host, 1);
input.addChild(new Label(lookup("port.number") + ": "));
input.addChild(port, 1);
addChild(input);
// "Abbrechen"-Button
cancelButton.setPreferredSize(new Vector3f(120, 40, 0));
cancelButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
this.close();
new StartMenu(network.getApp()).open();
}));
addChild(cancelButton);
// "Selber hosten"-Button
serverButton.addClickCommands(s -> ifTopDialog( () -> {
network.getApp().getGameLogic().playSound(Sound.BUTTON);
startServerInThread();
} ));
addChild(serverButton);
// "Beitreten"-Button
joinButton.setPreferredSize(new Vector3f(120, 40, 0));
joinButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
connect();
}));
addChild(joinButton);
} }
/** /**
* Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird. * Handles the action for the connect button in the connection dialog.
* Tries to parse the port number and initiate connection to the server.
*/ */
private void goBackToStartMenu() { private void connect() {
app.getGuiNode().detachChild(menuContainer); LOGGER.log(Level.INFO, "connect to host={0}, port={1}", host, port); //NON-NLS
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild try {
StartMenu.createStartMenu(app); hostname = host.getText().trim().isEmpty() ? LOCALHOST : host.getText();
portNumber = Integer.parseInt(port.getText());
openProgressDialog();
connectionFuture = network.getApp().getExecutor().submit(this::initNetwork);
}
catch (NumberFormatException e) {
network.getApp().errorDialog(lookup("port.must.be.integer"));
}
}
/**
* Creates a dialog indicating that the connection is in progress.
*/
private void openProgressDialog() {
progressDialog = DialogBuilder.simple(network.getApp().getDialogManager())
.setText(lookup("label.connecting"))
.build();
progressDialog.open();
}
/**
* Tries to initialize the network connection.
*
* @throws RuntimeException If an error occurs when creating the client.
*/
private Object initNetwork() {
try {
network.initNetwork(hostname, portNumber);
return null;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void escape() {
new SettingsMenu(network.getApp()).open();
}
/**
* This method is called by {@linkplain pp.dialog.DialogManager#update(float)} for periodically
* updating this dialog. T
*/
@Override
public void update(float delta) {
if (connectionFuture != null && connectionFuture.isDone())
try {
connectionFuture.get();
success();
}
catch (ExecutionException e) {
failure(e.getCause());
}
catch (InterruptedException e) {
LOGGER.log(Level.WARNING, "Interrupted!", e); //NON-NLS
Thread.currentThread().interrupt();
}
}
/**
* Handles a successful connection to the game server.
*/
private void success() {
connectionFuture = null;
progressDialog.close();
this.close();
new LobbyMenu(network.getApp()).open();
}
/**
* Handles a failed connection attempt.
*
* @param e The cause of the failure.
*/
private void failure(Throwable e) {
connectionFuture = null;
progressDialog.close();
network.getApp().errorDialog(lookup("server.connection.failed"));
network.getApp().setInfoText(e.getLocalizedMessage());
}
/**
* Starts the server in a separate thread.
*/
private void startServerInThread() {
serverButton.setEnabled(false);
Thread serverThread = new Thread(() -> {
try {
MonopolyServer.main(null);
} catch (Exception e) {
serverButton.setEnabled(true);
LOGGER.log(Level.ERROR, "Server could not be started", e);
network.getApp().errorDialog("Could not start server: " + e.getMessage());
}
});
serverThread.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
connect();
} }
} }

View File

@@ -7,6 +7,7 @@ import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import com.simsilica.lemur.Axis; import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button; import com.simsilica.lemur.Button;
@@ -21,47 +22,63 @@ import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList; import com.simsilica.lemur.core.VersionedList;
import com.simsilica.lemur.core.VersionedReference; import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.message.client.PlayerReady;
import pp.monopoly.notification.Sound;
import java.util.Set; import java.util.Set;
public class LobbyMenu { public class LobbyMenu extends Dialog {
private final MonopolyApp app; private final MonopolyApp app;
private final Container menuContainer; private final Container menuContainer;
private Geometry background; private Geometry background;
private final Selector<String> dropdown; private Geometry circle;
private Container lowerLeftMenu;
private Container lowerRightMenu;
private ColorRGBA playerColor= ColorRGBA.Gray;
private PlayerHandler playerHandler;
private TextField startingCapital;
private TextField playerInputField;
private Selector<String> figureDropdown;
private TextField playerInputField = new TextField("Spieler 1");
private TextField startingCapital = new TextField("15000");
private String figure;
public LobbyMenu(MonopolyApp app) { public LobbyMenu(MonopolyApp app) {
super(app.getDialogManager());
this.app = app; this.app = app;
// Entfernt das CreateGameMenu (inklusive Hintergrund) app.getGuiNode().detachAllChildren(); // Entfernt das CreateGameMenu (inklusive Hintergrund)
app.getGuiNode().detachAllChildren();
// Hintergrundbild laden und hinzufügen addBackgroundImage();// Hintergrundbild laden und hinzufügen
addBackgroundImage();
QuadBackgroundComponent translucentWhiteBackground = QuadBackgroundComponent translucentWhiteBackground =
new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f)); new QuadBackgroundComponent(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X)); menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
menuContainer.setPreferredSize(new Vector3f(1000, 600, 0)); // Fixed size of the container menuContainer.setPreferredSize(new Vector3f(1000, 600, 0));
menuContainer.setBackground(translucentWhiteBackground); menuContainer.setBackground(translucentWhiteBackground);
// Create a smaller horizontal container for the label, input field, and spacers // Create a smaller horizontal container for the label, input field, and spacers
Container horizontalContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y))); Container horizontalContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
horizontalContainer.setPreferredSize(new Vector3f(600, 50, 0)); // Adjust container size horizontalContainer.setPreferredSize(new Vector3f(600, 40, 0));
horizontalContainer.setBackground(null); horizontalContainer.setBackground(null);
Label title = horizontalContainer.addChild(new Label("Startkapital:", new ElementId("label-Bold"))); Label title = horizontalContainer.addChild(new Label("Startkapital:", new ElementId("label-Bold")));
title.setFontSize(48); title.setFontSize(40);
// Add a spacer between the title and the input field // Add a spacer between the title and the input field
Label spacerBeforeInput = horizontalContainer.addChild(new Label("")); // Invisible spacer Label spacerBeforeInput = horizontalContainer.addChild(new Label("")); // Invisible spacer
spacerBeforeInput.setPreferredSize(new Vector3f(20, 1, 0)); // Width of the spacer spacerBeforeInput.setPreferredSize(new Vector3f(20, 1, 0)); // Width of the spacer
// Add an input field (TextField) // Add an input field (TextField)
TextField startingCapital = horizontalContainer.addChild(new TextField("")); horizontalContainer.addChild(startingCapital);
startingCapital.setPreferredWidth(100); // Set the width of the input field startingCapital.setPreferredWidth(100); // Set the width of the input field
startingCapital.setPreferredSize(new Vector3f(150, 50, 0)); startingCapital.setPreferredSize(new Vector3f(150, 50, 0));
startingCapital.setInsets(new Insets3f(5, 10, 5, 10)); // Add padding around the text inside the field startingCapital.setInsets(new Insets3f(5, 10, 5, 10)); // Add padding around the text inside the field
@@ -77,40 +94,94 @@ public class LobbyMenu {
); );
app.getGuiNode().attachChild(menuContainer); app.getGuiNode().attachChild(menuContainer);
// Spielerstatus anzeigen // Dropdowns and Labels
Container playerListContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X))); Container dropdownContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
playerListContainer.addChild(new Label("Spieler in der Lobby:")); dropdownContainer.setPreferredSize(new Vector3f(800, 200, 0));
playerListContainer.setBackground(null); dropdownContainer.setBackground(null);
Label playersLabel = playerListContainer.addChild(new Label("Noch keine Spieler verbunden.")); // Beispieltext dropdownContainer.setInsets(new Insets3f(10, 0, 0, 0));
// Player Input Field
VersionedList<String> items = new VersionedList<>(); Container playerInputContainer = dropdownContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X)));
items.add("Alpha"); playerInputContainer.addChild(new Label("Spieler:"));
items.add("Beta"); playerInputContainer.setBackground(null);
items.add("Gamma");
items.add("Back");
dropdown = new Selector<>(items,"glass");
dropdown.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
menuContainer.addChild(dropdown);
// Add the custom action listener
addSelectionActionListener(dropdown, this::onDropdownSelectionChanged);
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<String> figures = new VersionedList<>();
figures.add("Laptop");
figures.add("Flugzeug");
figures.add("Jägermeister");
figures.add("Katze");
figures.add("OOP");
figures.add("Handyholster");
Selector<String> 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);
// Buttons
Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y))); Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
buttonContainer.setPreferredSize(new Vector3f(400, 50, 0)); 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("Beenden");
cancelButton.setPreferredSize(new Vector3f(200, 60, 0)); // Set size to match the appearance in the image
cancelButton.setFontSize(18); // Adjust font size
cancelButton.addClickCommands(s -> ifTopDialog(() -> {
app.closeApp();
app.getGameLogic().playSound(Sound.BUTTON);
}));
lowerLeftMenu.addChild(cancelButton);
// "Bereit"-Button // Position the container near the bottom-left corner
Button readyButton = buttonContainer.addChild(new Button("Bereit")); lowerLeftMenu.setLocalTranslation(new Vector3f(120, 170, 3)); // Adjust X and Y to align with the bottom-left corner
readyButton.setPreferredSize(new Vector3f(120, 40, 0)); app.getGuiNode().attachChild(lowerLeftMenu);
readyButton.addClickCommands(source -> toggleReady(playersLabel));
// "Zurück"-Button // Lower-right container for "Bereit" button
Button backButton = buttonContainer.addChild(new Button("Zurück")); lowerRightMenu = new Container();
backButton.setPreferredSize(new Vector3f(120, 40, 0)); Button readyButton = new Button("Bereit");
backButton.addClickCommands(source -> goBackToCreateGame()); 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(s -> ifTopDialog(() -> {
toggleReady();
app.getGameLogic().playSound(Sound.BUTTON);
}));
lowerRightMenu.addChild(readyButton);
//TODO aktivieren des Spielers in den ready Status und Sprung in den nächsten Menüzustand
// Position the container near the bottom-right corner
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 // Zentrierung des Containers
menuContainer.setLocalTranslation( menuContainer.setLocalTranslation(
@@ -121,12 +192,65 @@ public class LobbyMenu {
app.getGuiNode().attachChild(menuContainer); 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. * Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu.
*/ */
private void addBackgroundImage() { private void addBackgroundImage() {
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png"); Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/lobby.png");
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
background = new Geometry("Background", quad); background = new Geometry("Background", quad);
Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
@@ -137,21 +261,40 @@ public class LobbyMenu {
app.getGuiNode().attachChild(background); app.getGuiNode().attachChild(background);
} }
/** private Geometry createCircle() {
* Schaltet den "Bereit"-Status um.
*/ Sphere sphere = new Sphere(90,90,60.0f);
private void toggleReady(Label playersLabel) { Geometry circleGeometry = new Geometry("Circle", sphere);
// Beispiel-Logik für das Umschalten des Status
playersLabel.setText("Spielerstatus aktualisiert."); // Beispieltext // 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);
}
} }
/** /**
* Geht zurück zum CreateGameMenu. * Assigns a color to the player based on their ID.
*
* @param playerID the player's ID
*/ */
private void goBackToCreateGame() { private void toggleReady() {
app.getGuiNode().detachChild(menuContainer); app.getGameLogic().send(new PlayerReady(true, playerInputField.getText(), figure, Integer.parseInt(startingCapital.getText())));
app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild }
new CreateGameMenu(app);
@Override
public void escape() {
new SettingsMenu(app).open();
} }
/** /**
@@ -195,21 +338,28 @@ public class LobbyMenu {
*/ */
private void onDropdownSelectionChanged(String selected) { private void onDropdownSelectionChanged(String selected) {
System.out.println("Selected: " + selected); System.out.println("Selected: " + selected);
app.getGameLogic().playSound(Sound.BUTTON);
switch (selected) { switch (selected) {
case "[0]": case "[0]":
System.out.println("Alpha selected"); figure = "Laptop";
break; break;
case "[1]": case "[1]":
System.out.println("Beta selected"); figure = "Flugzeug";
break; break;
case "[2]": case "[2]":
System.out.println("Gamma selected"); figure = "Jägermeister";
break; break;
case "[3]": case "[3]":
goBackToCreateGame(); figure = "Katze";
break;
case "[4]":
figure = "OOP";
break;
case "[5]":
figure = "Handyholster";
break; break;
default: default:
System.out.println("Unknown selection"); break;
} }
} }

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -1,123 +1,92 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.client.gui; package pp.monopoly.client.gui;
import com.jme3.material.Material; import java.util.prefs.Preferences;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button; import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox; import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; 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.style.ElementId;
import com.simsilica.lemur.ValueRenderer;
import com.simsilica.lemur.Selector; import static pp.monopoly.Resources.lookup;
import pp.dialog.Dialog; import pp.monopoly.client.GameMusic;
import pp.monopoly.client.GameSound;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.dialog.Dialog;
import pp.dialog.StateCheckboxModel;
import pp.monopoly.notification.Sound;
import static pp.util.PreferencesUtils.getPreferences;
/** /**
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann. * The Menu class represents the main menu in the Battleship game application.
* It extends the Dialog class and provides functionalities for loading, saving,
* returning to the game, and quitting the application.
*/ */
public class SettingsMenu extends Dialog { public class SettingsMenu extends Dialog {
private static final Preferences PREFERENCES = getPreferences(SettingsMenu.class);
private static final String LAST_PATH = "last.file.path";
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground; private final VolumeSlider musicSlider;
private final Container settingsContainer; private final SoundSlider soundSlider;
private final Container backgroundContainer;
/**
* Constructs the Menu dialog for the Battleship application.
*
* @param app the MonopolyApp instance
*/
public SettingsMenu(MonopolyApp app) { public SettingsMenu(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
musicSlider = new VolumeSlider(app.getStateManager().getState(GameMusic.class));
soundSlider = new SoundSlider(app.getStateManager().getState(GameSound.class));
addChild(new Label("Einstellungen", new ElementId("settings-title"))); //NON-NLS
addChild(new Label("Sound Effekte", new ElementId("label"))); //NON-NLS
// Halbtransparentes Overlay hinzufügen addChild(soundSlider);
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container addChild(new Checkbox("Soundeffekte an / aus", new StateCheckboxModel(app, GameSound.class)));
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ü addChild(new Label("Hintergrund Musik", new ElementId("label"))); //NON-NLS
settingsContainer = new Container(); addChild(new Checkbox("Musik an / aus", new StateCheckboxModel(app, GameMusic.class)));
settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
addChild(musicSlider);
addChild(new Button("Zurück zum Spiel", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> {
// Titel this.close(); // Close the StartMenu dialog
Label settingsTitle = settingsContainer.addChild(new Label("Einstellungen", new ElementId("settings-title"))); app.getGameLogic().playSound(Sound.BUTTON);
settingsTitle.setFontSize(48); }));
addChild(new Button("Beenden", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> {
// Effekt-Sound: Slider und Checkbox app.getGameLogic().playSound(Sound.BUTTON);
Container effectSoundContainer = settingsContainer.addChild(new Container()); app.closeApp();
effectSoundContainer.addChild(new Label("Effekt Sound", new ElementId("label"))); }));
effectSoundContainer.addChild(new Slider()); update();
effectSoundContainer.addChild(new Checkbox("Soundeffekte an")).setChecked(true);
effectSoundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Hintergrundmusik: Slider und Checkbox
Container backgroundMusicContainer = settingsContainer.addChild(new Container());
backgroundMusicContainer.addChild(new Label("Hintergrund Musik", new ElementId("label")));
backgroundMusicContainer.addChild(new Slider());
backgroundMusicContainer.addChild(new Checkbox("Musik an")).setChecked(true);
backgroundMusicContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button
Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("menu-button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> app.stop());
float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü
settingsContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2,
4
);
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2,
3
);
app.getGuiNode().attachChild(settingsContainer);
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Updates the state of the load and save buttons based on the game logic.
*
* @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 @Override
public void close() { public void update() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren
app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
} }
@Override
public void update(float delta) {
musicSlider.update();
soundSlider.update();
}
/**
* As an escape action, this method closes the menu if it is the top dialog.
*/
@Override
public void escape() {
close();
}
} }

View File

@@ -0,0 +1,31 @@
package pp.monopoly.client.gui;
import com.simsilica.lemur.Slider;
import pp.monopoly.client.GameSound;
public class SoundSlider extends Slider {
private final pp.monopoly.client.GameSound sound;
private double vol;
/**
* Constructs the Volume Slider for the Menu dialog
* @param sound the Effects sound instance
*/
public SoundSlider(GameSound sound) {
super();
this.sound = sound;
vol = GameSound.volumeInPreferences();
getModel().setPercent(vol);
}
/**
* when triggered it updates the volume to the value set with the slider
*/
public void update() {
if (vol != getModel().getPercent()) {
vol = getModel().getPercent();
sound.setVolume( (float) vol);
}
}
}

View File

@@ -1,4 +1,4 @@
package pp.monopoly.client; package pp.monopoly.client.gui;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
@@ -13,8 +13,8 @@ import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.monopoly.client.gui.CreateGameMenu; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.notification.Sound;
/** /**
* Constructs the startup menu dialog for the Monopoly application. * Constructs the startup menu dialog for the Monopoly application.
@@ -22,8 +22,6 @@ import pp.monopoly.client.gui.GameMenu;
*/ */
public class StartMenu extends Dialog { public class StartMenu extends Dialog {
private final MonopolyApp app; private final MonopolyApp app;
private Container logoContainer;
private Container unibwLogoContainer;
/** /**
* Constructs the Startup Menu dialog for the Monopoly application. * Constructs the Startup Menu dialog for the Monopoly application.
@@ -33,13 +31,7 @@ public class StartMenu extends Dialog {
public StartMenu(MonopolyApp app) { public StartMenu(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
}
/**
* Creates and displays the Start Menu with buttons for starting the game,
* opening settings, and quitting the application.
*/
public static void createStartMenu(MonopolyApp app) {
int screenWidth = app.getContext().getSettings().getWidth(); int screenWidth = app.getContext().getSettings().getWidth();
int screenHeight = app.getContext().getSettings().getHeight(); int screenHeight = app.getContext().getSettings().getHeight();
@@ -53,9 +45,6 @@ public class StartMenu extends Dialog {
background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements
app.getGuiNode().attachChild(background); app.getGuiNode().attachChild(background);
createMonopolyLogo(app);
createUnibwLogo(app);
// Center container for title and play button // Center container for title and play button
Container centerMenu = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container centerMenu = new Container(new SpringGridLayout(Axis.Y, Axis.X));
@@ -64,7 +53,11 @@ public class StartMenu extends Dialog {
startButton.setFontSize(40); // Set the font size for the button text startButton.setFontSize(40); // Set the font size for the button text
startButton.setTextHAlignment(HAlignment.Center); // Center the text horizontally startButton.setTextHAlignment(HAlignment.Center); // Center the text horizontally
startButton.addClickCommands(source -> startGame(app)); startButton.addClickCommands(s -> ifTopDialog(() -> {
this.close(); // Close the StartMenu dialog
app.connect(); // Perform the connection logic
app.getGameLogic().playSound(Sound.BUTTON);
}));
centerMenu.addChild(startButton); centerMenu.addChild(startButton);
// Position the center container in the middle of the screen // Position the center container in the middle of the screen
@@ -73,34 +66,6 @@ public class StartMenu extends Dialog {
0)); 0));
app.getGuiNode().attachChild(centerMenu); app.getGuiNode().attachChild(centerMenu);
// Lower-left container for "Spiel beenden" button
Container lowerLeftMenu = new Container();
lowerLeftMenu.setLocalTranslation(new Vector3f(100, 90, 0));
Button quitButton = new Button("Spiel beenden");
quitButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height)
quitButton.setFontSize(18);
quitButton.addClickCommands(source -> quitGame());
lowerLeftMenu.addChild(quitButton);
app.getGuiNode().attachChild(lowerLeftMenu);
// Lower-right container for "Einstellungen" button
Container lowerRightMenu = new Container();
lowerRightMenu.setLocalTranslation(new Vector3f(screenWidth - 200, 90, 0));
Button settingsButton = new Button("Einstellungen");
settingsButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height)
settingsButton.setFontSize(18); // Increase the font size for the text
settingsButton.addClickCommands(source -> openSettings(app));
lowerRightMenu.addChild(settingsButton);
app.getGuiNode().attachChild(lowerRightMenu);
}
/**
* Creates and positions the Monopoly logo container in the center of the screen.
*/
private static void createMonopolyLogo(MonopolyApp app) {
int screenWidth = app.getContext().getSettings().getWidth();
int screenHeight = app.getContext().getSettings().getHeight();
// Load the Monopoly logo as a texture // Load the Monopoly logo as a texture
Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopoly.png"); Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopoly.png");
@@ -123,14 +88,6 @@ public class StartMenu extends Dialog {
// Attach the container to the GUI node // Attach the container to the GUI node
app.getGuiNode().attachChild(logoContainer); app.getGuiNode().attachChild(logoContainer);
}
/**
* Creates and positions the Unibw logo container in the center of the screen.
*/
private static void createUnibwLogo(MonopolyApp app) {
int screenWidth = app.getContext().getSettings().getWidth();
int screenHeight = app.getContext().getSettings().getHeight();
// Load the Unibw logo as a texture // Load the Unibw logo as a texture
Texture unibwTexture = app.getAssetManager().loadTexture("Pictures/logo-unibw.png"); Texture unibwTexture = app.getAssetManager().loadTexture("Pictures/logo-unibw.png");
@@ -156,26 +113,14 @@ public class StartMenu extends Dialog {
app.getGuiNode().attachChild(unibwContainer); app.getGuiNode().attachChild(unibwContainer);
} }
/** @Override
* Starts the game by transitioning to the CreateGameMenu. public void escape() {
*/ new SettingsMenu(app).open();
private static void startGame(MonopolyApp app) {
app.getGuiNode().detachAllChildren();
new CreateGameMenu(app);
} }
/** @Override
* Opens the settings menu. public void close() {
*/
private static void openSettings(MonopolyApp app) {
app.getGuiNode().detachAllChildren(); app.getGuiNode().detachAllChildren();
new SettingsMenu(app); super.close();
}
/**
* Quits the game application.
*/
private static void quitGame() {
System.exit(0);
} }
} }

View File

@@ -1,5 +1,9 @@
package pp.monopoly.client.gui; 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.material.Material;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
@@ -43,15 +47,18 @@ public class TestWorld {
cameraController = new CameraController( cameraController = new CameraController(
app.getCamera(), // Die Kamera der App app.getCamera(), // Die Kamera der App
Vector3f.ZERO, // Fokus auf die Mitte des Spielfelds Vector3f.ZERO, // Fokus auf die Mitte des Spielfelds
5, // Radius des Kreises 4, // Radius des Kreises
3, // Höhe der Kamera 15, // Höhe der Kamera
0.5f // Geschwindigkeit der Bewegung 0 // Geschwindigkeit der Bewegung
); );
// Füge die Toolbar hinzu // Füge die Toolbar hinzu
new Toolbar(app, cube); new Toolbar(app, cube);
cameraController.setPosition(0);
} }
/** /**
* Aktualisiert die Kameraposition. * Aktualisiert die Kameraposition.
* *
@@ -75,7 +82,7 @@ public class TestWorld {
*/ */
private void createBoard() { private void createBoard() {
// Erstelle ein Quadrat // 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); Geometry geom = new Geometry("Board", box);
// Setze das Material mit Textur // Setze das Material mit Textur

View File

@@ -14,6 +14,7 @@ import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound;
/** /**
* Toolbar Klasse, die am unteren Rand der Szene angezeigt wird. * Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
@@ -135,7 +136,10 @@ public class Toolbar extends Dialog {
private Button addDiceRollButton() { private Button addDiceRollButton() {
Button diceButton = new Button("Würfeln"); Button diceButton = new Button("Würfeln");
diceButton.setPreferredSize(new Vector3f(50, 20, 0)); diceButton.setPreferredSize(new Vector3f(50, 20, 0));
diceButton.addClickCommands(source -> rollDice()); diceButton.addClickCommands(s -> ifTopDialog(() -> {
rollDice();
app.getGameLogic().playSound(Sound.BUTTON);
}));
toolbarContainer.addChild(diceButton); toolbarContainer.addChild(diceButton);
return diceButton; return diceButton;
} }
@@ -143,21 +147,30 @@ public class Toolbar extends Dialog {
private void addTradeMenuButton() { private void addTradeMenuButton() {
Button diceButton = new Button("Handeln"); Button diceButton = new Button("Handeln");
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
diceButton.addClickCommands(source -> rollDice()); diceButton.addClickCommands(s -> ifTopDialog(() -> {
rollDice();
app.getGameLogic().playSound(Sound.BUTTON);
}));
toolbarContainer.addChild(diceButton); toolbarContainer.addChild(diceButton);
} }
private void addEndTurnButton() { private void addEndTurnButton() {
Button diceButton = new Button("Grundstücke"); Button diceButton = new Button("Grundstücke");
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
diceButton.addClickCommands(source -> rollDice()); diceButton.addClickCommands(s -> ifTopDialog(() -> {
rollDice();
app.getGameLogic().playSound(Sound.BUTTON);
}));
toolbarContainer.addChild(diceButton); toolbarContainer.addChild(diceButton);
} }
private void addPropertyMenuButton() { private void addPropertyMenuButton() {
Button diceButton = new Button("Zug beenden"); Button diceButton = new Button("Zug beenden");
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
diceButton.addClickCommands(source -> rollDice()); diceButton.addClickCommands(s -> ifTopDialog(() -> {
rollDice();
app.getGameLogic().playSound(Sound.BUTTON);
}));
toolbarContainer.addChild(diceButton); toolbarContainer.addChild(diceButton);
} }

View File

@@ -0,0 +1,37 @@
package pp.monopoly.client.gui;
import com.simsilica.lemur.Slider;
import pp.monopoly.client.GameMusic;
/**
* The VolumeSlider class represents the Volume Slider in the Menu.
* It extends the Slider class and provides functionalities for setting the music volume,
* with the help of the Slider in the GUI
*/
public class VolumeSlider extends Slider {
private final pp.monopoly.client.GameMusic music;
private double vol;
/**
* Constructs the Volume Slider for the Menu dialog
* @param music the music instance
*/
public VolumeSlider(GameMusic music) {
super();
this.music = music;
vol = GameMusic.volumeInPreferences();
getModel().setPercent(vol);
}
/**
* when triggered it updates the volume to the value set with the slider
*/
public void update() {
if (vol != getModel().getPercent()) {
vol = getModel().getPercent();
music.setVolume( (float) vol);
}
}
}

View File

@@ -5,7 +5,6 @@ import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
@@ -22,17 +21,16 @@ import pp.monopoly.model.fields.BuildingProperty;
public class BuildingPropertyCard extends Dialog { public class BuildingPropertyCard extends Dialog {
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground; private final Geometry overlayBackground;
private final Container settingsContainer; private final Container buildingPropertyContainer;
private final Container backgroundContainer; private final Container backgroundContainer;
private int index = 23; private int index = 37;
public BuildingPropertyCard(MonopolyApp app) { public BuildingPropertyCard(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
// Titel
//Generate the corresponfing field //Generate the corresponfing field
BuildingProperty field = (BuildingProperty) app.getBoardManager().getFieldAtIndex(index); BuildingProperty field = (BuildingProperty) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen // Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground(); overlayBackground = createOverlayBackground();
@@ -43,22 +41,19 @@ public class BuildingPropertyCard extends Dialog {
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer); app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für das Menü // Hauptcontainer für die Gebäudekarte
settingsContainer = new Container(); buildingPropertyContainer = new Container();
//settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(170 / 255f, 223 / 255f, 246 / 255f, 1))); // hell buildingPropertyContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
settingsContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor())); //dunkel
Label settingsTitle = buildingPropertyContainer.addChild(new Label( field.getName(), new ElementId("settings-title")));
Label settingsTitle = settingsContainer.addChild(new Label( field.getName(), new ElementId("settings-title")));
settingsTitle.setFontSize(48); settingsTitle.setFontSize(48);
// Effekt-Sound: Slider und Checkbox // Text, der auf der Karte steht
Container propertyValuesContainer = settingsContainer.addChild(new Container()); // 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("„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("„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 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 2 Häuser: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text")));
@@ -66,34 +61,39 @@ public class BuildingPropertyCard extends Dialog {
propertyValuesContainer.addChild(new Label("„-mit 4 Häuser: " + field.getAllRent().get(4) + " 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("„-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("„-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.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))); 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 // Beenden-Button
Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("button"))); Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
// Kaufen-Button // Kaufen-Button
Button buyButton = settingsContainer.addChild(new Button("Kaufen", new ElementId("button"))); Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32); buyButton.setFontSize(32);
*/
float padding = 10; // Padding around the settingsContainer for the background float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(buildingPropertyContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü // Zentriere das Menü
settingsContainer.setLocalTranslation( buildingPropertyContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y) / 2,
8 8
); );
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - buildingPropertyContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + buildingPropertyContainer.getPreferredSize().y+ padding) / 2,
7 7
); );
app.getGuiNode().attachChild(settingsContainer); app.getGuiNode().attachChild(buildingPropertyContainer);
} }
/** /**
@@ -118,10 +118,10 @@ public class BuildingPropertyCard extends Dialog {
@Override @Override
public void close() { public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü app.getGuiNode().detachChild(buildingPropertyContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren app.setSettingsMenuOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
} }

View File

@@ -3,14 +3,16 @@ package pp.monopoly.client.gui.popups;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode; import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.*; import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.model.fields.BuildingProperty;
/** /**
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann. * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
@@ -18,13 +20,18 @@ import pp.monopoly.client.MonopolyApp;
public class BuyCard extends Dialog { public class BuyCard extends Dialog {
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground; private final Geometry overlayBackground;
private final Container settingsContainer; private final Container buyCardContainer;
private final Container backgroundContainer; private final Container backgroundContainer;
private int index = 37;
public BuyCard(MonopolyApp app) { public BuyCard(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
//Generate the corresponfing field
BuildingProperty field = (BuildingProperty) app.getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen // Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground(); overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground); app.getGuiNode().attachChild(overlayBackground);
@@ -34,52 +41,55 @@ public class BuyCard extends Dialog {
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer); app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für das Menü // Hauptcontainer für die Gebäudekarte
settingsContainer = new Container(); buyCardContainer = new Container();
settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f))); buyCardContainer.setBackground(new QuadBackgroundComponent(field.getColor().getColor()));
Label settingsTitle = buyCardContainer.addChild(new Label( field.getName(), new ElementId("settings-title")));
// Titel
Label settingsTitle = settingsContainer.addChild(new Label("Gebäude 30", new ElementId("settings-title"))); //TODO Dynamische Gebäudezahl einfügen
settingsTitle.setFontSize(48); settingsTitle.setFontSize(48);
int i = 0; // Text, der auf der Karte steht
int a = 10; // Die Preise werden dynamisch dem BoardManager entnommen
int b = -45; Container propertyValuesContainer = buyCardContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Grundstückswert: " + field.getPrice() + " EUR", new ElementId("label-Text")));
// Effekt-Sound: Slider und Checkbox propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
Container propertyValuesContainer = settingsContainer.addChild(new Container()); propertyValuesContainer.addChild(new Label("„Miete allein: " + field.getAllRent().get(0)+ " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Preis:" + i, new ElementId("label-Text")));//TODO Variable hier einsetzen propertyValuesContainer.addChild(new Label("-mit 1 Haus: " + field.getAllRent().get(1) + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Miete:" + a, new ElementId("label-Text")));//TODO Variable hier einsetzen propertyValuesContainer.addChild(new Label("-mit 2 Häuser: " + field.getAllRent().get(2) + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Hypothek:" + b, new ElementId("label-Text")));//TODO Variable hier einsetzen 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))); propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button // Beenden-Button
Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("button"))); Button quitButton = buyCardContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
// Kaufen-Button // Kaufen-Button
Button buyButton = settingsContainer.addChild(new Button("Kaufen", new ElementId("button"))); Button buyButton = buyCardContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32); buyButton.setFontSize(32);
float padding = 10; // Padding around the settingsContainer for the background float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(buyCardContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü // Zentriere das Menü
settingsContainer.setLocalTranslation( buyCardContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y) / 2,
8 8
); );
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - buyCardContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + buyCardContainer.getPreferredSize().y+ padding) / 2,
7 7
); );
app.getGuiNode().attachChild(settingsContainer); app.getGuiNode().attachChild(buyCardContainer);
} }
/** /**
@@ -104,13 +114,11 @@ public class BuyCard extends Dialog {
@Override @Override
public void close() { public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü app.getGuiNode().detachChild(buyCardContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren app.setSettingsMenuOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
} }
} }

View File

@@ -0,0 +1,118 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.model.card.Card; // TODO für den Import der Queue notwendig
/**
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann.
*/
public class EventCard extends Dialog {
private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container eventCardContainer;
private final Container backgroundContainer;
public EventCard(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
//Generate the corresponfing field
Card card = app.getDeckHelper().drawCard(); // TODO nimmt die Karten gerade unabhängig aus dem DeckHelper
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container();
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für die Gebäudekarte
eventCardContainer = new Container();
eventCardContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
// Titel
// Die Namen werden dynamisch dem BoardManager entnommen
Label gateFieldTitle = eventCardContainer.addChild(new Label("Ereigniskarte", new ElementId("settings-title")));
gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der auf der Karte steht
// Die Preise werden dynamisch dem BoardManager entnommen
Container propertyValuesContainer = eventCardContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label(card.getDescription(), new ElementId("label-Text")));
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
// Beenden-Button
Button quitButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close());
// TODO Kaufen-Button wird nicht mehr benötigt, prüfen ob weg kann
//Button buyButton = buyCardContainer.addChild(new Button("Kaufen", new ElementId("button")));
//buyButton.setFontSize(32);
float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü
eventCardContainer.setLocalTranslation(
(app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y) / 2,
8
);
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - eventCardContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + eventCardContainer.getPreferredSize().y+ padding) / 2,
7
);
app.getGuiNode().attachChild(eventCardContainer);
}
/**
* Erstellt einen halbtransparenten Hintergrund für das Menü.
*
* @return Geometrie des Overlays
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Schließt das Menü und entfernt die GUI-Elemente.
*/
@Override
public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(eventCardContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setBuyCardPopupOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
}
}

View File

@@ -5,7 +5,6 @@ import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
@@ -16,12 +15,12 @@ import pp.monopoly.client.MonopolyApp;
import pp.monopoly.model.fields.FoodField; import pp.monopoly.model.fields.FoodField;
/** /**
* SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann. * FoodFieldCard erstellt die Geböudekarte vom Brandl und der Truppenküche
*/ */
public class FoodFieldCard extends Dialog { public class FoodFieldCard extends Dialog {
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground; private final Geometry overlayBackground;
private final Container settingsContainer; private final Container foodFieldContainer;
private final Container backgroundContainer; private final Container backgroundContainer;
private int index = 12; private int index = 12;
@@ -30,7 +29,7 @@ public class FoodFieldCard extends Dialog {
this.app = app; this.app = app;
//Generate the corresponfing field //Generate the corresponfing field
FoodField field = (FoodField) app.getBoardManager().getFieldAtIndex(index); FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen // Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground(); overlayBackground = createOverlayBackground();
@@ -41,52 +40,63 @@ public class FoodFieldCard extends Dialog {
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer); app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für das Menü // Hauptcontainer für die Gebäudekarte
settingsContainer = new Container(); foodFieldContainer = new Container();
settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f))); foodFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f)));
// Titel // Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe
Label settingsTitle = settingsContainer.addChild(new Label(field.getName(), new ElementId("settings-title"))); Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title")));
settingsTitle.setFontSize(48); settingsTitle.setFontSize(48);
// Effekt-Sound: Slider und Checkbox // Text, der auf der Karte steht
Container propertyValuesContainer = settingsContainer.addChild(new Container()); Container propertyValuesContainer = foodFieldContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text"))); 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("", new ElementId("label-Text"))); // Leerzeile
propertyValuesContainer.addChild(new Label("„Wenn man Besitzer des\n" +field.getName()+" ist, so ist die\nMiete 40-mal so hoch, wie\nAugen auf den zwei Würfeln sind.", new ElementId("label-Text"))); 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("", new ElementId("label-Text"))); // Leerzeile
propertyValuesContainer.addChild(new Label("„Wenn man Besitzer beider \nRestaurants ist, so ist die\nMiete 100-mal so hoch, wie\nAugen auf den zwei Würfeln sind.", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("„Wenn man Besitzer beider", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Restaurants ist, so ist die", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Miete 100-mal so hoch, wie", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("Augen auf den zwei Würfeln sind.", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text"))); // Leerzeile
propertyValuesContainer.addChild(new Label("„Hypothek: " + field.getHypo() + " EUR", 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))); 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 // Beenden-Button
Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("button"))); Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
// Kaufen-Button // Kaufen-Button
Button buyButton = settingsContainer.addChild(new Button("Kaufen", new ElementId("button"))); Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32); buyButton.setFontSize(32);
*/
float padding = 10; // Padding around the settingsContainer for the background float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü // Zentriere das Menü
settingsContainer.setLocalTranslation( foodFieldContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y) / 2,
8 8
); );
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - foodFieldContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + foodFieldContainer.getPreferredSize().y+ padding) / 2,
7 7
); );
app.getGuiNode().attachChild(settingsContainer); app.getGuiNode().attachChild(foodFieldContainer);
} }
/** /**
@@ -111,10 +121,10 @@ public class FoodFieldCard extends Dialog {
@Override @Override
public void close() { public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü app.getGuiNode().detachChild(foodFieldContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren app.setSettingsMenuOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
} }

View File

@@ -5,7 +5,6 @@ import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
@@ -20,16 +19,16 @@ import pp.monopoly.model.fields.GateField;
public class GateFieldCard extends Dialog { public class GateFieldCard extends Dialog {
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground; private final Geometry overlayBackground;
private final Container settingsContainer; private final Container gateFieldContainer;
private final Container backgroundContainer; private final Container backgroundContainer;
private int index; private int index = 5;
public GateFieldCard(MonopolyApp app) { public GateFieldCard(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
//Generate the corresponfing field //Generate the corresponfing field
GateField field = (GateField) app.getBoardManager().getFieldAtIndex(index); GateField field = (GateField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen // Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground(); overlayBackground = createOverlayBackground();
@@ -40,50 +39,58 @@ public class GateFieldCard extends Dialog {
backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background
app.getGuiNode().attachChild(backgroundContainer); app.getGuiNode().attachChild(backgroundContainer);
// Hauptcontainer für das Menü // Hauptcontainer für die Gebäudekarte
settingsContainer = new Container(); gateFieldContainer = new Container();
settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0 / 255f, 0 / 255f, 0 / 255f, 1))); gateFieldContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
// Titel // Titel
Label settingsTitle = settingsContainer.addChild(new Label(field.getName(), new ElementId("settings-title"))); // Die Namen werden dynamisch dem BoardManager entnommen
settingsTitle.setFontSize(48); Label gateFieldTitle = gateFieldContainer.addChild(new Label(field.getName(), new ElementId("settings-title")));
settingsTitle.setColor(ColorRGBA.Black); gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der auf der Karte steht
// Effekt-Sound: Slider und Checkbox // Die Preise werden dynamisch dem BoardManager entnommen
Container propertyValuesContainer = settingsContainer.addChild(new Container()); Container propertyValuesContainer = gateFieldContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("„Preis: " + field.getPrice() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("„Miete:", new ElementId("label-Text")));//TODO Variable hier einsetzen 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.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))); 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 // Beenden-Button
Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("button"))); Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
// Kaufen-Button // Kaufen-Button
Button buyButton = settingsContainer.addChild(new Button("Kaufen", new ElementId("button"))); Button buyButton = foodFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32); buyButton.setFontSize(32);
*/
float padding = 10; // Padding around the settingsContainer for the background float padding = 10; // Padding around the settingsContainer for the background
backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(gateFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
// Zentriere das Menü // Zentriere das Menü
settingsContainer.setLocalTranslation( gateFieldContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2, (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y) / 2,
8 8
); );
backgroundContainer.setLocalTranslation( backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2, (app.getCamera().getWidth() - gateFieldContainer.getPreferredSize().x - padding) / 2,
(app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2, (app.getCamera().getHeight() + gateFieldContainer.getPreferredSize().y+ padding) / 2,
7 7
); );
app.getGuiNode().attachChild(settingsContainer); app.getGuiNode().attachChild(gateFieldContainer);
} }
/** /**
@@ -108,10 +115,10 @@ public class GateFieldCard extends Dialog {
@Override @Override
public void close() { public void close() {
System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe
app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü app.getGuiNode().detachChild(gateFieldContainer); // Entferne das Menü
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay
app.setSettingsMenuOpen(false); // Menü als geschlossen markieren app.setSettingsMenuOpen(false); // Menü als geschlossen markieren TODO passt diese Variable noch (zu finden unter den Temps in MonopolyApp
app.unblockInputs(); // Eingaben wieder aktivieren app.unblockInputs(); // Eingaben wieder aktivieren
System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe
} }

View File

@@ -0,0 +1,52 @@
package pp.monopoly.client.gui.popups;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.IconComponent;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
public class LooserPopUp extends Dialog {
private final MonopolyApp app;
/**
* Constructs a new NetworkDialog.
*
* @param network The NetworkSupport instance to be used for network operations.
*/
public LooserPopUp(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
initializeDialog();
}
/**
* Initializes the dialog with input fields and connection buttons.
*/
private void initializeDialog() {
Container inputContainer = new Container();
// Titel und Eingabefelder für Host und Port
inputContainer.addChild(new Label("Schade, du hast leider verloren!"));
inputContainer.addChild(new Label("Die nächste Runde wird besser!"));
Label imageLabel = new Label("");
IconComponent icon = new IconComponent("Pictures/MonopolyLooser.png"); // Icon mit Textur erstellen
icon.setIconScale(1); // Skalierung des Bildes
imageLabel.setIcon(icon);
// Setze das Icon im Label
inputContainer.addChild(imageLabel);
Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
inputContainer.setLocalTranslation(300, 800, 0);
app.getGuiNode().attachChild(inputContainer);
}
}

View File

@@ -0,0 +1,55 @@
package pp.monopoly.client.gui.popups;
import com.jme3.asset.TextureKey;
import com.jme3.math.Vector2f;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.IconComponent;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
public class LoserPopUp extends Dialog {
private final MonopolyApp app;
/**
* Constructs a new NetworkDialog.
*
* @param network The NetworkSupport instance to be used for network operations.
*/
public LoserPopUp(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
initializeDialog();
}
/**
* Initializes the dialog with input fields and connection buttons.
*/
private void initializeDialog() {
Container inputContainer = new Container();
// Titel und Eingabefelder für Host und Port
inputContainer.addChild(new Label("Schade, du hast leider verloren!"));
inputContainer.addChild(new Label("Die nächste Runde wird besser!"));
Label imageLabel = new Label("");
TextureKey key = new TextureKey("Pictures/MonopolyLoser.png", true);
Texture texture = app.getAssetManager().loadTexture(key);
IconComponent icon = new IconComponent(texture.toString()); // Icon mit Textur erstellen
icon.setIconSize(new Vector2f(155f, 120f)); // Skalierung des Bildes
imageLabel.setIcon(icon); // Setze das Icon im Label
inputContainer.addChild(imageLabel);
Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
inputContainer.setLocalTranslation(300,500,0);
attachChild(inputContainer);
}
}

View File

@@ -0,0 +1,51 @@
package pp.monopoly.client.gui.popups;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.IconComponent;
import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp;
public class WinnerPopUp extends Dialog {
private final MonopolyApp app;
/**
* Constructs a new NetworkDialog.
*
* @param app The NetworkSupport instance to be used for network operations.
*/
public WinnerPopUp(MonopolyApp app) {
super(app.getDialogManager());
this.app = app;
initializeDialog();
}
/**
* Initializes the dialog with input fields and connection buttons.
*/
private void initializeDialog() {
Container inputContainer = new Container();
// Titel und Eingabefelder für Host und Port
inputContainer.addChild(new Label("Herlichen Glückwunsch!"));
inputContainer.addChild(new Label("Du,bist der Monopoly Champion!!!"));
Label imageLabel = new Label("");
IconComponent icon = new IconComponent("Pictures/MonopolyWinner.png"); // Icon mit Textur erstellen
icon.setIconScale(1); // Skalierung des Bildes
imageLabel.setIcon(icon);
// Setze das Icon im Label
inputContainer.addChild(imageLabel);
Button cancelButton = inputContainer.addChild(new Button("Spiel beenden"));
cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp));
inputContainer.setLocalTranslation(300, 800, 0);
app.getGuiNode().attachChild(inputContainer);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

View File

@@ -28,7 +28,7 @@ public class MonopolyConfig extends Config {
* The default port number for the Monopoly server. * The default port number for the Monopoly server.
*/ */
@Property("port") @Property("port")
private int port = 4321; private int port = 42069;
/** /**
* The width of the game map in terms of grid units. * The width of the game map in terms of grid units.

View File

@@ -5,6 +5,7 @@ import java.lang.System.Logger.Level;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.ClientMessage; import pp.monopoly.message.client.ClientMessage;
import pp.monopoly.message.server.BuyPropertyResponse; import pp.monopoly.message.server.BuyPropertyResponse;
import pp.monopoly.message.server.DiceResult; import pp.monopoly.message.server.DiceResult;
@@ -21,6 +22,7 @@ import pp.monopoly.message.server.TradeRequest;
import pp.monopoly.message.server.ViewAssetsResponse; import pp.monopoly.message.server.ViewAssetsResponse;
import pp.monopoly.model.Board; import pp.monopoly.model.Board;
import pp.monopoly.model.IntPoint; import pp.monopoly.model.IntPoint;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.notification.ClientStateEvent; import pp.monopoly.notification.ClientStateEvent;
import pp.monopoly.notification.GameEvent; import pp.monopoly.notification.GameEvent;
import pp.monopoly.notification.GameEventBroker; import pp.monopoly.notification.GameEventBroker;
@@ -50,6 +52,10 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
/** The current state of the client game logic. */ /** The current state of the client game logic. */
private ClientState state = new LobbyState(this); private ClientState state = new LobbyState(this);
private List<Player> players;
private BoardManager boardManager = new BoardManager();
/** /**
* Constructs a ClientGameLogic with the specified sender object. * Constructs a ClientGameLogic with the specified sender object.
* *
@@ -59,6 +65,14 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
this.clientSender = clientSender; this.clientSender = clientSender;
} }
/**
* Reutns the BoardManager
* @return the boardManager
*/
public BoardManager getBoardManager() {
return boardManager;
}
/** /**
* Returns the current state of the game logic. * Returns the current state of the game logic.
* *
@@ -80,6 +94,10 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
state.entry(); state.entry();
} }
public List<Player> getPlayers() {
return players;
}
/** /**
* Returns the player's game board. * Returns the player's game board.
* *
@@ -121,11 +139,12 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
* *
* @param msg the message to be sent * @param msg the message to be sent
*/ */
void send(ClientMessage msg) { public void send(ClientMessage msg) {
if (clientSender == null) { if (clientSender == null) {
LOGGER.log(Level.ERROR, "trying to send {0} with sender==null", msg); //NON-NLS LOGGER.log(Level.ERROR, "trying to send {0} with sender==null", msg); //NON-NLS
} else { } else {
clientSender.send(msg); clientSender.send(msg);
System.out.println("Message gesendet");
} }
} }
@@ -207,7 +226,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
@Override @Override
public void received(EventDrawCard msg) { public void received(EventDrawCard msg) {
setInfoText("Event card drawn: " + msg.getCardDescription()); setInfoText("Event card drawn: " + msg.getCardDescription());
//event card logic // Kartenlogik
playSound(Sound.EVENT_CARD); playSound(Sound.EVENT_CARD);
} }
@@ -236,6 +255,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
*/ */
@Override @Override
public void received(GameStart msg) { public void received(GameStart msg) {
players = msg.getPlayers();
setInfoText("The game has started! Good luck!"); setInfoText("The game has started! Good luck!");
setState(new WaitForTurnState(this)); setState(new WaitForTurnState(this));
} }

View File

@@ -10,11 +10,12 @@ package pp.monopoly.game.server;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.message.server.DiceResult; import pp.monopoly.message.server.DiceResult;
import pp.monopoly.model.FieldVisitor; import pp.monopoly.model.FieldVisitor;
import pp.monopoly.model.Figure; import pp.monopoly.model.Figure;
import pp.monopoly.model.IntPoint; import pp.monopoly.model.card.Card;
import pp.monopoly.model.card.DeckHelper;
import pp.monopoly.model.fields.BuildingProperty; import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.EventField; import pp.monopoly.model.fields.EventField;
import pp.monopoly.model.fields.FineField; import pp.monopoly.model.fields.FineField;
@@ -29,6 +30,7 @@ import pp.monopoly.model.fields.WacheField;
/** /**
* Class representing a player * Class representing a player
*/ */
@Serializable
public class Player implements FieldVisitor<Void>{ public class Player implements FieldVisitor<Void>{
private final int id; private final int id;
private String name; private String name;
@@ -41,6 +43,14 @@ public class Player implements FieldVisitor<Void>{
private final PlayerHandler handler; private final PlayerHandler handler;
private PlayerState state = new LobbyState(); private PlayerState state = new LobbyState();
/**
* Default constructor for serialization purposes.
*/
private Player(){
id = 0;
handler = null;
}
/** /**
* Constructs a player with the speciefied params * Constructs a player with the speciefied params
* @param id the id of the player * @param id the id of the player
@@ -85,10 +95,18 @@ public class Player implements FieldVisitor<Void>{
* Set the name of the Player * Set the name of the Player
* @param name the new name * @param name the new name
*/ */
void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
/**
* Retuns the Playerhandler
* @return the Playerhandler
*/
public PlayerHandler getHandler() {
return handler;
}
/** /**
* Returns this players id * Returns this players id
* @return th eid of this player * @return th eid of this player
@@ -104,6 +122,21 @@ public class Player implements FieldVisitor<Void>{
public int getFieldID() { public int getFieldID() {
return fieldID; 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 * Moves by the specified amount of steps
@@ -146,6 +179,7 @@ public class Player implements FieldVisitor<Void>{
public void buyProperty(PropertyField property) { public void buyProperty(PropertyField property) {
if (property.getOwner() == null && accountBalance >= property.getPrice()) { if (property.getOwner() == null && accountBalance >= property.getPrice()) {
properties.add(property); properties.add(property);
property.setOwner(this);
pay(property.getPrice()); pay(property.getPrice());
} }
} }
@@ -284,7 +318,8 @@ public class Player implements FieldVisitor<Void>{
@Override @Override
public Void visit(EventField field) { public Void visit(EventField field) {
DeckHelper.drawCard(); Card c = getHandler().getLogic().getDeckHelper().drawCard();
getHandler().getLogic().getDeckHelper().visit(c, this);
return null; return null;
} }
@@ -327,6 +362,26 @@ public class Player implements FieldVisitor<Void>{
return count; 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. * Inner class for dice functionality in the game.
* Rolls random dice values. * Rolls random dice values.
@@ -460,47 +515,19 @@ public class Player implements FieldVisitor<Void>{
} }
} }
private class BankruptState implements PlayerState {
@Override
public DiceResult rollDice() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'rollDice'");
}
@Override
public void payBail() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'payBail'");
}
@Override
public void useJailCard() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'useJailCard'");
}
}
private class WaitForTurnState implements PlayerState { private class WaitForTurnState implements PlayerState {
@Override @Override
public DiceResult rollDice() { public DiceResult rollDice() {
// TODO Auto-generated method stub throw new UnsupportedOperationException("not allowed");
throw new UnsupportedOperationException("Unimplemented method 'rollDice'");
} }
@Override @Override
public void payBail() { public void payBail() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'payBail'");
} }
@Override @Override
public void useJailCard() { public void useJailCard() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'useJailCard'");
} }
} }

View File

@@ -8,15 +8,24 @@ import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.model.LimitedLinkedList; import pp.monopoly.model.LimitedLinkedList;
/** /**
* A class for helping with player actions and managing thier turns * A class for helping with player actions and managing thier turns
*/ */
@Serializable
public class PlayerHandler { public class PlayerHandler {
private List<Player> players = new LimitedLinkedList<>(6); private List<Player> players = new LimitedLinkedList<>(6);
private Set<Player> readyPlayers = new HashSet<>(); private Set<Player> readyPlayers = new HashSet<>();
private ServerGameLogic logic; private ServerGameLogic logic;
private Player hostPlayer; private Player hostPlayer;
private Player extra = null;
/**
* Default constructor for serialization purposes.
*/
private PlayerHandler() {}
/** /**
* Contructs a PlayerHandler * Contructs a PlayerHandler
@@ -131,8 +140,13 @@ public class PlayerHandler {
* Completes a player turn and return the next player * Completes a player turn and return the next player
* @return the next players who is active * @return the next players who is active
*/ */
Player nextPlayer() { public Player nextPlayer() {
Player tmp = players.get(0); Player tmp = players.get(0);
if (extra != null) {
tmp = extra;
extra = null;
return tmp;
}
players.remove(0); players.remove(0);
players.add(tmp); players.add(tmp);
return players.get(0); return players.get(0);
@@ -142,7 +156,7 @@ public class PlayerHandler {
* Returns the {@link ServerGameLogic} of this PlayerHandler * Returns the {@link ServerGameLogic} of this PlayerHandler
* @return the {@link ServerGameLogic} of this PlayerHandler * @return the {@link ServerGameLogic} of this PlayerHandler
*/ */
ServerGameLogic getLogic() { public ServerGameLogic getLogic() {
return logic; return logic;
} }
@@ -151,7 +165,7 @@ public class PlayerHandler {
* @param id the id to be searched for * @param id the id to be searched for
* @return the player with the required id * @return the player with the required id
*/ */
Player getPlayerById(int id) { public Player getPlayerById(int id) {
for (Player player : players) { for (Player player : players) {
if (player.getId() == id) return player; if (player.getId() == id) return player;
} }
@@ -159,15 +173,24 @@ public class PlayerHandler {
} }
/** /**
* Arranges the players turns in a random order * Arranges the players turns in a random order.
* Shuffles the players and sets their state to WaitForNextTurn, the first one will be active
*/ */
void randomOrder() { void randomOrder() {
Collections.shuffle(players); Collections.shuffle(players);
for (Player player : players) {
player.finishTurn();
}
players.get(0).setActive();
} }
void setStartBalance(int amount) { public void setStartBalance(int amount) {
for (Player player : players) { for (Player player : players) {
player.setAccountBalance(amount); player.setAccountBalance(amount);
} }
} }
public void extraTurn(Player player) {
if (players.contains(player)) extra = player;
}
} }

View File

@@ -22,6 +22,7 @@ import pp.monopoly.message.server.ViewAssetsResponse;
import pp.monopoly.model.Board; import pp.monopoly.model.Board;
import pp.monopoly.model.Figure; import pp.monopoly.model.Figure;
import pp.monopoly.model.Rotation; import pp.monopoly.model.Rotation;
import pp.monopoly.model.card.DeckHelper;
import pp.monopoly.model.fields.BoardManager; import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.PropertyField;
@@ -38,6 +39,7 @@ public class ServerGameLogic implements ClientInterpreter {
private ServerState state = ServerState.LOBBY; private ServerState state = ServerState.LOBBY;
private static final int MAX_PLAYERS = 6; private static final int MAX_PLAYERS = 6;
private BoardManager boardManager = new BoardManager(); private BoardManager boardManager = new BoardManager();
private final DeckHelper deckHelper = new DeckHelper();
private int startMoney; private int startMoney;
/** /**
@@ -169,11 +171,14 @@ public class ServerGameLogic implements ClientInterpreter {
public void received(EndTurn msg, int from) { public void received(EndTurn msg, int from) {
Player player = playerHandler.getPlayerById(from); Player player = playerHandler.getPlayerById(from);
if (player != null && state == ServerState.INGAME) { if (player != null && state == ServerState.INGAME) {
if (player.finishTurn()) {
LOGGER.log(Level.DEBUG, "Ending turn for player {0}", player.getName()); LOGGER.log(Level.DEBUG, "Ending turn for player {0}", player.getName());
Player next = playerHandler.nextPlayer(); Player next = playerHandler.nextPlayer();
next.setActive();
send(next, new NextPlayerTurn(next)); send(next, new NextPlayerTurn(next));
} }
} }
}
/** /**
* Handles a PlayerReady message, marking the player as ready. * Handles a PlayerReady message, marking the player as ready.
@@ -283,4 +288,8 @@ public class ServerGameLogic implements ClientInterpreter {
public Player getPlayerById(int id) { public Player getPlayerById(int id) {
return playerHandler.getPlayerById(id); return playerHandler.getPlayerById(id);
} }
public DeckHelper getDeckHelper() {
return deckHelper;
}
} }

View File

@@ -1,11 +1,19 @@
package pp.monopoly.message.client; package pp.monopoly.message.client;
import com.jme3.network.serializing.Serializable;
/** /**
* Represents a request from a player to buy a property. * Represents a request from a player to buy a property.
*/ */
@Serializable
public class BuyPropertyRequest extends ClientMessage{ public class BuyPropertyRequest extends ClientMessage{
private int propertyId; private int propertyId;
/**
* Default constructor for serialization purposes.
*/
private BuyPropertyRequest() { /* empty */ }
/** /**
* Constructs a BuyPropertyRequest with the specified property ID. * Constructs a BuyPropertyRequest with the specified property ID.
* *

View File

@@ -1,9 +1,18 @@
package pp.monopoly.message.client; package pp.monopoly.message.client;
import com.jme3.network.serializing.Serializable;
/** /**
* Represents a message indicating the player wants to end their turn. * Represents a message indicating the player wants to end their turn.
*/ */
@Serializable
public class EndTurn extends ClientMessage{ public class EndTurn extends ClientMessage{
/**
* Default constructor for serialization purposes.
*/
public EndTurn() { /* empty */ }
@Override @Override
public void accept(ClientInterpreter interpreter, int from) { public void accept(ClientInterpreter interpreter, int from) {
interpreter.received(this, from); interpreter.received(this, from);

View File

@@ -1,13 +1,21 @@
package pp.monopoly.message.client; package pp.monopoly.message.client;
import com.jme3.network.serializing.Serializable;
/** /**
* Represents a message indicating the player is ready to play. * Represents a message indicating the player is ready to play.
*/ */
@Serializable
public class PlayerReady extends ClientMessage { public class PlayerReady extends ClientMessage {
private final boolean isReady; private boolean isReady;
private final String name; private String name;
private final String figure; private String figure;
private final int startMoney; private int startMoney;
/**
* Default constructor for serialization purposes.
*/
private PlayerReady() { /* empty */ }
/** /**
* Constructs a PlayerReady message. * Constructs a PlayerReady message.

View File

@@ -1,9 +1,18 @@
package pp.monopoly.message.client; package pp.monopoly.message.client;
import com.jme3.network.serializing.Serializable;
/** /**
* Represents a message requesting to roll the dice. * Represents a message requesting to roll the dice.
*/ */
@Serializable
public class RollDice extends ClientMessage{ public class RollDice extends ClientMessage{
/**
* Default constructor for serialization purposes.
*/
private RollDice() { /* empty */ }
@Override @Override
public void accept(ClientInterpreter interpreter, int from) { public void accept(ClientInterpreter interpreter, int from) {
interpreter.received(this, from); interpreter.received(this, from);

View File

@@ -1,14 +1,21 @@
package pp.monopoly.message.client; package pp.monopoly.message.client;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.model.TradeHandler; import pp.monopoly.model.TradeHandler;
/** /**
* Represents a trade Request message from one player to another. * Represents a trade Request message from one player to another.
*/ */
@Serializable
public class TradeOffer extends ClientMessage{ public class TradeOffer extends ClientMessage{
private int receiverId; private int receiverId;
private TradeHandler tradehandler; private TradeHandler tradehandler;
/**
* Default constructor for serialization purposes.
*/
private TradeOffer() { /* empty */ }
/** /**
* Constructs a TradeOffer with the specified details. * Constructs a TradeOffer with the specified details.

View File

@@ -1,14 +1,22 @@
package pp.monopoly.message.client; package pp.monopoly.message.client;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.model.TradeHandler; import pp.monopoly.model.TradeHandler;
/** /**
* Represents a response to a trade offer. * Represents a response to a trade offer.
*/ */
@Serializable
public class TradeResponse extends ClientMessage{ public class TradeResponse extends ClientMessage{
private int initiatorId; private int initiatorId;
private TradeHandler tradeHandler; private TradeHandler tradeHandler;
/**
* Default constructor for serialization purposes.
*/
private TradeResponse() { /* empty */ }
/** /**
* Constructs a TradeResponse with the specified response details. * Constructs a TradeResponse with the specified response details.
* *

View File

@@ -1,13 +1,21 @@
package pp.monopoly.message.client; package pp.monopoly.message.client;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
/** /**
* Represents a request from a player to view their assets. * Represents a request from a player to view their assets.
*/ */
@Serializable
public class ViewAssetsRequest extends ClientMessage{ public class ViewAssetsRequest extends ClientMessage{
private final Player player; private Player player;
/**
* Default constructor for serialization purposes.
*/
private ViewAssetsRequest() { /* empty */ }
public ViewAssetsRequest(Player player) { public ViewAssetsRequest(Player player) {
this.player = player; this.player = player;

View File

@@ -1,12 +1,20 @@
package pp.monopoly.message.server; package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
/** /**
* Represents the server's response to a player's request to buy a property. * Represents the server's response to a player's request to buy a property.
*/ */
@Serializable
public class BuyPropertyResponse extends ServerMessage{ public class BuyPropertyResponse extends ServerMessage{
private final boolean successful; private boolean successful;
private final String propertyName; private String propertyName;
private final String reason; // Reason for failure, if any private String reason; // Reason for failure, if any
/**
* Default constructor for serialization purposes.
*/
private BuyPropertyResponse() { /* empty */ }
public BuyPropertyResponse(boolean successful, String propertyName, String reason) { public BuyPropertyResponse(boolean successful, String propertyName, String reason) {
this.successful = successful; this.successful = successful;

View File

@@ -2,10 +2,18 @@ package pp.monopoly.message.server;
import java.util.List; import java.util.List;
import com.jme3.network.serializing.Serializable;
@Serializable
public class DiceResult extends ServerMessage{ public class DiceResult extends ServerMessage{
private List<Integer> rollResult; private List<Integer> rollResult;
/**
* Default constructor for serialization purposes.
*/
private DiceResult() { /* empty */ }
public DiceResult(List<Integer> rollResult) { public DiceResult(List<Integer> rollResult) {
this.rollResult = rollResult; this.rollResult = rollResult;
} }

View File

@@ -1,7 +1,15 @@
package pp.monopoly.message.server; package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
@Serializable
public class EventDrawCard extends ServerMessage{ public class EventDrawCard extends ServerMessage{
private final String cardDescription; private String cardDescription;
/**
* Default constructor for serialization purposes.
*/
private EventDrawCard() { /* empty */ }
public EventDrawCard(String cardDescription) { public EventDrawCard(String cardDescription) {
this.cardDescription = cardDescription; this.cardDescription = cardDescription;

View File

@@ -1,7 +1,15 @@
package pp.monopoly.message.server; package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
@Serializable
public class GameOver extends ServerMessage{ public class GameOver extends ServerMessage{
private final boolean isWinner; private boolean isWinner;
/**
* Default constructor for serialization purposes.
*/
private GameOver() { /* empty */ }
public GameOver(boolean isWinner) { public GameOver(boolean isWinner) {
this.isWinner = isWinner; this.isWinner = isWinner;

View File

@@ -2,11 +2,19 @@ package pp.monopoly.message.server;
import java.util.List; import java.util.List;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
@Serializable
public class GameStart extends ServerMessage{ public class GameStart extends ServerMessage{
private final List<Player> players; private List<Player> players;
/**
* Default constructor for serialization purposes.
*/
private GameStart() { /* empty */ }
public GameStart(List<Player> players) { public GameStart(List<Player> players) {
this.players = players; this.players = players;

View File

@@ -1,8 +1,16 @@
package pp.monopoly.message.server; package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
@Serializable
public class JailEvent extends ServerMessage{ public class JailEvent extends ServerMessage{
private final boolean goingToJail; private boolean goingToJail;
/**
* Default constructor for serialization purposes.
*/
private JailEvent() { /* empty */ }
public JailEvent(boolean goingToJail) { public JailEvent(boolean goingToJail) {
this.goingToJail = goingToJail; this.goingToJail = goingToJail;

View File

@@ -1,10 +1,18 @@
package pp.monopoly.message.server; package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
@Serializable
public class NextPlayerTurn extends ServerMessage{ public class NextPlayerTurn extends ServerMessage{
private final Player player; private Player player;
/**
* Default constructor for serialization purposes.
*/
private NextPlayerTurn() { /* empty */ }
public NextPlayerTurn(Player player) { public NextPlayerTurn(Player player) {
this.player = player; this.player = player;

View File

@@ -1,12 +1,20 @@
package pp.monopoly.message.server; package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.game.server.PlayerColor; import pp.monopoly.game.server.PlayerColor;
@Serializable
public class PlayerStatusUpdate extends ServerMessage{ public class PlayerStatusUpdate extends ServerMessage{
private final String playerName; private String playerName;
private final String status; private String status;
private final PlayerColor color; private PlayerColor color;
/**
* Default constructor for serialization purposes.
*/
private PlayerStatusUpdate() { /* empty */ }
public PlayerStatusUpdate(String playerName, String status, PlayerColor color) { public PlayerStatusUpdate(String playerName, String status, PlayerColor color) {
this.playerName = playerName; this.playerName = playerName;

View File

@@ -1,8 +1,16 @@
package pp.monopoly.message.server; package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
@Serializable
public class TimeOutWarning extends ServerMessage{ public class TimeOutWarning extends ServerMessage{
private final int remainingTime; private int remainingTime;
/**
* Default constructor for serialization purposes.
*/
private TimeOutWarning() { /* empty */ }
public TimeOutWarning(int remainingTime) { public TimeOutWarning(int remainingTime) {
this.remainingTime = remainingTime; this.remainingTime = remainingTime;

View File

@@ -1,14 +1,22 @@
package pp.monopoly.message.server; package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.model.TradeHandler; import pp.monopoly.model.TradeHandler;
/** /**
* Represents a response to a trade offer. * Represents a response to a trade offer.
*/ */
@Serializable
public class TradeReply extends ServerMessage{ public class TradeReply extends ServerMessage{
private int initiatorId; private int initiatorId;
private TradeHandler tradeHandler; private TradeHandler tradeHandler;
/**
* Default constructor for serialization purposes.
*/
private TradeReply() { /* empty */ }
/** /**
* Constructs a TradeResponse with the specified response details. * Constructs a TradeResponse with the specified response details.
* *

View File

@@ -1,15 +1,23 @@
package pp.monopoly.message.server; package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.model.TradeHandler; import pp.monopoly.model.TradeHandler;
/** /**
* Represents a trade Request message from one player to another. * Represents a trade Request message from one player to another.
*/ */
@Serializable
public class TradeRequest extends ServerMessage{ public class TradeRequest extends ServerMessage{
private int receiverId; private int receiverId;
private TradeHandler tradehandler; private TradeHandler tradehandler;
/**
* Default constructor for serialization purposes.
*/
private TradeRequest() { /* empty */ }
/** /**
* Constructs a TradeRequest with the specified details. * Constructs a TradeRequest with the specified details.
* *

View File

@@ -2,18 +2,26 @@ package pp.monopoly.message.server;
import java.util.List; import java.util.List;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.model.fields.BoardManager; import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.PropertyField;
/** /**
* Represents a response containing the player's assets. * Represents a response containing the player's assets.
*/ */
@Serializable
public class ViewAssetsResponse extends ServerMessage{ public class ViewAssetsResponse extends ServerMessage{
private final List<PropertyField> properties; private List<PropertyField> properties;
private final BoardManager board; private BoardManager board;
private final int accountBalance; private int accountBalance;
private final int jailCards; private int jailCards;
/**
* Default constructor for serialization purposes.
*/
private ViewAssetsResponse() { /* empty */ }
/** /**
* Constructs a ViewAssetsResponse with the specified properties and account balance. * Constructs a ViewAssetsResponse with the specified properties and account balance.

View File

@@ -1,7 +0,0 @@
package pp.monopoly.model;
import pp.monopoly.model.card.Card;
public interface CardVisitor<T> {
T visit(Card c);
}

View File

@@ -4,9 +4,12 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import com.jme3.network.serializing.Serializable;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.Math.min; import static java.lang.Math.min;
@Serializable
public class Figure implements Item{ public class Figure implements Item{
private final String type; private final String type;
private final int length; // The length of the Figure private final int length; // The length of the Figure

View File

@@ -2,14 +2,22 @@ package pp.monopoly.model;
import java.util.LinkedList; import java.util.LinkedList;
import com.jme3.network.serializing.Serializable;
/** /**
* A LinkedList with a maximum size limit. * A LinkedList with a maximum size limit.
* *
* @param <E> the type of elements held in this collection * @param <E> the type of elements held in this collection
*/ */
@Serializable
public class LimitedLinkedList<E> extends LinkedList<E> { public class LimitedLinkedList<E> extends LinkedList<E> {
private final int maxSize; private int maxSize;
/**
* Default constructor for serialization purposes.
*/
private LimitedLinkedList() {}
/** /**
* Constructs a LimitedLinkedList with the specified maximum size. * Constructs a LimitedLinkedList with the specified maximum size.

View File

@@ -1,5 +1,7 @@
package pp.monopoly.model.card; package pp.monopoly.model.card;
import pp.monopoly.game.server.Player;
public class Card { public class Card {
private final String description; private final String description;
private final String keyword; private final String keyword;
@@ -9,13 +11,13 @@ public class Card {
this.keyword = keyword; this.keyword = keyword;
} }
public void accept(DeckHelper visitor) { public void accept(DeckHelper visitor, Player player) {
visitor.visit(this); visitor.visit(this, player);
} }
String getDescription() { public String getDescription() {
return description; return description;
} } // TODO wird gerade in der EventCard zur erstellung des Popup genutzt
String getKeyword() { String getKeyword() {
return keyword; return keyword;

View File

@@ -2,24 +2,317 @@ package pp.monopoly.model.card;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import pp.monopoly.model.CardVisitor; import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.EndTurn;
public class DeckHelper implements CardVisitor<Void>{ public class DeckHelper{
private static Queue<Card> cards; private Queue<Card> cards;
private List<Card> drawn = new ArrayList<>();
private DeckHelper() {
public DeckHelper() {
cards = new LinkedList<Card>();
cards.add(new Card("Du wurdest mit einem Dienst KFZ geblitzt. Zahle: 800€", "dienst-kfz-blitzer"));
cards.add(new Card("Die erste Spoparty steht bevor. Ziehe vor zum 23er.", "spoparty"));
cards.add(new Card("Du kommst aus dem Gulak frei.", "gulak-frei-1"));
cards.add(new Card("Du kommst aus dem Gulak frei.", "gulak-frei-2"));
cards.add(new Card("Du hast den Dienstführerschein bestanden. Ziehe vor bis Teststrecke.", "dienstfuehrerschein"));
cards.add(new Card("Malkmus läd zum Pubquiz ein. Rücke vor bis zum 20er.", "pubquiz"));
cards.add(new Card("Du warst ohne Namensschild in der Truppenküche. Rücke vor zum 10er. Gehe nicht über Monatsgehalt. Ziehe keine 2000x€ ein.", "namensschild-truppenkueche"));
cards.add(new Card("Du hast heute die Spendierhosen an und gibst eine Runde in der Unibar. Zahle jedem Spieler: 400€", "spendierhosen-unibar"));
cards.add(new Card("Du warst in der Prüfungsphase krank. Gehe 3 Felder zurück.", "pruefungsphase-krank"));
cards.add(new Card("Ziehe vor bis zum nächsten Monatsgehalt.", "naechstes-monatsgehalt"));
cards.add(new Card("Du hast ein Antreten verschlafen. Zahle: 500€", "antreten-verschlafen-1"));
cards.add(new Card("Du hast den Maibock organisiert. Du erhältst: 3000€", "maibock-organisiert"));
cards.add(new Card("Der Spieß macht eine unangekündigte Inventur. Zahle für jedes Haus: 400€ und jedes Hotel: 2800€", "inventur-haeuser-hotels"));
cards.add(new Card("Es gab keine Mozzarella Bällchen mehr für Thoma. Alle Spieler ziehen vor auf Gym.", "dienstsport-gym"));
cards.add(new Card("Auf deiner Stube wurde Schimmel gefunden. Gehe ins Gulak. Begib Dich direkt dorthin. Gehe nicht über Monatsgehalt. Ziehe nicht ein.", "schimmel-gulak"));
cards.add(new Card("Deine Stube ist nach einer Partynacht nicht mehr bewohnbar. Du ziehst ins Gulak. Begib Dich direkt dorthin. Gehe nicht über Monatsgehalt. Ziehe nicht ein.", "partynacht-gulak"));
cards.add(new Card("Das Jahresabschlussantreten steht an. Ziehe vor bis Schwimmhalle.", "jahresabschlussantreten"));
cards.add(new Card("Du wurdest beim Verkaufen von Versicherungen erwischt. Zahle: 4000€", "verkaufen-versicherungen"));
cards.add(new Card("Du musstest einen Rückstuferantrag stellen. Setze eine Runde aus.", "rueckstuferantrag"));
cards.add(new Card("Auf einer Hausfeier bist du betrunken auf der Treppe gestürzt und dabei auf einen Kameraden gefallen. Zahle: 800€ und gehe zurück zu SanZ.", "hausfeier-sturz"));
cards.add(new Card("Beförderung. Beim nächsten Monatsgehalt ziehst du ein: 3000€", "befoerderung"));
cards.add(new Card("Du entscheidest dich für eine Dienstreise nach Lourd. Zahle: 1000€ und setze eine Runde aus.", "dienstreise-lourd"));
cards.add(new Card("Du warst fleißig Blutspenden und erhältst einen Tag Sonderurlaub. Du bist nochmal an der Reihe.", "blutspenden-sonderurlaub"));
cards.add(new Card("Dir wurde auf dem Oktoberfest dein Geldbeutel geklaut. Gebe 10% deines Vermögens ab.", "geldbeutel-oktoberfest"));
cards.add(new Card("Du wirst von deinem Chef für vorbildliches Verhalten gelobt. Du erhältst: 4000€", "lob-chef"));
cards.add(new Card("Deine Bekanntschaft von letzter Nacht war eine Spo. Lasse dich testen und zahle: 200€", "spo-testen"));
cards.add(new Card("Du wurdest von Kranz geexmattet. Gehe zurück zu Prüfungsamt.", "kranz-exmatrikulation"));
cards.add(new Card("Die letzte Party ist ein wenig eskaliert. Setze eine Runde aus.", "party-eskaliert"));
cards.add(new Card("Du wurdest zur VP gewählt und schmeißt eine Einstandsparty. Zahle: 800€", "vp-einstandsparty"));
cards.add(new Card("Du hast eine Party veranstaltet und dick Gewinn gemacht. Ziehe ein: 1500€", "party-gewinn"));
cards.add(new Card("Zur falschen Zeit am falschen Ort. Du musst einen Bergmarsch planen und setzt eine Runde aus.", "bergmarsch"));
cards.add(new Card("Dein Jodel eines Eispenis mit Unterhodenbeleuchtung geht viral. Ziehe ein: 1000€", "jodel-eispenis"));
} }
@Override public void visit(Card card, Player player) {
public Void visit(Card c) { switch (card.getKeyword()) {
// TODO Auto-generated method stub case "dienst-kfz-blitzer":
throw new UnsupportedOperationException("Unimplemented method 'visit'"); 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;
} }
}
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() { private void shuffle() {
List<Card> cardList = new ArrayList<>(cards); List<Card> cardList = new ArrayList<>(cards);
@@ -28,7 +321,13 @@ public class DeckHelper implements CardVisitor<Void>{
cards.addAll(cardList); cards.addAll(cardList);
} }
public static Card drawCard() { public Card drawCard() {
return cards != null ? cards.poll() : null; if (cards.isEmpty()) {
drawn.forEach(cards::add);
shuffle();
}
Card card = cards.poll();
drawn.add(card);
return card;
} }
} }

View File

@@ -98,4 +98,12 @@ public class BuildingProperty extends PropertyField {
public int getHousePrice() { public int getHousePrice() {
return housePrice; return housePrice;
} }
public int getHouses() {
return houses;
}
public int getHotel() {
return hotel ? 1:0;
}
} }

View File

@@ -2,8 +2,6 @@ package pp.monopoly.model.fields;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
import pp.monopoly.model.card.Card;
import pp.monopoly.model.card.DeckHelper;
public class EventField extends Field{ public class EventField extends Field{
@@ -15,9 +13,4 @@ public class EventField extends Field{
public void accept(Player player) { public void accept(Player player) {
player.visit(this); player.visit(this);
} }
public Card drawCard() {
return DeckHelper.drawCard();
}
} }

View File

@@ -26,11 +26,23 @@ import com.jme3.network.serializing.Serializer;
import pp.monopoly.MonopolyConfig; import pp.monopoly.MonopolyConfig;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
import pp.monopoly.game.server.PlayerHandler;
import pp.monopoly.game.server.ServerGameLogic; import pp.monopoly.game.server.ServerGameLogic;
import pp.monopoly.game.server.ServerSender; import pp.monopoly.game.server.ServerSender;
import pp.monopoly.message.client.BuyPropertyRequest;
import pp.monopoly.message.client.ClientMessage; import pp.monopoly.message.client.ClientMessage;
import pp.monopoly.message.client.EndTurn;
import pp.monopoly.message.client.PlayerReady;
import pp.monopoly.message.client.RollDice;
import pp.monopoly.message.client.TradeOffer;
import pp.monopoly.message.client.TradeResponse;
import pp.monopoly.message.client.ViewAssetsRequest;
import pp.monopoly.message.server.GameStart;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.ServerMessage; import pp.monopoly.message.server.ServerMessage;
import pp.monopoly.model.Figure;
import pp.monopoly.model.IntPoint; import pp.monopoly.model.IntPoint;
import pp.monopoly.model.LimitedLinkedList;
/** /**
* Server implementing the visitor pattern as MessageReceiver for ClientMessages * Server implementing the visitor pattern as MessageReceiver for ClientMessages
@@ -105,14 +117,35 @@ public class MonopolyServer implements MessageListener<HostedConnection>, Connec
private void initializeSerializables() { private void initializeSerializables() {
Serializer.registerClass(IntPoint.class); Serializer.registerClass(IntPoint.class);
Serializer.registerClass(BuyPropertyRequest.class);
Serializer.registerClass(EndTurn.class);
Serializer.registerClass(PlayerReady.class);
Serializer.registerClass(RollDice.class);
Serializer.registerClass(TradeOffer.class);
Serializer.registerClass(TradeResponse.class);
Serializer.registerClass(ViewAssetsRequest.class);
Serializer.registerClass(GameStart.class);
Serializer.registerClass(LimitedLinkedList.class);
Serializer.registerClass(NextPlayerTurn.class);
Serializer.registerClass(Player.class);
Serializer.registerClass(Figure.class);
Serializer.registerClass(PlayerHandler.class);
} }
private void registerListeners() { private void registerListeners() {
myServer.addMessageListener(this, BuyPropertyRequest.class);
myServer.addMessageListener(this, EndTurn.class);
myServer.addMessageListener(this, PlayerReady.class);
myServer.addMessageListener(this, RollDice.class);
myServer.addMessageListener(this, TradeOffer.class);
myServer.addMessageListener(this, TradeResponse.class);
myServer.addMessageListener(this, ViewAssetsRequest.class);
myServer.addConnectionListener(this); myServer.addConnectionListener(this);
} }
@Override @Override
public void messageReceived(HostedConnection source, Message message) { public void messageReceived(HostedConnection source, Message message) {
System.out.println("Message recieved");
LOGGER.log(Level.INFO, "message received from {0}: {1}", source.getId(), message); //NON-NLS LOGGER.log(Level.INFO, "message received from {0}: {1}", source.getId(), message); //NON-NLS
if (message instanceof ClientMessage clientMessage) if (message instanceof ClientMessage clientMessage)
pendingMessages.add(new ReceivedMessage(clientMessage, source.getId())); pendingMessages.add(new ReceivedMessage(clientMessage, source.getId()));