111 Commits

Author SHA1 Message Date
Johannes Schmelz
159927e52c now able to add all nessecary models 2024-12-08 02:16:40 +01:00
Johannes Schmelz
8614faf940 show popups 2024-12-07 22:11:31 +01:00
Johannes Schmelz
4ba43602fa player now moves without animation 2024-12-07 21:58:26 +01:00
Johannes Schmelz
b4e2beca3a frist working version, TODO: trigger the render events 2024-12-07 01:13:17 +01:00
Simon Wilkening
5f4c6be7b8 adjusted test in ReceivedRent 2024-12-06 17:04:00 +01:00
Johannes Schmelz
aca92cd7f1 clean up 2024-12-06 16:21:12 +01:00
Johannes Schmelz
b50b5e64d1 can only trade fields without buildings 2024-12-06 16:06:40 +01:00
Johannes Schmelz
551786bf30 fixed enabled pref in GameMusic 2024-12-06 15:56:42 +01:00
Simon Wilkening
2aca94100e adjusted test in ReceivedRent 2024-12-06 13:20:40 +01:00
Simon Wilkening
9e81fb8549 TopDialog in Propertyoverview eingefügt 2024-12-06 13:17:57 +01:00
Simon Wilkening
3c6e519e77 Rent/ReceivedRent text changed 2024-12-06 13:12:56 +01:00
Simon Wilkening
9be00ab848 renamed IgfPadubrin and Rent/ReceivedRent 2024-12-06 12:35:57 +01:00
Simon Wilkening
c2c22f9ae5 NoMoneywarning and TimeOut use Dialogmanager now 2024-12-06 11:57:20 +01:00
Johannes Schmelz
e65c2661f7 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-05 02:48:00 +01:00
Johannes Schmelz
88db193b5e choose your charakter 2024-12-05 02:47:55 +01:00
Yvonne Schmidt
38824895bb set new toolbar background 2024-12-05 02:05:47 +01:00
Johannes Schmelz
a78261594d ImageButton for new Button design 2024-12-05 01:43:01 +01:00
Yvonne Schmidt
646d301554 added toolbar icons 2024-12-05 01:16:06 +01:00
Johannes Schmelz
e49b22c022 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-04 18:51:19 +01:00
Luca Puderbach
8821602728 kamera 2024-12-04 16:44:26 +01:00
Luca Puderbach
eb19e290bb Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-04 16:39:37 +01:00
Luca Puderbach
b477077b9b Kamera Teil1 2024-12-04 16:39:32 +01:00
Yvonne Schmidt
02cfc1d21a fixed formating errors 2024-12-04 16:00:24 +01:00
Yvonne Schmidt
4c40b447a5 fixed formating errors 2024-12-04 12:16:04 +01:00
Yvonne Schmidt
eaff7b6c5d fixed formating error in RejectTrade 2024-12-04 01:52:30 +01:00
Yvonne Schmidt
9ee1b5b81b simplified representation of trade 2024-12-04 01:48:18 +01:00
Yvonne Schmidt
49b9972ade replaced textinput with dynamic label 2024-12-04 01:10:12 +01:00
Johannes Schmelz
aae003823d trigger money sounds 2024-12-03 12:34:56 +01:00
Johannes Schmelz
1369de865a can no longer build if already has hotel 2024-12-03 12:30:34 +01:00
Johannes Schmelz
8e3cf9c31e now allowed to roll dice after getting out of jail 2024-12-03 12:24:55 +01:00
Johannes Schmelz
bc31c61fb3 bigger hack 2024-12-03 12:24:25 +01:00
Johannes Schmelz
975e4a2737 gym card text 2024-12-03 12:16:03 +01:00
Johannes Schmelz
8d638158e4 fixed Miete popup 2024-12-03 12:15:00 +01:00
Johannes Schmelz
1f37eb9962 refactor PlayerColor
fixed default playermodel selection
2024-12-03 12:07:09 +01:00
Johannes Schmelz
09ea8a046e mortage house interaction 2024-12-03 11:37:36 +01:00
Johannes Schmelz
0acb23ab8b price settings 2024-12-03 01:09:00 +01:00
Johannes Schmelz
831974cb63 miete erhalten popup 2024-12-03 00:58:01 +01:00
Johannes Schmelz
031ac52670 foodfield rent calc 2024-12-03 00:40:43 +01:00
Johannes Schmelz
14ceb9dc67 fixed GateField rent 2024-12-03 00:39:36 +01:00
Johannes Schmelz
aa86c25e7c fixed sell house payment 2024-12-03 00:30:54 +01:00
Johannes Schmelz
cb0788e44c lock endTurnButton when player needs to roll dice 2024-12-03 00:29:27 +01:00
Johannes Schmelz
9e88353bd5 show bankrupt popup once 2024-12-03 00:17:23 +01:00
Johannes Schmelz
6db96f0a1d trigger demo mode 2024-12-03 00:12:22 +01:00
Johannes Schmelz
b01bb3cf7b update for jar export 2024-12-02 16:29:57 +01:00
Johannes Schmelz
95b9da9377 server doc 2024-12-02 09:06:00 +01:00
Luca Puderbach
30822e3f4d Java Docs 2024-12-02 09:02:41 +01:00
Yvonne Schmidt
957bf8ffcc Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 09:00:57 +01:00
Yvonne Schmidt
446ecfd4b5 added documentation for NoMoneyWarning 2024-12-02 09:00:43 +01:00
Yvonne Schmidt
821c9ec3fb added documentation for SellHouse 2024-12-02 08:58:41 +01:00
Yvonne Schmidt
531a3e263c added documentation for TakeMortage 2024-12-02 08:54:49 +01:00
Yvonne Schmidt
4917208818 added documentation for TimeOut 2024-12-02 08:51:22 +01:00
Yvonne Schmidt
e81cdf3b40 added documentation for WinnerPopUp 2024-12-02 08:49:26 +01:00
Yvonne Schmidt
bffe614b54 added documentation for LooserPopUp 2024-12-02 08:47:36 +01:00
Yvonne Schmidt
69ad19757d added documentation for GulagInfo 2024-12-02 08:44:23 +01:00
Yvonne Schmidt
a4c0afe277 added documentation for Gulag 2024-12-02 08:42:08 +01:00
Yvonne Schmidt
cc157a3cf3 added documentation for Rent 2024-12-02 08:40:02 +01:00
Johannes Schmelz
ff2b64d476 removed errors in java doc 2024-12-02 08:39:47 +01:00
Yvonne Schmidt
459a54ac5d added documentation for Rent 2024-12-02 08:36:54 +01:00
Yvonne Schmidt
a50821f2e6 added documentation for RejectTrade 2024-12-02 08:34:53 +01:00
Yvonne Schmidt
72e0fc7cbd added documentation for GateFieldCard 2024-12-02 08:31:14 +01:00
Johannes Schmelz
3260d06bc8 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 08:28:09 +01:00
Johannes Schmelz
e07db0129f completed tests 2024-12-02 08:28:05 +01:00
Yvonne Schmidt
3bfa7ff69f added documentation for FoodFieldCard 2024-12-02 08:26:08 +01:00
Yvonne Schmidt
160fff88ea added documentation for EventCardPopup 2024-12-02 08:23:13 +01:00
Yvonne Schmidt
7a658cb3d6 added documentation for EventCardPopup 2024-12-02 08:15:54 +01:00
Yvonne Schmidt
25361933d7 added documentation for ConfirmTrade 2024-12-02 08:13:06 +01:00
Yvonne Schmidt
4ac02a1a7b added documentation for BuyHouse 2024-12-02 08:10:08 +01:00
Yvonne Schmidt
6f15f12b49 added documentation for BuildingPropertyCard 2024-12-02 08:05:00 +01:00
Yvonne Schmidt
9e50c1afe2 added documentation for Bankrupt 2024-12-02 07:59:24 +01:00
Yvonne Schmidt
3a43ea10d9 added documentation for AcceptTrade 2024-12-02 07:55:07 +01:00
Yvonne Schmidt
3539b1cf23 added documentation for BuildingAdminMenu 2024-12-02 07:48:57 +01:00
Yvonne Schmidt
d0ba0d011f added documentation for CameraController 2024-12-02 07:45:37 +01:00
Yvonne Schmidt
1f07affbef added documentation for GameBoardSynchronizer 2024-12-02 07:40:45 +01:00
Yvonne Schmidt
c83f7de30c added documentation for LobbyMenu 2024-12-02 07:23:25 +01:00
Yvonne Schmidt
acb5c75379 added documentation for TradeMenu 2024-12-02 07:07:19 +01:00
Johannes Schmelz
a73384c436 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 06:53:35 +01:00
Johannes Schmelz
96542fa42b fixed numberformat 2024-12-02 06:53:18 +01:00
Johannes Schmelz
0d885203a7 max 10 long name 2024-12-02 05:58:56 +01:00
Yvonne Schmidt
e08654bb20 Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 05:54:29 +01:00
Johannes Schmelz
486c0a9810 TopDialog 2024-12-02 05:54:15 +01:00
Yvonne Schmidt
0b71c2cb96 added documentation 2024-12-02 05:53:52 +01:00
Johannes Schmelz
737576e0ca Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 05:43:53 +01:00
Johannes Schmelz
db7a99dc59 fixed Top Dialog 2024-12-02 05:43:49 +01:00
Luca Puderbach
4b48229329 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 05:43:24 +01:00
Luca Puderbach
1a41b548c4 Figuren Drehung 2024-12-02 05:43:20 +01:00
Yvonne Schmidt
7f58558da4 Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 05:25:24 +01:00
Johannes Schmelz
1503e18585 limit name length 2024-12-02 05:24:53 +01:00
Yvonne Schmidt
94155d2816 Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 05:16:12 +01:00
Luca Puderbach
ec42cc2c07 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 05:15:53 +01:00
Luca Puderbach
af79e39492 figuren drehen 2024-12-02 05:15:47 +01:00
Yvonne Schmidt
0698c29410 Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 05:13:08 +01:00
Johannes Schmelz
08c1854885 fixed jail card trade 2024-12-02 05:10:45 +01:00
Johannes Schmelz
ff39402d82 fixed event card position 2024-12-02 05:09:31 +01:00
Johannes Schmelz
4e375131d1 change property side 2024-12-02 05:06:58 +01:00
Yvonne Schmidt
ac9ced2cf4 Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 04:39:50 +01:00
Johannes Schmelz
e93791e6e8 remove testing 2024-12-02 04:39:30 +01:00
Yvonne Schmidt
fa554cbffc Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 04:37:49 +01:00
Luca Puderbach
f317d7723e Lets GO 2024-12-02 04:35:55 +01:00
Luca Puderbach
07fd92c9b2 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 04:20:14 +01:00
Luca Puderbach
91fea83f26 Modelle Fixes 2024-12-02 04:19:56 +01:00
Johannes Schmelz
471f703634 updated models 2024-12-02 04:16:49 +01:00
Yvonne Schmidt
065049f663 added documentation in client package 2024-12-02 04:08:54 +01:00
Yvonne Schmidt
580d81a621 Merge remote-tracking branch 'origin/gui' into gui 2024-12-02 03:44:42 +01:00
Yvonne Schmidt
7acf448c0c added documentation for MonopolyApp 2024-12-02 03:44:33 +01:00
Johannes Schmelz
bcf4956d2d TradeReplay popup 2024-12-02 03:16:50 +01:00
Johannes Schmelz
13754c843a clean up 2024-12-02 03:03:42 +01:00
Johannes Schmelz
4743a6882c fixed testing env 2024-12-02 03:02:05 +01:00
Johannes Schmelz
2dbc727728 Merge branch 'gui' of https://athene2.informatik.unibw-muenchen.de/progproj/gruppen-ht24/Gruppe-02 into gui 2024-12-02 03:00:28 +01:00
Johannes Schmelz
560bedc80b mortage 2024-12-02 03:00:22 +01:00
Johannes Schmelz
7ace959f1f sellHouse 2024-12-02 02:48:06 +01:00
Yvonne Schmidt
95dc7b07e2 fixed typos 2024-12-02 02:40:53 +01:00
138 changed files with 3410 additions and 1732 deletions

View File

@@ -1,5 +1,6 @@
plugins { plugins {
id 'buildlogic.jme-application-conventions' id 'buildlogic.jme-application-conventions'
id 'com.github.johnrengelman.shadow' version '8.1.1'
} }
description = 'Monopoly Client' description = 'Monopoly Client'
@@ -26,3 +27,12 @@ application {
mainClass = 'pp.monopoly.client.MonopolyApp' mainClass = 'pp.monopoly.client.MonopolyApp'
applicationName = 'monopoly' applicationName = 'monopoly'
} }
shadowJar {
manifest {
attributes(
'Main-Class': 'pp.monopoly.client.MonopolyApp'
)
}
}

View File

@@ -0,0 +1,217 @@
package pp.monopoly.client;
import com.jme3.app.Application;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import com.jme3.shadow.EdgeFilteringMode;
import com.jme3.texture.Texture;
import com.jme3.util.SkyFactory;
import com.jme3.util.TangentBinormalGenerator;
import pp.monopoly.model.Board;
import pp.monopoly.client.gui.BobTheBuilder;
import pp.monopoly.client.gui.Toolbar;
import static pp.util.FloatMath.PI;
import static pp.util.FloatMath.TWO_PI;
import static pp.util.FloatMath.cos;
import static pp.util.FloatMath.sin;
import static pp.util.FloatMath.sqrt;
/**
* Manages the rendering and visual aspects of the sea and sky in the Battleship game.
* This state is responsible for setting up and updating the sea, sky, and lighting
* conditions, and controls the camera to create a dynamic view of the game environment.
*/
public class BoardAppState extends MonopolyAppState {
/**
* The path to the unshaded texture material.
*/
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
/**
* The path to the sea texture material.
*/
private static final String BoardTexture = "Pictures/board2.png"; //NON-NLS
/**
* The root node for all visual elements in this state.
*/
private final Node viewNode = new Node("view"); //NON-NLS
/**
* The node containing the scene elements, such as the sea surface.
*/
private final Node sceneNode = new Node("scene"); //NON-NLS
/**
* Synchronizes the buildings's visual representation with the game logic.
*/
private BobTheBuilder bobTheBuilder;
/**
* The pop-up manager for displaying messages and notifications.
*/
private PopUpManager popUpManager;;
/**
* Initializes the state by setting up the sky, lights, and other visual components.
* This method is called when the state is first attached to the state manager.
*
* @param stateManager the state manager
* @param application the application
*/
@Override
public void initialize(AppStateManager stateManager, Application application) {
super.initialize(stateManager, application);
popUpManager = new PopUpManager(getApp());
viewNode.attachChild(sceneNode);
setupLights();
setupSky();
}
/**
* Enables the sea and sky state, setting up the scene and registering any necessary listeners.
* This method is called when the state is set to active.
*/
@Override
protected void enableState() {
getApp().getRootNode().detachAllChildren();
getApp().getGuiNode().detachAllChildren();
new Toolbar(getApp()).open();
sceneNode.detachAllChildren();
setupScene();
if (bobTheBuilder == null) {
bobTheBuilder = new BobTheBuilder(getApp(), getApp().getRootNode());
System.out.println("LISTENER IS REGISTEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
getGameLogic().addListener(bobTheBuilder);
}
getApp().getRootNode().attachChild(viewNode);
}
//TODO remove this only for camera testing
private static final float ABOVE_SEA_LEVEL = 10f;
private static final float INCLINATION = 2.5f;
private float cameraAngle;
/**
* Adjusts the camera position and orientation to create a circular motion around
* the center of the map. This provides a dynamic view of the sea and surrounding environment.
*/
private void adjustCamera() {
final Board board = getGameLogic().getBoard();
final float mx = 0.5f * board.getWidth();
final float my = 0.5f * board.getHeight();
final float radius = 2f * sqrt(mx * mx + my + my);
final float cos = radius * cos(cameraAngle);
final float sin = radius * sin(cameraAngle);
final float x = mx - cos;
final float y = my - sin;
final Camera camera = getApp().getCamera();
camera.setLocation(new Vector3f(x, ABOVE_SEA_LEVEL, y));
camera.lookAt(new Vector3f(0,0, 0),
Vector3f.UNIT_Y);
camera.update();
}
/**
* Disables the sea and sky state, removing visual elements from the scene and unregistering listeners.
* This method is called when the state is set to inactive.
*/
@Override
protected void disableState() {
getApp().getRootNode().detachChild(viewNode);
if (bobTheBuilder != null) {
getGameLogic().removeListener(bobTheBuilder);
bobTheBuilder = null;
}
}
/**
* Updates the state each frame, moving the camera to simulate it circling around the map.
*
* @param tpf the time per frame (seconds)
*/
@Override
public void update(float tpf) {
super.update(tpf);
//TODO remove this only for camera testing
cameraAngle += TWO_PI * 0.05f * tpf;
adjustCamera();
}
/**
* Sets up the lighting for the scene, including directional and ambient lights.
* Also configures shadows to enhance the visual depth of the scene.
*/
private void setupLights() {
final AssetManager assetManager = getApp().getAssetManager();
final DirectionalLightShadowRenderer shRend = new DirectionalLightShadowRenderer(assetManager, 2048, 3);
shRend.setLambda(0.55f);
shRend.setShadowIntensity(0.6f);
shRend.setEdgeFilteringMode(EdgeFilteringMode.Bilinear);
getApp().getViewPort().addProcessor(shRend);
final DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-1f, -0.7f, -1f).normalizeLocal());
viewNode.addLight(sun);
shRend.setLight(sun);
final AmbientLight ambientLight = new AmbientLight(new ColorRGBA(1f, 1f, 1f, 1f));
viewNode.addLight(ambientLight);
}
/**
* Sets up the sky in the scene using a skybox with textures for all six directions.
* This creates a realistic and immersive environment for the sea.
*/
private void setupSky() {
final AssetManager assetManager = getApp().getAssetManager();
final Texture west = assetManager.loadTexture("Pictures/Backdrop/left.jpg"); //NON-NLS
final Texture east = assetManager.loadTexture("Pictures/Backdrop/right.jpg"); //NON-NLS
final Texture north = assetManager.loadTexture("Pictures/Backdrop/front.jpg"); //NON-NLS
final Texture south = assetManager.loadTexture("Pictures/Backdrop/back.jpg"); //NON-NLS
final Texture up = assetManager.loadTexture("Pictures/Backdrop/up.jpg"); //NON-NLS
final Texture down = assetManager.loadTexture("Pictures/Backdrop/down.jpg"); //NON-NLS
final Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down);
// sky.rotate(0, PI, 0);
viewNode.attachChild(sky);
}
/**
* Sets up the sea surface in the scene. This includes creating the sea mesh,
* applying textures, and enabling shadows.
*/
private void setupScene() {
final Board board = getGameLogic().getBoard();
final float x = board.getWidth();
final float y = board.getHeight();
final Box seaMesh = new Box(y, 0.1f, x);
final Geometry seaGeo = new Geometry("sea", seaMesh); //NONs-NLS
seaGeo.setLocalTranslation(new Vector3f(0, -0.1f, 0));
Quaternion rotation = new com.jme3.math.Quaternion();
rotation.fromAngleAxis(FastMath.HALF_PI, com.jme3.math.Vector3f.UNIT_Y);
seaGeo.setLocalRotation(rotation);
final Material seaMat = new Material(getApp().getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
Texture texture = getApp().getAssetManager().loadTexture("Pictures/board2.png");
seaMat.setTexture("DiffuseMap", texture);
seaGeo.setMaterial(seaMat);
seaGeo.setShadowMode(ShadowMode.CastAndReceive);
TangentBinormalGenerator.generate(seaGeo);
sceneNode.attachChild(seaGeo);
}
}

View File

@@ -8,14 +8,13 @@
package pp.monopoly.client; package pp.monopoly.client;
import java.lang.System.Logger; import java.lang.System.Logger;
import java.util.List;
import java.lang.System.Logger.Level;
import com.jme3.input.controls.ActionListener; import com.jme3.input.controls.ActionListener;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.system.AppSettings;
import pp.monopoly.client.gui.TestWorld; import pp.monopoly.client.gui.TestWorld;
import pp.monopoly.game.server.Player;
/** /**
* Represents the state responsible for managing the battle interface within the Battleship game. * Represents the state responsible for managing the battle interface within the Battleship game.
@@ -24,8 +23,6 @@ import pp.monopoly.game.server.Player;
*/ */
public class GameAppState extends MonopolyAppState { public class GameAppState extends MonopolyAppState {
private static final Logger LOGGER = System.getLogger(MonopolyAppState.class.getName()); private static final Logger LOGGER = System.getLogger(MonopolyAppState.class.getName());
private static final float DEPTH = 0f;
private static final float GAP = 20f;
/** /**
* A listener for handling click events in the battle interface. * A listener for handling click events in the battle interface.
@@ -49,9 +46,9 @@ public class GameAppState extends MonopolyAppState {
*/ */
@Override @Override
protected void enableState() { protected void enableState() {
LOGGER.log(Level.DEBUG, "Enabling game state");
battleNode.detachAllChildren(); battleNode.detachAllChildren();
initializeGuiComponents(); initializeGuiComponents();
layoutGuiComponents();
addGuiComponents(); addGuiComponents();
getApp().getGuiNode().attachChild(battleNode); getApp().getGuiNode().attachChild(battleNode);
} }
@@ -85,16 +82,6 @@ public class GameAppState extends MonopolyAppState {
private void addGuiComponents() { private void addGuiComponents() {
} }
/**
* Lays out the GUI components within the window, positioning them appropriately.
* The opponent's map view is positioned based on the window's dimensions and a specified gap.
*/
private void layoutGuiComponents() {
final AppSettings s = getApp().getContext().getSettings();
final float windowWidth = s.getWidth();
final float windowHeight = s.getHeight();
}
/** /**
* Handles click events in the battle interface. If the event indicates a click (not a release), * Handles click events in the battle interface. If the event indicates a click (not a release),
* it translates the cursor position to the model's coordinate system and triggers the game logic * it translates the cursor position to the model's coordinate system and triggers the game logic
@@ -107,7 +94,6 @@ public class GameAppState extends MonopolyAppState {
@Override @Override
public void update(float tpf) { public void update(float tpf) {
// testWorld.update(tpf);
super.update(tpf); super.update(tpf);
} }
} }

View File

@@ -15,49 +15,34 @@ import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode; import com.jme3.audio.AudioNode;
/** /**
* Handles the background music beeing played. Is able to start and stop the music. Set the Volume of the Audio. * Handles the background and secondary music in the game.
* Allows playing, stopping, and toggling between background music and a secondary track.
*/ */
public class GameMusic extends AbstractAppState{ public class GameMusic extends AbstractAppState {
private static final Logger LOGGER = System.getLogger(GameMusic.class.getName()); private static final Logger LOGGER = System.getLogger(GameMusic.class.getName());
private static final Preferences PREFERENCES = getPreferences(GameMusic.class); private static final Preferences PREFERENCES = getPreferences(GameMusic.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 static final String VOLUME_PREF = "volume"; // NON-NLS
private AudioNode music; private AudioNode mainMusic;
private AudioNode secondaryMusic;
private boolean isMainMusicPlaying = false;
private boolean isSecondaryMusicPlaying = false;
/** /**
* Checks if sound is enabled in the preferences. * Initializes the GameMusic app state and loads the background music.
*
* @return {@code true} if sound is enabled, {@code false} otherwise.
*/
public static boolean enabledInPreferences() {
return PREFERENCES.getBoolean(ENABLED_PREF, true);
}
/**
* Checks if sound is enabled in the preferences.
*
* @return float to which the volume is set
*/
public static float volumeInPreferences() {
return PREFERENCES.getFloat(VOLUME_PREF, 0.5f);
}
/**
* Initializes the sound effects for the game.
* Overrides {@link AbstractAppState#initialize(AppStateManager, Application)}
* *
* @param stateManager The state manager * @param stateManager The state manager
* @param app The application * @param app The application instance
*/ */
@Override @Override
public void initialize(AppStateManager stateManager, Application app) { public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app); super.initialize(stateManager, app);
music = loadSound(app, "Sound/background.ogg"); mainMusic = loadSound(app, "Sound/background.ogg");
secondaryMusic = loadSound(app, "Sound/ChooseYourCharakter.ogg");
setVolume(volumeInPreferences()); setVolume(volumeInPreferences());
music.setLooping(true); if (isEnabled()) {
if (isEnabled() && music != null) { playMainMusic();
music.play();
} }
} }
@@ -71,7 +56,7 @@ public class GameMusic extends AbstractAppState{
private AudioNode loadSound(Application app, String name) { private AudioNode loadSound(Application app, String name) {
try { try {
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer); final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
sound.setLooping(false); sound.setLooping(true);
sound.setPositional(false); sound.setPositional(false);
return sound; return sound;
} }
@@ -82,41 +67,129 @@ public class GameMusic extends AbstractAppState{
} }
/** /**
* Sets the enabled state of this AppState. * Plays the main music.
* Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)} */
private void playMainMusic() {
if (!isEnabled()) {
return; // Sound is disabled
}
if (mainMusic != null && !isMainMusicPlaying) {
mainMusic.play();
isMainMusicPlaying = true;
}
}
/**
* Stops the main music.
*/
private void stopMainMusic() {
if (mainMusic != null && isMainMusicPlaying) {
mainMusic.stop();
isMainMusicPlaying = false;
}
}
/**
* Plays the secondary music and stops the main music.
* *
* @param enabled {@code true} to enable the AppState, {@code false} to disable it. * @param app The application instance
* @param secondaryMusicFile The file path of the secondary audio file
*/
private void playSecondaryMusic() {
if(!isEnabled()) {
return;
}
if (isSecondaryMusicPlaying) {
return; // Secondary music is already playing
}
stopMainMusic();
if (secondaryMusic != null) {
secondaryMusic.setVolume(volumeInPreferences());
secondaryMusic.play();
isSecondaryMusicPlaying = true;
}
}
/**
* Stops the secondary music.
*/
private void stopSecondaryMusic() {
if (secondaryMusic != null && isSecondaryMusicPlaying) {
secondaryMusic.stop();
isSecondaryMusicPlaying = false;
}
}
/**
* Toggles between the background music and the secondary track.
* If the secondary track is playing, it stops and resumes the background music.
* If the background music is playing, it pauses and plays the secondary track.
*
* @param app The application instance
* @param secondaryMusicFile The file path of the secondary audio file
*/
public void toggleMusic() {
if(!isEnabled()) {
return;
}
if (isSecondaryMusicPlaying) {
stopSecondaryMusic();
playMainMusic();
} else {
playSecondaryMusic();
}
}
/**
* Sets the audio volume for both the main and secondary tracks.
*
* @param vol The volume level (0.0f to 1.0f)
*/
public void setVolume(float vol) {
if (mainMusic != null) mainMusic.setVolume(vol);
if (secondaryMusic != null) secondaryMusic.setVolume(vol);
PREFERENCES.putFloat(VOLUME_PREF, vol);
}
/**
* Enables or disables the sound system.
* When disabled, all music stops.
*
* @param enabled {@code true} to enable, {@code false} to disable
*/ */
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
if (isEnabled() == enabled) return; if (isEnabled() == enabled) return;
if (music != null) { if (enabled) {
if (enabled) { playMainMusic();
music.play(); } else {
} else { stopMainMusic();
music.stop(); stopSecondaryMusic();
}
} }
super.setEnabled(enabled); super.setEnabled(enabled);
LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); //NON-NLS LOGGER.log(Level.INFO, "Sound enabled: {0}", enabled); // NON-NLS
PREFERENCES.putBoolean(ENABLED_PREF, enabled); PREFERENCES.putBoolean(ENABLED_PREF, enabled);
} }
/** /**
* Toggles the game sound on or off. * Retrieves the current sound volume preference.
*
* @return The volume level (0.0f to 1.0f)
*/ */
public void toggleSound() { public static float volumeInPreferences() {
setEnabled(!isEnabled()); return PREFERENCES.getFloat(VOLUME_PREF, 0.5f);
} }
/** /**
* Sets the volume of music * Checks if sound is enabled in the preferences.
* @param vol the volume to which the music should be set *
* @return {@code true} if sound is enabled, {@code false} otherwise
*/ */
public void setVolume(float vol){ public static boolean enabledInPreferences() {
music.setVolume(vol); return PREFERENCES.getBoolean(ENABLED_PREF, true);
PREFERENCES.putFloat(VOLUME_PREF, vol);
} }
} }

View File

@@ -27,9 +27,25 @@ import static pp.util.PreferencesUtils.getPreferences;
* An application state that plays sounds. * An application state that plays sounds.
*/ */
public class GameSound extends AbstractAppState implements GameEventListener { public class GameSound extends AbstractAppState implements GameEventListener {
/**
* Logger instance for logging messages related to GameSound.
*/
private static final Logger LOGGER = System.getLogger(GameSound.class.getName()); private static final Logger LOGGER = System.getLogger(GameSound.class.getName());
/**
* Preferences instance for managing GameSound-related settings.
*/
private static final Preferences PREFERENCES = getPreferences(GameSound.class); private static final Preferences PREFERENCES = getPreferences(GameSound.class);
/**
* Preference key for enabling or disabling GameSound.
*/
private static final String ENABLED_PREF = "enabled"; //NON-NLS private static final String ENABLED_PREF = "enabled"; //NON-NLS
/**
* Preference key for storing the volume level of GameSound.
*/
private static final String VOLUME_PREF = "volume"; //NON-NLS private static final String VOLUME_PREF = "volume"; //NON-NLS
private AudioNode passStartSound; private AudioNode passStartSound;
@@ -223,6 +239,11 @@ public class GameSound extends AbstractAppState implements GameEventListener {
PREFERENCES.putFloat(VOLUME_PREF, vol); PREFERENCES.putFloat(VOLUME_PREF, vol);
} }
/**
* Overrides {@link SoundEvent#notifyListener(GameEventListener)}
* @param event the received event
*/
@Override @Override
public void receivedEvent(SoundEvent event) { public void receivedEvent(SoundEvent event) {
switch (event.sound()) { switch (event.sound()) {

View File

@@ -30,25 +30,23 @@ 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.dialog.Dialog;
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 static pp.monopoly.Resources.lookup; import static pp.monopoly.Resources.lookup;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.client.gui.StartMenu; import pp.monopoly.client.gui.StartMenu;
import pp.monopoly.client.gui.TestWorld;
import pp.monopoly.client.gui.popups.*;
import pp.monopoly.game.client.ClientGameLogic; import pp.monopoly.game.client.ClientGameLogic;
import pp.monopoly.game.client.MonopolyClient; import pp.monopoly.game.client.MonopolyClient;
import pp.monopoly.game.client.ServerConnection; import pp.monopoly.game.client.ServerConnection;
import pp.monopoly.message.client.NotificationAnswer;
import pp.monopoly.notification.ClientStateEvent; import pp.monopoly.notification.ClientStateEvent;
import pp.monopoly.notification.GameEventListener; import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent; import pp.monopoly.notification.InfoTextEvent;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* The main class for the Battleship client application. * The main class for the Monopoly client application.
* It manages the initialization, input setup, GUI setup, and game states for the client. * 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 {
@@ -123,22 +121,10 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
*/ */
private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed); private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
//TODO temp for testing /**
private EventCardPopup eventCard; * Listener for handeling Demo Mode (Minas mode)
private BuildingPropertyCard buildingProperty; */
private FoodFieldCard foodField; private final ActionListener f8Listener = (name, isPressed, tpf) -> handleF8(isPressed);
private GateFieldCard gateField;
private LooserPopUp looserpopup;
private Bankrupt bankrupt;
private TimeOut timeOut;
private SellHouse sellHouse;
private BuyHouse buyHouse;
private TakeMortage takeMortage;
private RepayMortage repayMortage;
private boolean isBuyCardPopupOpen = false;
private final ActionListener BListener = (name, isPressed, tpf) -> handleB(isPressed);
private TestWorld testWorld;
static { static {
// Configure logging // Configure logging
@@ -153,7 +139,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
} }
/** /**
* Starts the Battleship application. * Starts the Monopoly application.
* *
* @param args Command-line arguments for launching the application. * @param args Command-line arguments for launching the application.
*/ */
@@ -220,9 +206,9 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
} }
/** /**
* Returns the current configuration settings for the Battleship client. * Returns the current configuration settings for the Monopoly client.
* *
* @return The {@link BattleshipClientConfig} instance. //TODO Fehler im Kommentar * @return The {@link pp.monopoly.game.client.MonopolyClientConfig} instance.
*/ */
@Override @Override
public MonopolyAppConfig getConfig() { public MonopolyAppConfig getConfig() {
@@ -267,20 +253,20 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
inputManager.setCursorVisible(false); inputManager.setCursorVisible(false);
inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE)); inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addMapping("F8", new KeyTrigger(KeyInput.KEY_F8));
inputManager.addListener(f8Listener, "F8");
inputManager.addListener(escapeListener, ESC); inputManager.addListener(escapeListener, ESC);
//TODO tmp for testing
inputManager.addMapping("B", new KeyTrigger(KeyInput.KEY_B));
inputManager.addListener(BListener, "B");
inputManager.addMapping("T", new KeyTrigger(KeyInput.KEY_T));
} }
//logik zum wechselnden erscheinen und verschwinden beim drücken von B //TODO süäter entfernen /**
private void handleB(boolean isPressed) { * Handles the action on alt m for demo mode
* @param isPressed {@code true} is alt + m is pressed, {@code false} otherwise
*/
private void handleF8(boolean isPressed) {
if (isPressed) { if (isPressed) {
Dialog tmp = new GulagInfo(this, 3); LOGGER.log(Level.INFO, "F detected."); // Debug logging
tmp.open(); getGameLogic().send(new NotificationAnswer("hack"));
} }
} }
@@ -299,7 +285,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
attachGameSound(); attachGameSound();
attachGameMusic(); attachGameMusic();
stateManager.attach(new GameAppState()); stateManager.attach(new BoardAppState());
} }
/** /**
@@ -333,11 +319,6 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
dialogManager.update(tpf); dialogManager.update(tpf);
logic.update(tpf); logic.update(tpf);
stateManager.update(tpf); stateManager.update(tpf);
// //TODO testing replace later
// if (testWorld != null) {
// testWorld.update(tpf);
// }
} }
/** /**
@@ -424,7 +405,7 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
*/ */
@Override @Override
public void receivedEvent(ClientStateEvent event) { public void receivedEvent(ClientStateEvent event) {
stateManager.getState(GameAppState.class).setEnabled(true); stateManager.getState(BoardAppState.class).setEnabled(logic.isTurn());
} }
/** /**
@@ -482,10 +463,24 @@ public class MonopolyApp extends SimpleApplication implements MonopolyClient, Ga
.open(); .open();
} }
/**
* Disconnects the current server connection.
*
* This method delegates the disconnection operation to the `disconnect` method of the
* `serverConnection` object.
*
*/
public void disconnect() { public void disconnect() {
serverConnection.disconnect(); serverConnection.disconnect();
} }
/**
* Retrieves the unique identifier associated with the server connection.
*
* Checks if a Server is connected and returns 0 if there is no connection
*
* @return the ID of the connected Server instance.
*/
public int getId() { public int getId() {
if (serverConnection != null && serverConnection instanceof NetworkSupport) return ((NetworkSupport) serverConnection).getId(); if (serverConnection != null && serverConnection instanceof NetworkSupport) return ((NetworkSupport) serverConnection).getId();
return 0; return 0;

View File

@@ -25,7 +25,7 @@ import java.lang.System.Logger.Level;
import static pp.monopoly.Resources.lookup; import static pp.monopoly.Resources.lookup;
/** /**
* Manages the network connection for the Battleship application. * Manages the network connection for the Monopoly 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 {
@@ -34,9 +34,9 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
private Client client; private Client client;
/** /**
* Constructs a NetworkSupport instance for the given Battleship application. * Constructs a NetworkSupport instance for the given Monopoly application.
* *
* @param app The Battleship application instance. * @param app The Monopoly application instance.
*/ */
public NetworkSupport(MonopolyApp app) { public NetworkSupport(MonopolyApp app) {
this.app = app; this.app = app;
@@ -44,6 +44,7 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
/** /**
* Return the client connections Id * Return the client connections Id
*
* @return the client id * @return the client id
*/ */
public int getId() { public int getId() {
@@ -52,9 +53,9 @@ public class NetworkSupport implements MessageListener<Client>, ClientStateListe
} }
/** /**
* Returns the Battleship application instance. * Returns the Monopoly application instance.
* *
* @return Battleship application instance * @return Monopoly application instance
*/ */
public MonopolyApp getApp() { public MonopolyApp getApp() {
return app; return app;

View File

@@ -0,0 +1,97 @@
package pp.monopoly.client;
import java.util.Timer;
import java.util.TimerTask;
import pp.monopoly.client.gui.popups.AcceptTrade;
import pp.monopoly.client.gui.popups.BuildingPropertyCard;
import pp.monopoly.client.gui.popups.ConfirmTrade;
import pp.monopoly.client.gui.popups.EventCardPopup;
import pp.monopoly.client.gui.popups.FoodFieldCard;
import pp.monopoly.client.gui.popups.GateFieldCard;
import pp.monopoly.client.gui.popups.Gulag;
import pp.monopoly.client.gui.popups.GulagInfo;
import pp.monopoly.client.gui.popups.LooserPopUp;
import pp.monopoly.client.gui.popups.NoMoneyWarning;
import pp.monopoly.client.gui.popups.ReceivedRent;
import pp.monopoly.client.gui.popups.RejectTrade;
import pp.monopoly.client.gui.popups.Rent;
import pp.monopoly.client.gui.popups.TimeOut;
import pp.monopoly.client.gui.popups.WinnerPopUp;
import pp.monopoly.message.server.NotificationMessage;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.FoodField;
import pp.monopoly.model.fields.GateField;
import pp.monopoly.notification.EventCardEvent;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.PopUpEvent;
public class PopUpManager implements GameEventListener {
private final MonopolyApp app;
public PopUpManager(MonopolyApp app) {
this.app = app;
app.getGameLogic().addListener(this);
}
@Override
public void receivedEvent(PopUpEvent event) {
if (event.msg().equals("Buy")) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
app.enqueue(() -> {
int field = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
Object fieldObject = app.getGameLogic().getBoardManager().getFieldAtIndex(field);
if (fieldObject instanceof BuildingProperty) {
new BuildingPropertyCard(app).open();
} else if (fieldObject instanceof GateField) {
new GateFieldCard(app).open();
} else if (fieldObject instanceof FoodField) {
new FoodFieldCard(app).open();
}
});
}
}, 2500);
} else if (event.msg().equals("Winner")) {
new WinnerPopUp(app).open();
} else if (event.msg().equals("Looser")) {
new LooserPopUp(app).open();
} else if (event.msg().equals("timeout")) {
new TimeOut(app).open();
} else if (event.msg().equals("tradeRequest")) {
new ConfirmTrade(app).open();
} else if (event.msg().equals("goingToJail")) {
new Gulag(app).open();
} else if (event.msg().equals("NoMoneyWarning")) {
new NoMoneyWarning(app).open();
} else if(event.msg().equals("rent")) {
new Rent(app, ( (NotificationMessage) event.message()).getRentOwner(), ( (NotificationMessage) event.message()).getRentAmount() ).open();
} else if (event.msg().equals("jailtryagain")) {
new GulagInfo(app, 1).open();
} else if (event.msg().equals("jailpay")) {
new GulagInfo(app, 3).open();
} else if (event.msg().equals("tradepos")) {
new AcceptTrade(app, (TradeReply) event.message()).open();
} else if (event.msg().equals("tradeneg")) {
new RejectTrade(app, (TradeReply) event.message()).open();
} else if (event.msg().equals("ReceivedRent")) {
new ReceivedRent(app, ( (NotificationMessage) event.message()).getRentOwner(), ( (NotificationMessage) event.message()).getRentAmount() ).open();
}
}
@Override
public void receivedEvent(EventCardEvent event) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
app.enqueue(() -> new EventCardPopup(app, event.description()).open());
}
}, 2500);
}
}

View File

@@ -1,74 +0,0 @@
package pp.monopoly.client.gui;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import pp.monopoly.model.Board;
import pp.monopoly.model.Item;
import pp.monopoly.model.Visitor;
import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.ItemAddedEvent;
import pp.monopoly.notification.ItemRemovedEvent;
import pp.view.ModelViewSynchronizer;
/**
* Abstract base class for synchronizing the visual representation of a {@link Board} with its model state.
* This class handles the addition and removal of items from the map, ensuring that changes in the model
* are accurately reflected in the view.
*/
abstract class BoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
protected final Board board;
/**
* Constructs a new BoardSynchronizer.
*
* @param board the game board to synchronize
* @param root the root node to which the view representations of the board items are attached
*/
protected BoardSynchronizer(Board board, Node root) {
super(root);
this.board = board;
}
/**
* Translates a model item into its corresponding visual representation.
*
* @param item the item from the model to be translated
* @return the visual representation of the item as a {@link Spatial}
*/
@Override
protected Spatial translate(Item item) {
return item.accept(this);
}
/**
* Adds the existing items from the board to the view during initialization.
*/
protected void addExisting() {
board.getItems().forEach(this::add);
}
/**
* Handles the event when an item is removed from the board.
*
* @param event the event indicating that an item has been removed from the board
*/
@Override
public void receivedEvent(ItemRemovedEvent event) {
if (board == event.getBoard()) {
delete(event.getItem());
}
}
/**
* Handles the event when an item is added to the board.
*
* @param event the event indicating that an item has been added to the board
*/
@Override
public void receivedEvent(ItemAddedEvent event) {
if (board == event.getBoard()) {
add(event.getItem());
}
}
}

View File

@@ -0,0 +1,159 @@
package pp.monopoly.client.gui;
import static com.jme3.material.Materials.LIGHTING;
import java.util.stream.Collectors;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import pp.monopoly.client.MonopolyApp;
import pp.monopoly.game.server.Player;
import pp.monopoly.model.Figure;
import pp.monopoly.model.Hotel;
import pp.monopoly.model.House;
import pp.monopoly.model.Item;
import pp.monopoly.notification.UpdatePlayerView;
public class BobTheBuilder extends GameBoardSynchronizer {
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS
private static final String COLOR = "Color"; //NON-NLS
private static final String FIGURE = "figure"; //NON-NLS
private static final String HOUSE = "house"; //NON-NLS
private static final String HOTEL = "hotel"; //NON-NLS
private final MonopolyApp app;
public BobTheBuilder(MonopolyApp app, Node root) {
super(app.getGameLogic().getBoard(), root);
this.app = app;
addExisting();
}
@Override
public Spatial visit(Figure figure) {
final Node node = new Node(FIGURE);
node.attachChild(createFigure(figure));
// Setze die Position basierend auf der Feld-ID
node.setLocalTranslation(figure.getPos());
// Setze die Rotation basierend auf der Feld-ID
node.setLocalRotation(figure.getRot().toQuaternion());
// node.addControl(new FigureControl(figure));
return node;
}
@Override
public Spatial visit(Hotel hotel) {
final Node node = new Node(HOTEL);
node.attachChild(createHotel(hotel));
// Setze die Position basierend auf der Feld-ID
node.setLocalTranslation(hotel.getPos());
// Setze die Rotation basierend auf der Feld-ID
node.setLocalRotation(hotel.getRot().toQuaternion());
return node;
}
@Override
public Spatial visit(House house) {
final Node node = new Node(HOUSE);
node.attachChild(createHouse(house));
// Setze die Position basierend auf der Feld-ID
node.setLocalTranslation(house.getPos());
// Setze die Rotation basierend auf der Feld-ID
node.setLocalRotation(house.getAlignment());
return node;
}
private Spatial createFigure(Figure figure) {
// Lade das Modell
Spatial model = app.getAssetManager().loadModel("models/" + "Spielfiguren/" + figure.getType() + "/" + figure.getType() + ".j3o");
// Skaliere und positioniere das Modell
model.scale(0.5f);
return model;
}
private Spatial createHotel(Hotel hotel) {
Spatial model = app.getAssetManager().loadModel("models/Hotel/Hotel.j3o");
model.scale(0.2f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;
}
private Spatial createHouse(House house) {
Spatial model = app.getAssetManager().loadModel("models/Haus/"+house.getStage()+"Haus.j3o");
model.scale(0.5f);
model.setShadowMode(ShadowMode.CastAndReceive);
return model;
}
/**
* Creates a simple box to represent a battleship that is not of the "King George V" type.
*
* @param ship the battleship to be represented
* @return the geometry representing the battleship as a box
*/
private Spatial createBox(Item item) {
final Box box = new Box(3,
3f,
3);
final Geometry geometry = new Geometry(FIGURE, box);
geometry.setMaterial(createColoredMaterial(ColorRGBA.Blue));
geometry.setShadowMode(ShadowMode.CastAndReceive);
geometry.setLocalTranslation(0, 2, 0);
return geometry;
}
/**
* Creates a new {@link Material} with the specified color.
* If the color includes transparency (i.e., alpha value less than 1),
* the material's render state is set to use alpha blending, allowing for
* semi-transparent rendering.
*
* @param color the {@link ColorRGBA} to be applied to the material. If the alpha value
* of the color is less than 1, the material will support transparency.
* @return a {@link Material} instance configured with the specified color and,
* if necessary, alpha blending enabled.
*/
private Material createColoredMaterial(ColorRGBA color) {
final Material material = new Material(app.getAssetManager(), UNSHADED);
if (color.getAlpha() < 1f)
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
material.setColor(COLOR, color);
return material;
}
@Override
public void receivedEvent(UpdatePlayerView event) {
board.removePlayers();
//TODO transition animation
for (Player player : app.getGameLogic().getPlayerHandler().getPlayers()) {
board.add(player.getFigure());
}
for (Item item : board.getItems().stream().filter(p -> p instanceof Figure).collect(Collectors.toList())) {
add(item);
}
}
}

View File

@@ -18,18 +18,46 @@ import pp.monopoly.client.gui.popups.SellHouse;
import pp.monopoly.client.gui.popups.TakeMortage; import pp.monopoly.client.gui.popups.TakeMortage;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/**
* Represents the building administration menu in the Monopoly application.
* <p>
* Provides options to manage properties, including building houses, demolishing houses,
* taking mortgages, repaying mortgages, and viewing an overview of owned properties.
* </p>
*/
public class BuildingAdminMenu extends Dialog { public class BuildingAdminMenu extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the menu's UI components. */
private final Container mainContainer; private final Container mainContainer;
/** Background geometry for the menu. */
private Geometry background; private Geometry background;
/** Button to navigate back to the previous menu. */
private final Button backButton = new Button("Zurück"); private final Button backButton = new Button("Zurück");
/** Button to build houses on properties. */
private final Button buildButton = new Button("Bauen"); private final Button buildButton = new Button("Bauen");
/** Button to demolish houses on properties. */
private final Button demolishButton = new Button("Abriss"); private final Button demolishButton = new Button("Abriss");
/** Button to take out a mortgage on properties. */
private final Button takeMortgageButton = new Button("Hypothek aufnehmen"); private final Button takeMortgageButton = new Button("Hypothek aufnehmen");
/** Button to repay a mortgage on properties. */
private final Button payMortgageButton = new Button("Hypothek bezahlen"); private final Button payMortgageButton = new Button("Hypothek bezahlen");
/** Button to open the property overview menu. */
private final Button overviewButton = new Button("Übersicht"); private final Button overviewButton = new Button("Übersicht");
/**
* Constructs the building administration menu.
*
* @param app the Monopoly application instance
*/
public BuildingAdminMenu(MonopolyApp app) { public BuildingAdminMenu(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -163,6 +191,9 @@ public class BuildingAdminMenu extends Dialog {
app.getGuiNode().attachChild(background); app.getGuiNode().attachChild(background);
} }
/**
* Closes the building administration menu and detaches its elements from the GUI.
*/
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(mainContainer); app.getGuiNode().detachChild(mainContainer);
@@ -170,11 +201,19 @@ public class BuildingAdminMenu extends Dialog {
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();
} }
/**
* Periodic updates for the menu, if required.
*
* @param delta Time since the last update in seconds.
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
// Periodic updates if necessary // Periodic updates if necessary

View File

@@ -4,20 +4,16 @@ import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
/** /**
* Steuert die Kamerabewegung in der Szene. * Controls the movement of the camera within the scene.
*/ */
public class CameraController { public class CameraController {
private final Camera camera; private final Camera camera;
private final float height = 25; // Höhe der Kamera über dem Spielfeld // Aktueller Winkel in der Kreisbewegung private final float height = 25; // Height of the camera above the game board
/** /**
* Konstruktor für den CameraController. * Constructor for the CameraController.
* *
* @param camera Die Kamera, die gesteuert werden soll * @param camera The camera to be controlled
* @param center Der Mittelpunkt der Kreisbewegung (Fokuspunkt)
* @param radius Der Radius der Kreisbewegung
* @param height Die Höhe der Kamera über dem Fokuspunkt
* @param speed Die Geschwindigkeit der Kamerabewegung
*/ */
public CameraController(Camera camera) { public CameraController(Camera camera) {
this.camera = camera; this.camera = camera;
@@ -26,27 +22,45 @@ public class CameraController {
} }
/** /**
* Aktualisiert die Kameraposition und -ausrichtung. * Updates the camera's position and orientation.
* *
* @param tpf Zeit pro Frame * @param tpf Time per frame
*/ */
public void update(float tpf) { public void update(float tpf) {
camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); camera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
} }
/**
* Sets the camera's position based on the field ID.
*
* @param fieldID The ID of the field to which the camera should move
*/
public void setPosition(int fieldID) { public void setPosition(int fieldID) {
camera.setLocation(fieldIdToVector(fieldID)); camera.setLocation(fieldIdToVector(fieldID));
} }
/**
* Sets the camera's position using specific coordinates.
*
* @param x The X-coordinate of the new camera position
* @param y The Y-coordinate of the new camera position
*/
public void setPosition(float x, float y) { public void setPosition(float x, float y) {
camera.setLocation(new Vector3f(x,height,y)); camera.setLocation(new Vector3f(x, height, y));
} }
/**
* Maps a field ID to its corresponding position in the game world.
*
* @param fieldID The ID of the field
* @return The position of the field as a {@link Vector3f}
* @throws IllegalArgumentException If the field ID is invalid
*/
private Vector3f fieldIdToVector(int fieldID) { private Vector3f fieldIdToVector(int fieldID) {
if (fieldID <= 10) return new Vector3f(30,height,0); if (fieldID <= 10) return new Vector3f(30, height, 0);
if (fieldID <= 20) return new Vector3f(0, height, 30); if (fieldID <= 20) return new Vector3f(0, height, 30);
if (fieldID <= 30) return new Vector3f(-30, height, 0); if (fieldID <= 30) return new Vector3f(-30, height, 0);
if (fieldID <= 40) return new Vector3f(0, height, -30); if (fieldID <= 40) return new Vector3f(0, height, -30);
else throw new IllegalArgumentException(); else throw new IllegalArgumentException();
} }
} }

View File

@@ -0,0 +1,60 @@
//package pp.monopoly.client.gui;
//
//import com.jme3.input.InputManager;
//import com.jme3.input.KeyInput;
//import com.jme3.input.controls.ActionListener;
//import com.jme3.input.controls.KeyTrigger;
//
///**
// * Handhabt die Eingaben für die Kamera.
// */
//public class CameraInputHandler {
//
// private CameraController cameraController; // Kamera-Controller
//
// /**
// * Konstruktor für den CameraInputHandler.
// *
// * @param cameraController Der Kamera-Controller, der gesteuert werden soll.
// * @param inputManager Der InputManager, um Eingaben zu registrieren.
// */
// public CameraInputHandler(CameraController cameraController, InputManager inputManager) {
// if (cameraController == null || inputManager == null) {
// throw new IllegalArgumentException("CameraController und InputManager dürfen nicht null sein");
// }
// this.cameraController = cameraController;
//
// // Mappings für Kamerasteuerung
// inputManager.addMapping("FocusCurrentPlayer", new KeyTrigger(KeyInput.KEY_1)); // Modus 1
// inputManager.addMapping("FocusSelf", new KeyTrigger(KeyInput.KEY_2)); // Modus 2
// inputManager.addMapping("FreeCam", new KeyTrigger(KeyInput.KEY_3)); // Modus 3
//
// // Listener für die Kameramodi
// inputManager.addListener(actionListener, "FocusCurrentPlayer", "FocusSelf", "FreeCam");
// }
//
// /**
// * ActionListener für die Kamerasteuerung.
// */
// private final ActionListener actionListener = (name, isPressed, tpf) -> {
// if (!isPressed) return;
//
// // Umschalten der Kamera-Modi basierend auf der Eingabe
// switch (name) {
// case "FocusCurrentPlayer" -> {
// cameraController.setMode(CameraController.CameraMode.FOCUS_CURRENT_PLAYER);
// System.out.println("Kameramodus: Fokus auf aktuellen Spieler");
// }
// case "FocusSelf" -> {
// cameraController.setMode(CameraController.CameraMode.FOCUS_SELF);
// System.out.println("Kameramodus: Fokus auf eigene Figur");
// }
// case "FreeCam" -> {
// cameraController.setMode(CameraController.CameraMode.FREECAM);
// System.out.println("Kameramodus: Freie Kamera");
// }
// default -> System.err.println("Unbekannter Kameramodus: " + name);
// }
// };
//}
//

View File

@@ -1,124 +1,87 @@
////////////////////////////////////////
// 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 com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box; import pp.monopoly.model.Item;
import pp.monopoly.model.Visitor;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.notification.DiceRollEvent;
import pp.monopoly.game.server.PlayerColor; import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.ItemAddedEvent;
import pp.monopoly.notification.ItemRemovedEvent;
import pp.monopoly.notification.UpdatePlayerView;
import pp.monopoly.model.Board; import pp.monopoly.model.Board;
import pp.monopoly.model.Figure; import pp.monopoly.model.Figure;
import pp.monopoly.model.Rotation; import pp.view.ModelViewSynchronizer;
import static pp.util.FloatMath.HALF_PI;
import static pp.util.FloatMath.PI;
/** /**
* The {@code GameBoardSynchronizer} class is responsible for synchronizing the graphical * Abstract base class for synchronizing the visual representation of a {@link Board} with its model state.
* representation of the ships and shots on the sea map with the underlying data model. * This class handles the addition and removal of items from the board, ensuring that changes in the model
* It extends the {@link BoardSynchronizer} to provide specific synchronization * are accurately reflected in the view.
* logic for the sea map. * <p>
* Subclasses are responsible for providing the specific implementation of how each item in the map
* is represented visually by implementing the {@link Visitor} interface.
* </p>
*/ */
class GameBoardSynchronizer extends BoardSynchronizer { abstract class GameBoardSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
private static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md"; //NON-NLS // The board that this synchronizer is responsible for
private static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md"; protected final Board board;
private static final String COLOR = "Color"; //NON-NLS
private static final String FIGURE = "figure"; //NON-NLS
private final MonopolyApp app;
private final ParticleEffectFactory particleFactory;
/** /**
* Constructs a {@code GameBoardSynchronizer} object with the specified application, root node, and ship map. * Constructs a new GameBoardSynchronizer.
* Initializes the synchronizer with the provided board and the root node for attaching view representations.
* *
* @param app the Battleship application * @param map the board to be synchronized
* @param root the root node to which graphical elements will be attached * @param root the root node to which the view representations of the board items are attached
* @param map the ship map containing the ships and shots
*/ */
public GameBoardSynchronizer(MonopolyApp app, Node root, Board board) { protected GameBoardSynchronizer(Board board, Node root) {
super(board, root); super(root);
this.app = app; this.board = board;
this.particleFactory = new ParticleEffectFactory(app);
addExisting();
} }
/** /**
* Visits a {@link Battleship} and creates a graphical representation of it. * Translates a model item into its corresponding visual representation.
* The representation is either a 3D model or a simple box depending on the * The specific visual representation is determined by the concrete implementation of the {@link Visitor} interface.
* type of battleship.
* *
* @param ship the battleship to be represented * @param item the item from the model to be translated
* @return the node containing the graphical representation of the battleship * @return the visual representation of the item as a {@link Spatial}
*/ */
public Spatial visit(Figure figure) { @Override
final Node node = new Node(FIGURE); protected Spatial translate(Item item) {
node.attachChild(createBox(figure)); return item.accept(this);
// compute the center of the ship in world coordinates
final float x = 1;
final float z = 1;
node.setLocalTranslation(x, 0f, z);
return node;
} }
/** /**
* Creates a simple box to represent a battleship that is not of the "King George V" type. * Adds the existing items from the board to the view.
* * This method should be called during initialization to ensure that all current items in the board
* @param ship the battleship to be represented * are visually represented.
* @return the geometry representing the battleship as a box
*/ */
private Spatial createBox(Figure figure) { protected void addExisting() {
final Box box = new Box(0.5f * (figure.getMaxY() - figure.getMinY()) + 0.3f, board.getItems().forEach(this::add);
0.3f, }
0.5f * (figure.getMaxX() - figure.getMinX()) + 0.3f);
final Geometry geometry = new Geometry(FIGURE, box);
geometry.setMaterial(createColoredMaterial(PlayerColor.PINK.getColor()));
geometry.setShadowMode(ShadowMode.CastAndReceive);
return geometry; /**
* Handles the event when an item is removed from the ship map.
* Removes the visual representation of the item from the view if it belongs to the synchronized ship map.
*
* @param event the event indicating that an item has been removed from the ship map
*/
@Override
public void receivedEvent(ItemRemovedEvent event) {
if (board == event.board())
delete(event.item());
} }
/** /**
* Creates a new {@link Material} with the specified color. * Handles the event when an item is added to the ship map.
* If the color includes transparency (i.e., alpha value less than 1), * Adds the visual representation of the new item to the view if it belongs to the synchronized ship map.
* the material's render state is set to use alpha blending, allowing for
* semi-transparent rendering.
* *
* @param color the {@link ColorRGBA} to be applied to the material. If the alpha value * @param event the event indicating that an item has been added to the ship map
* of the color is less than 1, the material will support transparency.
* @return a {@link Material} instance configured with the specified color and,
* if necessary, alpha blending enabled.
*/ */
private Material createColoredMaterial(ColorRGBA color) { @Override
final Material material = new Material(app.getAssetManager(), UNSHADED); public void receivedEvent(ItemAddedEvent event) {
if (color.getAlpha() < 1f) if (board == event.board()){
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); add(event.item());
material.setColor(COLOR, color); }
return material;
} }
/**
* Calculates the rotation angle for the specified rotation.
*
* @param rot the rotation of the battleship
* @return the rotation angle in radians
*/
private static float calculateRotationAngle(Rotation rot) {
return switch (rot) {
case RIGHT -> HALF_PI;
case DOWN -> 0f;
case LEFT -> -HALF_PI;
case UP -> PI;
};
}
} }

View File

@@ -0,0 +1,39 @@
package pp.monopoly.client.gui;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.style.ElementId;
import pp.monopoly.client.MonopolyApp;
public class ImageButton extends Button {
private final String file;
private static MonopolyApp app;
public ImageButton( String s, String file, MonopolyApp app ) {
this(s, true, new ElementId(ELEMENT_ID), null, file, app);
}
public ImageButton( String s, String style, String file, MonopolyApp app ) {
this(s, true, new ElementId(ELEMENT_ID), style, file, app);
}
public ImageButton( String s, ElementId elementId, String file, MonopolyApp app ) {
this(s, true, elementId, null, file, app);
}
public ImageButton( String s, ElementId elementId, String style, String file, MonopolyApp app ) {
this(s, true, elementId, style, file, app);
}
protected ImageButton( String s, boolean applyStyles, ElementId elementId, String style, String file, MonopolyApp app ) {
super(s, false, elementId, style);
this.file = file;
ImageButton.app = app;
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/Buttons/"+file+".png");
setBackground(new QuadBackgroundComponent(backgroundImage));
}
}

View File

@@ -1,7 +1,5 @@
package pp.monopoly.client.gui; package pp.monopoly.client.gui;
import com.jme3.app.Application;
import com.jme3.app.state.BaseAppState;
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;
@@ -24,30 +22,65 @@ import com.simsilica.lemur.core.VersionedReference;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.monopoly.client.GameMusic;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.game.server.PlayerColor; import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.PlayerReady; import pp.monopoly.message.client.PlayerReady;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
import java.util.Set; import java.util.Set;
/**
* Represents the lobby menu in the Monopoly application.
* <p>
* Provides functionality for player configuration, including input for starting capital,
* player name, and figure selection, as well as options to ready up or exit the game.
* </p>
*/
public class LobbyMenu extends Dialog { public class LobbyMenu extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the lobby menu UI. */
private final Container menuContainer; private final Container menuContainer;
/** Background geometry for the menu. */
private Geometry background; private Geometry background;
/** Colored circle displayed between input fields and dropdown menus. */
private Geometry circle; private Geometry circle;
/** Container for the lower-left section of the menu. */
private Container lowerLeftMenu; private Container lowerLeftMenu;
/** Container for the lower-right section of the menu. */
private Container lowerRightMenu; private Container lowerRightMenu;
/** Text field for entering the player's name. */
private TextField playerInputField; private TextField playerInputField;
/** Text field for entering the starting capital. */
private TextField startingCapital = new TextField("15000"); private TextField startingCapital = new TextField("15000");
/** Selected player figure. */
private String figure; private String figure;
private VersionedReference<Set<Integer>> selectionRef;
private Selector<String> figureDropdown;
/**
* Constructs the lobby menu for player configuration.
*
* @param app the Monopoly application instance
*/
public LobbyMenu(MonopolyApp app) { public LobbyMenu(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
GameMusic music = app.getStateManager().getState(GameMusic.class);
music.toggleMusic();
playerInputField = new TextField("Spieler "+(app.getId()+1)); playerInputField = new TextField("Spieler "+(app.getId()+1));
// Hintergrundbild laden und hinzufügen // Hintergrundbild laden und hinzufügen
addBackgroundImage(); addBackgroundImage();
@@ -114,7 +147,7 @@ public class LobbyMenu extends Dialog {
figureDropdownContainer.setBackground(null); figureDropdownContainer.setBackground(null);
VersionedList<String> figures = new VersionedList<>(); VersionedList<String> figures = new VersionedList<>();
figures.add("Laptop"); figures.add("Computer");
figures.add("Flugzeug"); figures.add("Flugzeug");
figures.add("Jägermeister"); figures.add("Jägermeister");
figures.add("Katze"); figures.add("Katze");
@@ -122,8 +155,7 @@ public class LobbyMenu extends Dialog {
figures.add("Handyholster"); figures.add("Handyholster");
figureDropdown = new Selector<>(figures, "glass");
Selector<String> figureDropdown = new Selector<>(figures, "glass");
figureDropdown.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray)); figureDropdown.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
figureDropdown.setPreferredSize(new Vector3f(100, 20, 0)); figureDropdown.setPreferredSize(new Vector3f(100, 20, 0));
figureDropdownContainer.addChild(figureDropdown); figureDropdownContainer.addChild(figureDropdown);
@@ -131,10 +163,12 @@ public class LobbyMenu extends Dialog {
Vector3f dimens2 = figureDropdown.getPopupContainer().getPreferredSize(); Vector3f dimens2 = figureDropdown.getPopupContainer().getPreferredSize();
dimens2.setX( dimens.getX() ); dimens2.setX( dimens.getX() );
figureDropdown.getPopupContainer().setPreferredSize(new Vector3f(200,200,5)); figureDropdown.getPopupContainer().setPreferredSize(new Vector3f(200,200,5));
figureDropdown.getSelectionModel().setSelection(0);
figure = "Laptop";
addSelectionActionListener(figureDropdown, this::onDropdownSelectionChanged); // Create selection ref for updating
selectionRef = figureDropdown.getSelectionModel().createReference();
// Set default
figureDropdown.getSelectionModel().setSelection(0);
onDropdownSelectionChanged(figureDropdown);
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(100, 40, 0)); buttonContainer.setPreferredSize(new Vector3f(100, 40, 0));
@@ -162,6 +196,7 @@ public class LobbyMenu extends Dialog {
readyButton.setFontSize(18); // Adjust font size readyButton.setFontSize(18); // Adjust font size
readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.Green)); // Add color to match the style readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.Green)); // Add color to match the style
readyButton.addClickCommands(s -> ifTopDialog(() -> { readyButton.addClickCommands(s -> ifTopDialog(() -> {
music.toggleMusic();
toggleReady(); toggleReady();
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray)); readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
@@ -188,12 +223,13 @@ public class LobbyMenu extends Dialog {
1 // Höhere Z-Ebene für den Vordergrund 1 // Höhere Z-Ebene für den Vordergrund
); );
app.getGuiNode().attachChild(menuContainer); app.getGuiNode().attachChild(menuContainer);
} }
/** /**
* Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu. * Adds a background image to the lobby menu.
*/ */
private void addBackgroundImage() { private void addBackgroundImage() {
Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/lobby.png"); Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/lobby.png");
@@ -207,6 +243,11 @@ public class LobbyMenu extends Dialog {
app.getGuiNode().attachChild(background); app.getGuiNode().attachChild(background);
} }
/**
* Creates a circle graphic element for the menu.
*
* @return the created circle geometry
*/
private Geometry createCircle() { private Geometry createCircle() {
Sphere sphere = new Sphere(90,90,60.0f); Sphere sphere = new Sphere(90,90,60.0f);
@@ -214,107 +255,67 @@ public class LobbyMenu extends Dialog {
// Create a material with a solid color // Create a material with a solid color
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", idToColor()); // Set the desired color material.setColor("Color", Player.getColor(app.getId()).getColor()); // Set the desired color
circleGeometry.setMaterial(material); circleGeometry.setMaterial(material);
return circleGeometry; return circleGeometry;
} }
private ColorRGBA idToColor() {
switch (app.getId()+1) {
case 1: return PlayerColor.CYAN.getColor();
case 2: return PlayerColor.YELLOW.getColor();
case 3: return PlayerColor.RED.getColor();
case 4: return PlayerColor.PINK.getColor();
case 5: return PlayerColor.GREEN.getColor();
case 6: return PlayerColor.PURPLE.getColor();
default:
return null;
}
}
/** /**
* Schaltet den "Bereit"-Status um. * Toggles the player's ready state and sends the configuration to the server.
*/ */
private void toggleReady() { private void toggleReady() {
app.getGameLogic().send(new PlayerReady(true, playerInputField.getText(), figure, Integer.parseInt(startingCapital.getText()))); app.getGameLogic().send(new PlayerReady(true, playerInputField.getText(), figure, Integer.parseInt(startingCapital.getText())));
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();
} }
/** @Override
* Adds a custom action listener to the Selector. public void update(float tpf) {
*/ if (selectionRef.update()) {
private void addSelectionActionListener(Selector<String> selector, SelectionActionListener<String> listener) { onDropdownSelectionChanged(figureDropdown);
VersionedReference<Set<Integer>> selectionRef = selector.getSelectionModel().createReference();
app.getStateManager().attach(new BaseAppState() {
@Override
public void update(float tpf) {
if (selectionRef.update()) {
String selected = selectionRef.get().toString();
listener.onSelectionChanged(selected);
}
}
@Override
protected void initialize(Application app) {
}
@Override
protected void cleanup(Application app) {
}
@Override
protected void onEnable() {
}
@Override
protected void onDisable() {
}
});
}
/**
* Callback for when the dropdown selection changes.
*/
private void onDropdownSelectionChanged(String selected) {
app.getGameLogic().playSound(Sound.BUTTON);
switch (selected) {
case "[0]":
figure = "Laptop";
break;
case "[1]":
figure = "Flugzeug";
break;
case "[2]":
figure = "Jägermeister";
break;
case "[3]":
figure = "Katze";
break;
case "[4]":
figure = "OOP";
break;
case "[5]":
figure = "Handyholster";
break;
default:
break;
} }
} }
/** /**
* Functional interface for a selection action listener. * Updates the selected figure based on the dropdown menu selection.
*
* @param selected the selected figure
*/
private void onDropdownSelectionChanged(Selector<String> selector) {
app.getGameLogic().playSound(Sound.BUTTON);
switch (selector.getSelectedItem()) {
case "Jägermeister":
figure = "Jaegermeister";
break;
case "Handyholster":
figure = "Holster";
break;
default:
figure = selector.getSelectedItem();
break;
}
System.out.println("FIGUR:::::"+figure);
}
/**
* Functional interface for handling selection changes in dropdown menus.
*
* @param <T> the type of the selection
*/ */
@FunctionalInterface @FunctionalInterface
private interface SelectionActionListener<T> { private interface SelectionActionListener<T> {
/**
* Triggered when the selection changes.
*
* @param selection the new selection
*/
void onSelectionChanged(T selection); void onSelectionChanged(T selection);
} }
} }

View File

@@ -1,22 +0,0 @@
package pp.monopoly.client.gui;
import com.jme3.effect.ParticleMesh.Type;
import pp.monopoly.client.MonopolyApp;
/**
* Factory class responsible for creating particle effects used in the game.
* This centralizes the creation of various types of particle emitters.
*/
public class ParticleEffectFactory {
private static final int COUNT_FACTOR = 1;
private static final float COUNT_FACTOR_F = 1f;
private static final boolean POINT_SPRITE = true;
private static final Type EMITTER_TYPE = POINT_SPRITE ? Type.Point : Type.Triangle;
private final MonopolyApp app;
ParticleEffectFactory(MonopolyApp app) {
this.app = app;
}
}

View File

@@ -17,8 +17,8 @@ import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.FoodField; import pp.monopoly.model.fields.FoodField;
import pp.monopoly.model.fields.GateField; import pp.monopoly.model.fields.GateField;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound;
import java.text.Collator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@@ -43,7 +43,6 @@ public class PropertyOverviewMenu extends Dialog {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
// Make the menu fullscreen // Make the menu fullscreen
Vector3f screenSize = new Vector3f(app.getCamera().getWidth(), app.getCamera().getHeight(), 0); Vector3f screenSize = new Vector3f(app.getCamera().getWidth(), app.getCamera().getHeight(), 0);
@@ -79,7 +78,11 @@ public class PropertyOverviewMenu extends Dialog {
// Add the "Zurück" button at the bottom // Add the "Zurück" button at the bottom
Button backButton = mainContainer.addChild(new Button("Zurück", new ElementId("button"))); Button backButton = mainContainer.addChild(new Button("Zurück", new ElementId("button")));
backButton.setPreferredSize(new Vector3f(200, 60, 0)); backButton.setPreferredSize(new Vector3f(200, 60, 0));
backButton.addClickCommands(source -> this.close()); backButton.addClickCommands(source -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Attach the main container to the GUI node // Attach the main container to the GUI node
app.getGuiNode().attachChild(mainContainer); app.getGuiNode().attachChild(mainContainer);
@@ -231,6 +234,8 @@ public class PropertyOverviewMenu extends Dialog {
/** /**
* Custom listener for slider value changes. * Custom listener for slider value changes.
* Extends {@link AbstractControl} to respond to updates in the slider's value and refresh
* the visible cards accordingly.
*/ */
private class SliderValueChangeListener extends AbstractControl { private class SliderValueChangeListener extends AbstractControl {
@Override @Override
@@ -240,6 +245,14 @@ public class PropertyOverviewMenu extends Dialog {
refreshVisibleCards(sliderValue); refreshVisibleCards(sliderValue);
} }
/**
* Overrides the rendering logic for the control.
* <p>
* This implementation does not require any rendering operations, so the method is left empty.
*
* @param renderManager the {@link RenderManager} handling the rendering process.
* @param viewPort the {@link ViewPort} associated with the rendering context.
*/
@Override @Override
protected void controlRender(RenderManager renderManager, ViewPort viewPort) { protected void controlRender(RenderManager renderManager, ViewPort viewPort) {
// No rendering logic needed // No rendering logic needed

View File

@@ -14,7 +14,6 @@ import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.style.ElementId; import com.simsilica.lemur.style.ElementId;
import static pp.monopoly.Resources.lookup;
import pp.monopoly.client.GameMusic; import pp.monopoly.client.GameMusic;
import pp.monopoly.client.GameSound; import pp.monopoly.client.GameSound;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
@@ -25,15 +24,30 @@ import pp.monopoly.notification.Sound;
import static pp.util.PreferencesUtils.getPreferences; import static pp.util.PreferencesUtils.getPreferences;
/** /**
* The Menu class represents the main menu in the Battleship game application. * The Menu class represents the main menu in the Monopoly game application.
* It extends the Dialog class and provides functionalities for loading, saving, * It extends the Dialog class and provides functionalities for Volume adjustment, Sound adjustment,
* returning to the game, and quitting the application. * returning to the game, and quitting the application.
*/ */
public class SettingsMenu extends Dialog { public class SettingsMenu extends Dialog {
/**
* Preferences instance for storing and retrieving settings specific to the SettingsMenu.
*/
private static final Preferences PREFERENCES = getPreferences(SettingsMenu.class); private static final Preferences PREFERENCES = getPreferences(SettingsMenu.class);
private static final String LAST_PATH = "last.file.path";
/**
* Reference to the main Monopoly application instance.
*/
private final MonopolyApp app; private final MonopolyApp app;
/**
* Slider control for adjusting the music volume.
*/
private final VolumeSlider musicSlider; private final VolumeSlider musicSlider;
/**
* Slider control for adjusting the sound effects volume.
*/
private final SoundSlider soundSlider; private final SoundSlider soundSlider;
/** /**

View File

@@ -5,7 +5,14 @@ import pp.monopoly.client.GameSound;
public class SoundSlider extends Slider { public class SoundSlider extends Slider {
/**
* Manages sound effects for the game.
*/
private final pp.monopoly.client.GameSound sound; private final pp.monopoly.client.GameSound sound;
/**
* Volume level for the game sounds.
*/
private double vol; private double vol;
/** /**
@@ -20,7 +27,7 @@ public class SoundSlider extends Slider {
} }
/** /**
* when triggered it updates the volume to the value set with the slider * When triggered it updates the volume to the value set with the slider
*/ */
public void update() { public void update() {
if (vol != getModel().getPercent()) { if (vol != getModel().getPercent()) {

View File

@@ -18,7 +18,6 @@ import pp.monopoly.notification.Sound;
/** /**
* Constructs the startup menu dialog for the Monopoly application. * Constructs the startup menu dialog for the Monopoly application.
import pp.monopoly.client.gui.GameMenu;
*/ */
public class StartMenu extends Dialog { public class StartMenu extends Dialog {
private final MonopolyApp app; private final MonopolyApp app;
@@ -42,25 +41,24 @@ public class StartMenu extends Dialog {
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); // Ensure it is behind other GUI elements background.setLocalTranslation(0, 0, -1);
app.getGuiNode().attachChild(background); app.getGuiNode().attachChild(background);
// 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));
Button startButton = new Button("Spielen"); Button startButton = new Button("Spielen");
startButton.setPreferredSize(new Vector3f(190, 60, 0)); // Increase button size (width, height) startButton.setPreferredSize(new Vector3f(190, 60, 0));
startButton.setFontSize(40); // Set the font size for the button text startButton.setFontSize(40);
startButton.setTextHAlignment(HAlignment.Center); // Center the text horizontally startButton.setTextHAlignment(HAlignment.Center);
startButton.addClickCommands(s -> ifTopDialog(() -> { startButton.addClickCommands(s -> ifTopDialog(() -> {
close(); close();
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
app.connect(); // Perform the connection logic app.connect();
})); }));
centerMenu.addChild(startButton); centerMenu.addChild(startButton);
// Position the center container in the middle of the screen
centerMenu.setLocalTranslation(new Vector3f(screenWidth / 2f - centerMenu.getPreferredSize().x / 2f, centerMenu.setLocalTranslation(new Vector3f(screenWidth / 2f - centerMenu.getPreferredSize().x / 2f,
screenHeight / 2f - 280 + centerMenu.getPreferredSize().y / 2f, screenHeight / 2f - 280 + centerMenu.getPreferredSize().y / 2f,
0)); 0));
@@ -74,38 +72,32 @@ public class StartMenu extends Dialog {
QuadBackgroundComponent logoBackground = new QuadBackgroundComponent(logoTexture); QuadBackgroundComponent logoBackground = new QuadBackgroundComponent(logoTexture);
logoContainer.setBackground(logoBackground); logoContainer.setBackground(logoBackground);
// Set the size of the container to fit the logo
float logoWidth = 512; // Adjust these values based on the logo dimensions float logoWidth = 512;
float logoHeight = 128; // Adjust these values based on the logo dimensions float logoHeight = 128;
logoContainer.setPreferredSize(new Vector3f(logoWidth, logoHeight, 0)); logoContainer.setPreferredSize(new Vector3f(logoWidth, logoHeight, 0));
// Position the container at the center of the screen
logoContainer.setLocalTranslation(new Vector3f( logoContainer.setLocalTranslation(new Vector3f(
screenWidth / 2f - logoWidth / 2f, screenWidth / 2f - logoWidth / 2f,
screenHeight / 2f + 200, // Adjust this value for vertical position screenHeight / 2f + 200,
0 0
)); ));
// Attach the container to the GUI node
app.getGuiNode().attachChild(logoContainer); app.getGuiNode().attachChild(logoContainer);
// 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");
// Create a container for the Unibw logo
Container unibwContainer = new Container(); Container unibwContainer = new Container();
QuadBackgroundComponent unibwBackground = new QuadBackgroundComponent(unibwTexture); QuadBackgroundComponent unibwBackground = new QuadBackgroundComponent(unibwTexture);
unibwContainer.setBackground(unibwBackground); unibwContainer.setBackground(unibwBackground);
// Set the size of the container to fit the Unibw logo float unibwWidth = 512;
float unibwWidth = 512; // Adjust these values based on the logo dimensions float unibwHeight = 128;
float unibwHeight = 128; // Adjust these values based on the logo dimensions
unibwContainer.setPreferredSize(new Vector3f(unibwWidth, unibwHeight, 0)); unibwContainer.setPreferredSize(new Vector3f(unibwWidth, unibwHeight, 0));
// Position the container slightly below the Monopoly logo
unibwContainer.setLocalTranslation(new Vector3f( unibwContainer.setLocalTranslation(new Vector3f(
screenWidth / 2f - unibwWidth / 2f, screenWidth / 2f - unibwWidth / 2f,
screenHeight / 2f + 100, // Adjust this value for vertical position screenHeight / 2f + 100,
0 0
)); ));
@@ -113,11 +105,17 @@ public class StartMenu extends Dialog {
app.getGuiNode().attachChild(unibwContainer); app.getGuiNode().attachChild(unibwContainer);
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();
} }
/**
* Closes the startup menu and detaches all GUI elements.
*/
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachAllChildren(); app.getGuiNode().detachAllChildren();

View File

@@ -5,13 +5,19 @@ import java.util.List;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.AbstractControl;
import com.jme3.texture.Texture;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.popups.AcceptTrade;
import pp.monopoly.client.gui.popups.BuildingPropertyCard; import pp.monopoly.client.gui.popups.BuildingPropertyCard;
import pp.monopoly.client.gui.popups.ConfirmTrade; import pp.monopoly.client.gui.popups.ConfirmTrade;
import pp.monopoly.client.gui.popups.EventCardPopup; import pp.monopoly.client.gui.popups.EventCardPopup;
@@ -21,12 +27,15 @@ import pp.monopoly.client.gui.popups.Gulag;
import pp.monopoly.client.gui.popups.GulagInfo; import pp.monopoly.client.gui.popups.GulagInfo;
import pp.monopoly.client.gui.popups.LooserPopUp; import pp.monopoly.client.gui.popups.LooserPopUp;
import pp.monopoly.client.gui.popups.NoMoneyWarning; import pp.monopoly.client.gui.popups.NoMoneyWarning;
import pp.monopoly.client.gui.popups.ReceivedRent;
import pp.monopoly.client.gui.popups.RejectTrade;
import pp.monopoly.client.gui.popups.Rent; import pp.monopoly.client.gui.popups.Rent;
import pp.monopoly.client.gui.popups.TimeOut; import pp.monopoly.client.gui.popups.TimeOut;
import pp.monopoly.client.gui.popups.WinnerPopUp; import pp.monopoly.client.gui.popups.WinnerPopUp;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
import pp.monopoly.game.server.PlayerHandler; import pp.monopoly.game.server.PlayerHandler;
import pp.monopoly.message.server.NotificationMessage; import pp.monopoly.message.server.NotificationMessage;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.model.fields.BuildingProperty; import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.FoodField; import pp.monopoly.model.fields.FoodField;
import pp.monopoly.model.fields.GateField; import pp.monopoly.model.fields.GateField;
@@ -44,12 +53,12 @@ public class TestWorld implements GameEventListener {
private PlayerHandler playerHandler; private PlayerHandler playerHandler;
private CameraController cameraController; private CameraController cameraController;
private Toolbar toolbar; private Toolbar toolbar;
private List<String> existingHouses = new ArrayList<>();
/** /**
* Konstruktor für die TestWorld. * Konstruktor für die TestWorld.
* *
* @param app Die Hauptanwendung * @param app Die Hauptanwendung
* @param players Die Liste der Spieler mit ihren Figuren
*/ */
public TestWorld(MonopolyApp app) { public TestWorld(MonopolyApp app) {
this.app = app; this.app = app;
@@ -71,6 +80,7 @@ public class TestWorld implements GameEventListener {
//Füge Inhalte ein //Füge Inhalte ein
setSkyColor(); setSkyColor();
createBoard(); createBoard();
addLighting();
createPlayerFigures(); createPlayerFigures();
toolbar = new Toolbar(app); toolbar = new Toolbar(app);
toolbar.open(); toolbar.open();
@@ -91,9 +101,9 @@ public class TestWorld implements GameEventListener {
com.jme3.scene.shape.Box box = new com.jme3.scene.shape.Box(10, 0.1f, 10); com.jme3.scene.shape.Box box = new com.jme3.scene.shape.Box(10, 0.1f, 10);
com.jme3.scene.Geometry geom = new com.jme3.scene.Geometry("Board", box); com.jme3.scene.Geometry geom = new com.jme3.scene.Geometry("Board", box);
com.jme3.material.Material mat = new com.jme3.material.Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
com.jme3.texture.Texture texture = app.getAssetManager().loadTexture("Pictures/board2.png"); Texture texture = app.getAssetManager().loadTexture("Pictures/board2.png");
mat.setTexture("ColorMap", texture); mat.setTexture("DiffuseMap", texture);
geom.setMaterial(mat); geom.setMaterial(mat);
geom.setLocalTranslation(0, -0.1f, 0); geom.setLocalTranslation(0, -0.1f, 0);
@@ -103,33 +113,79 @@ public class TestWorld implements GameEventListener {
geom.setLocalRotation(rotation); geom.setLocalRotation(rotation);
app.getRootNode().attachChild(geom); app.getRootNode().attachChild(geom);
System.out.println("Spielbrett erfolgreich erstellt, gedreht und hinzugefügt.");
} catch (Exception e) { } catch (Exception e) {
System.err.println("Fehler beim Erstellen des Spielfelds: " + e.getMessage()); System.err.println("Fehler beim Erstellen des Spielfelds: " + e.getMessage());
} }
} }
private void addLighting() {
// Direktionales Licht
DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(-0.5f, -0.7f, -1.0f).normalizeLocal());
app.getRootNode().addLight(sun);
// Umgebungslicht
AmbientLight ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.6f, 0.6f, 0.6f, 1.0f));
app.getRootNode().addLight(ambient);
}
private com.jme3.math.Quaternion calculateRotationForField(int fieldID) {
com.jme3.math.Quaternion rotation = new com.jme3.math.Quaternion();
// Berechne die Rotation basierend auf der Feld-ID
if (fieldID >= 0 && fieldID <= 9) {
// Untere Seite (0-9)
rotation.fromAngleAxis(0, Vector3f.UNIT_Y); // Richtung: nach oben
} else if (fieldID >= 10 && fieldID <= 19) {
// Rechte Seite (10-19)
rotation.fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y); // Richtung: nach links
} else if (fieldID >= 20 && fieldID <= 29) {
// Obere Seite (20-29)
rotation.fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y); // Richtung: nach unten
} else if (fieldID >= 30 && fieldID <= 39) {
// Linke Seite (30-39)
rotation.fromAngleAxis(3 * FastMath.HALF_PI, Vector3f.UNIT_Y); // Richtung: nach rechts
}
// Korrigiere die Richtung für die Quadranten 1019 und 3039 (gegenüberliegende Richtung)
if ((fieldID >= 10 && fieldID <= 19) || (fieldID >= 30 && fieldID <= 39)) {
com.jme3.math.Quaternion oppositeDirection = new com.jme3.math.Quaternion();
oppositeDirection.fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y); // 180° drehen
rotation = rotation.multLocal(oppositeDirection);
}
// Füge zusätzliche 90° nach links hinzu
com.jme3.math.Quaternion leftTurn = new com.jme3.math.Quaternion();
leftTurn.fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y); // 90° nach links
rotation = rotation.multLocal(leftTurn);
return rotation;
}
/** /**
* Erstellt die Spielfiguren basierend auf der bereits bekannten Spielerliste. * Erstellt die Spielfiguren basierend auf der bereits bekannten Spielerliste.
*/ */
private void createPlayerFigures() { private void createPlayerFigures() {
for (int i = 0; i < playerHandler.getPlayers().size(); i++) { for (Player player : playerHandler.getPlayers()) {
Player player = playerHandler.getPlayers().get(i);
try { try {
// Lade das Modell
com.jme3.scene.Spatial model = app.getAssetManager().loadModel( com.jme3.scene.Spatial model = app.getAssetManager().loadModel(
"models/" + player.getFigure().getType() + "/" + player.getFigure().getType() + ".j3o" "models/" + "Spielfiguren/" + player.getFigure().getType() + "/" + player.getFigure().getType() + ".j3o");
);
// Skaliere und positioniere das Modell
model.setLocalScale(0.5f); model.setLocalScale(0.5f);
Vector3f startPosition = calculateFieldPosition(player.getFieldID(), player.getId());
int playerIndexOnField = calculatePlayerIndexOnField(player.getFieldID(), player.getId());
Vector3f startPosition = calculateFieldPosition(player.getFieldID(), playerIndexOnField);
model.setLocalTranslation(startPosition); model.setLocalTranslation(startPosition);
// Setze die Rotation basierend auf der Feld-ID
model.setLocalRotation(calculateRotationForField(player.getFieldID()));
model.setName("PlayerFigure_" + player.getId()); model.setName("PlayerFigure_" + player.getId());
// Füge das Modell zur Szene hinzu
app.getRootNode().attachChild(model); app.getRootNode().attachChild(model);
System.out.println("Figur für Spieler " + player.getId() + " erstellt bei " + startPosition);
} catch (Exception e) { } catch (Exception e) {
System.err.println("Fehler beim Laden des Modells für Spieler " + player.getId() + ": " + e.getMessage()); System.err.println("Fehler beim Laden des Modells für Spieler " + player.getId() + ": " + e.getMessage());
} }
@@ -197,27 +253,21 @@ public class TestWorld implements GameEventListener {
com.jme3.scene.Spatial figure = app.getRootNode().getChild(figureName); com.jme3.scene.Spatial figure = app.getRootNode().getChild(figureName);
if (figure != null) { if (figure != null) {
// Berechne das aktuelle Feld basierend auf der Position der Figur // Füge einen Delay hinzu (z.B. 3 Sekunden)
int startFieldID = getFieldIDFromPosition(figure.getLocalTranslation()); Timer timer = new Timer();
int targetFieldID = player.getFieldID(); timer.schedule(new TimerTask() {
@Override
public void run() {
app.enqueue(() -> {
// Setze die Position
Vector3f targetPosition = calculateFieldPosition(player.getFieldID(), player.getId());
figure.setLocalTranslation(targetPosition);
// Bewege die Figur nur, wenn das Ziel-Feld unterschiedlich ist // Aktualisiere die Rotation basierend auf der Feld-ID
if (startFieldID != targetFieldID) { figure.setLocalRotation(calculateRotationForField(player.getFieldID()));
// Verzögerung vor Start der Animation (z.B. 3 Sekunden) });
Timer timer = new Timer(); }
timer.schedule(new TimerTask() { }, 3000); // 3000 Millisekunden Delay
@Override
public void run() {
// Berechne den Pfad basierend auf den Feld-IDs
List<Vector3f> pathPoints = calculatePath(startFieldID, targetFieldID, playerIndexOnField);
// Starte die Animation entlang des Pfads
animateMovementAlongPath(figure, pathPoints);
}
}, 3000); // Verzögerung von 3000ms (3 Sekunden)
} else {
System.out.println("Figur für Spieler " + player.getId() + " bleibt auf dem gleichen Feld.");
}
} else { } else {
System.err.println("Figur für Spieler " + player.getId() + " nicht gefunden."); System.err.println("Figur für Spieler " + player.getId() + " nicht gefunden.");
} }
@@ -385,9 +435,114 @@ public class TestWorld implements GameEventListener {
new GulagInfo(app, 1).open(); new GulagInfo(app, 1).open();
} else if (event.msg().equals("jailpay")) { } else if (event.msg().equals("jailpay")) {
new GulagInfo(app, 3).open(); new GulagInfo(app, 3).open();
} else if (event.msg().equals("tradepos")) {
new AcceptTrade(app, (TradeReply) event.message()).open();
} else if (event.msg().equals("tradeneg")) {
new RejectTrade(app, (TradeReply) event.message()).open();
} else if (event.msg().equals("ReceivedRent")) {
new ReceivedRent(app, ( (NotificationMessage) event.message()).getRentOwner(), ( (NotificationMessage) event.message()).getRentAmount() ).open();
} }
} }
private Vector3f calculateBuildingPosition(int fieldID) {
float baseX = 0.0f;
float baseZ = 0.0f;
switch (fieldID) {
case 0: baseX = -8.4f; baseZ = -7.7f; break;
case 1: baseX = -6.3f; baseZ = -7.7f; break;
case 2: baseX = -4.7f; baseZ = -7.7f; break;
case 3: baseX = -3.1f; baseZ = -7.7f; break;
case 4: baseX = -1.4f; baseZ = -7.7f; break;
case 5: baseX = 0.2f; baseZ = -7.7f; break;
case 6: baseX = 1.8f; baseZ = -7.7f; break;
case 7: baseX = 3.5f; baseZ = -7.7f; break;
case 8: baseX = 5.1f; baseZ = -7.7f; break;
case 9: baseX = 6.7f; baseZ = -7.7f; break;
case 10: baseX = 8.2f; baseZ = -7.7f; break;
case 11: baseX = 8.2f; baseZ = -6.5f; break; //passt
case 12: baseX = 8.2f; baseZ = -4.9f; break; //passt
case 13: baseX = 8.2f; baseZ = -3.3f; break; //passt
case 14: baseX = 8.2f; baseZ = -1.6f; break; //passt
case 15: baseX = 8.2f; baseZ = 0.0f; break; //passt
case 16: baseX = 8.2f; baseZ = 1.6f; break; //passt
case 17: baseX = 8.2f; baseZ = 3.3f; break; //passt
case 18: baseX = 8.2f; baseZ = 4.9f; break; //passt
case 19: baseX = 8.2f; baseZ = 6.5f; break; //passt
case 20: baseX = 8.2f; baseZ = 7.7f; break;
case 21: baseX = 6.5f; baseZ = 7.7f; break;
case 22: baseX = 4.9f; baseZ = 7.7f; break;
case 23: baseX = 3.3f; baseZ = 7.7f; break;
case 24: baseX = 1.6f; baseZ = 7.7f; break;
case 25: baseX = 0.0f; baseZ = 7.7f; break;
case 26: baseX = -1.6f; baseZ = 7.7f; break;
case 27: baseX = -3.3f; baseZ = 7.7f; break;
case 28: baseX = -4.9f; baseZ = 7.7f; break;
case 29: baseX = -6.5f; baseZ = 7.7f; break;
case 30: baseX = -7.2f; baseZ = 7.7f; break;
case 31: baseX = -7.2f; baseZ = 6.5f; break;
case 32: baseX = -7.2f; baseZ = 4.9f; break;
case 33: baseX = -7.2f; baseZ = 3.3f; break;
case 34: baseX = -7.2f; baseZ = 1.6f; break;
case 35: baseX = -7.2f; baseZ = 0.0f; break;
case 36: baseX = -7.2f; baseZ = -1.6f; break;
case 37: baseX = -7.2f; baseZ = -3.3f; break;
case 38: baseX = -7.2f; baseZ = -4.9f; break;
case 39: baseX = -7.2f; baseZ = -6.5f; break;
default: throw new IllegalArgumentException("Ungültige Feld-ID: " + fieldID);
}
return new Vector3f(baseX, 0, baseZ);
}
private void updateHousesOnBoard() {
app.enqueue(() -> {
List<BuildingProperty> propertiesWithBuildings = app.getGameLogic().getBoardManager().getPropertiesWithBuildings();
for (BuildingProperty property : propertiesWithBuildings) {
int houseCount = property.getHouses();
int hotelCount = property.getHotel();
String uniqueIdentifier = "Building_" + property.getId() + "_" + (hotelCount > 0 ? "Hotel" : houseCount);
if (existingHouses.contains(uniqueIdentifier)) continue;
try {
String modelPath = hotelCount > 0
? "models/Hotel/Hotel.j3o"
: "models/Haus/" + houseCount + "Haus.j3o";
com.jme3.scene.Spatial buildingModel = app.getAssetManager().loadModel(modelPath);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
buildingModel.setMaterial(mat);
buildingModel.setLocalScale(0.5f);
Vector3f position = calculateBuildingPosition(property.getId()).add(0, 0.5f, 0);
buildingModel.setLocalTranslation(position);
com.jme3.math.Quaternion rotation = new com.jme3.math.Quaternion();
if (property.getId() >= 1 && property.getId() <= 10) {
rotation.fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y);
} else if (property.getId() >= 21 && property.getId() <= 30) {
rotation.fromAngleAxis(3 * FastMath.HALF_PI, Vector3f.UNIT_Y);
} else if (property.getId() >= 31 && property.getId() <= 39) {
rotation.fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y);
}
buildingModel.setLocalRotation(rotation);
buildingModel.setName(uniqueIdentifier);
app.getRootNode().attachChild(buildingModel);
existingHouses.add(uniqueIdentifier);
} catch (Exception e) {
System.err.println("Fehler beim Hinzufügen eines Gebäudes: " + e.getMessage());
}
}
});
}
@Override @Override
public void receivedEvent(EventCardEvent event) { public void receivedEvent(EventCardEvent event) {
Timer timer = new Timer(); Timer timer = new Timer();
@@ -405,5 +560,6 @@ public class TestWorld implements GameEventListener {
for (Player player : playerHandler.getPlayers()) { for (Player player : playerHandler.getPlayers()) {
movePlayerFigure(player); movePlayerFigure(player);
} }
updateHousesOnBoard();
} }
} }

View File

@@ -3,10 +3,13 @@ package pp.monopoly.client.gui;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f; import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
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;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.IconComponent; import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
@@ -25,23 +28,91 @@ import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
import pp.monopoly.notification.UpdatePlayerView; import pp.monopoly.notification.UpdatePlayerView;
/**
* Represents the toolbar interface in the Monopoly application.
* <p>
* This class provides game controls, player information, and event handling
* for actions such as dice rolling, trading, and ending turns.
* Implements {@link GameEventListener} to respond to game events.
* </p>
*/
public class Toolbar extends Dialog implements GameEventListener { public class Toolbar extends Dialog implements GameEventListener {
/**
* Reference to the Monopoly application instance.
*/
private final MonopolyApp app; private final MonopolyApp app;
/**
* The main container for the toolbar interface.
*/
private final Container toolbarContainer; private final Container toolbarContainer;
/**
* Container for displaying an overview of other players.
*/
private Container overviewContainer; private Container overviewContainer;
/**
* Container for displaying account-related information.
*/
private Container accountContainer; private Container accountContainer;
/**
* Handles player-related data and actions.
*/
private PlayerHandler playerHandler; private PlayerHandler playerHandler;
/**
* Label for the first dice display.
*/
private Label imageLabel; private Label imageLabel;
/**
* Label for the second dice display.
*/
private Label imageLabel2; private Label imageLabel2;
/**
* Button for rolling the dice.
*/
private Button diceButton; private Button diceButton;
/**
* Button for initiating trades.
*/
private Button tradeButton; private Button tradeButton;
/**
* Button for accessing the property menu.
*/
private Button propertyMenuButton; private Button propertyMenuButton;
/**
* Button for ending the player's turn.
*/
private Button endTurnButton; private Button endTurnButton;
private volatile boolean animatingDice = false; /**
private volatile DiceRollEvent latestDiceRollEvent = null; * Stores the most recent dice roll event.
*/
private DiceRollEvent latestDiceRollEvent = null;
/**Indicates if the bankrupt PopUp has already been shown */
private boolean bankruptPopUp = false;
/**
* Constructs the toolbar for the Monopoly application.
* <p>
* Initializes the toolbar interface, adds event listeners, and sets up
* the GUI elements such as dice, buttons, and player information displays.
* </p>
*
* @param app the Monopoly application instance
*/
public Toolbar(MonopolyApp app) { public Toolbar(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -54,14 +125,16 @@ public class Toolbar extends Dialog implements GameEventListener {
} }
private Container createToolbarContainer() { private Container createToolbarContainer() {
// Erstelle den Hauptcontainer
Container container = new Container(new SpringGridLayout(Axis.X, Axis.Y), "toolbar"); Container container = new Container(new SpringGridLayout(Axis.X, Axis.Y), "toolbar");
container.setLocalTranslation(0, 200, 0); container.setLocalTranslation(0, 200, 0);
container.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 200, 0)); container.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 200, 0));
Texture backgroundToolbar = app.getAssetManager().loadTexture("Pictures/toolbarbg.png");
QuadBackgroundComponent background = new QuadBackgroundComponent(backgroundToolbar);
container.setBackground(background);
// Spielerfarbe abrufen // Spielerfarbe abrufen
Player currentPlayer = playerHandler.getPlayerById(app.getId()); Player currentPlayer = playerHandler.getPlayerById(app.getId());
ColorRGBA playerColor = currentPlayer.getColor().getColor(); ColorRGBA playerColor = Player.getColor(currentPlayer.getId()).getColor();
// Oberer Balken // Oberer Balken
Container playerColorBar = new Container(); Container playerColorBar = new Container();
@@ -105,11 +178,11 @@ public class Toolbar extends Dialog implements GameEventListener {
menuContainer.addChild(createTradeButton()); menuContainer.addChild(createTradeButton());
menuContainer.addChild(createPropertyMenuButton()); menuContainer.addChild(createPropertyMenuButton());
menuContainer.addChild(createEndTurnButton()); menuContainer.addChild(createEndTurnButton());
menuContainer.setBackground(createBackground()); menuContainer.setBackground(null);
return container; return container;
} }
private Container createDiceSection() { private Container createDiceSection() {
Container diceContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y)); Container diceContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
@@ -120,6 +193,7 @@ public class Toolbar extends Dialog implements GameEventListener {
diceButton.setPreferredSize(new Vector3f(200, 50, 0)); diceButton.setPreferredSize(new Vector3f(200, 50, 0));
diceButton.addClickCommands(s -> ifTopDialog(() -> { diceButton.addClickCommands(s -> ifTopDialog(() -> {
diceButton.setEnabled(false); diceButton.setEnabled(false);
endTurnButton.setEnabled(true);
startDiceAnimation(); startDiceAnimation();
app.getGameLogic().send(new RollDice()); app.getGameLogic().send(new RollDice());
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
@@ -160,18 +234,39 @@ public class Toolbar extends Dialog implements GameEventListener {
} }
private Button createTradeButton() { private Button createTradeButton() {
tradeButton = new Button("Handeln", new ElementId("button-toolbar"));
tradeButton = new Button("", new ElementId("button-toolbar"));
tradeButton.setPreferredSize(new Vector3f(150, 50, 0)); tradeButton.setPreferredSize(new Vector3f(150, 50, 0));
tradeButton.addClickCommands(s -> ifTopDialog(() -> {
String iconTradePath = "icons/icon-handeln.png";
IconComponent iconTrade = new IconComponent(iconTradePath);
iconTrade.setHAlignment(HAlignment.Center);
iconTrade.setVAlignment(VAlignment.Center);
iconTrade.setIconSize(new Vector2f(100, 100));
tradeButton.setIcon(iconTrade);
tradeButton.setFontSize(40);
// Add click behavior
tradeButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
new ChoosePartner(app).open(); new ChoosePartner(app).open();
})); }));
return tradeButton; return tradeButton;
} }
private Button createPropertyMenuButton() { private Button createPropertyMenuButton() {
propertyMenuButton = new Button("Grundstücke", new ElementId("button-toolbar")); propertyMenuButton = new Button("", new ElementId("button-toolbar"));
propertyMenuButton.setPreferredSize(new Vector3f(150, 50, 0)); propertyMenuButton.setPreferredSize(new Vector3f(150, 50, 0));
String iconBuildingPath = "icons/icon-gebaude.png";
IconComponent iconBuilding = new IconComponent(iconBuildingPath);
iconBuilding.setHAlignment(HAlignment.Center);
iconBuilding.setVAlignment(VAlignment.Center);
iconBuilding.setIconSize(new Vector2f(75, 75));
propertyMenuButton.setIcon(iconBuilding);
propertyMenuButton.setFontSize(30); propertyMenuButton.setFontSize(30);
propertyMenuButton.addClickCommands(s -> ifTopDialog(() -> { propertyMenuButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
@@ -181,14 +276,24 @@ public class Toolbar extends Dialog implements GameEventListener {
} }
private Button createEndTurnButton() { private Button createEndTurnButton() {
endTurnButton = new Button("Zug beenden", new ElementId("button-toolbar")); endTurnButton = new Button("", new ElementId("button-toolbar"));
endTurnButton.setFontSize(28); endTurnButton.setFontSize(28);
endTurnButton.setPreferredSize(new Vector3f(150, 50, 0)); endTurnButton.setPreferredSize(new Vector3f(150, 50, 0));
String iconEndTurnPath = "icons/icon-zugbeenden.png";
IconComponent iconEndTurn = new IconComponent(iconEndTurnPath);
iconEndTurn.setHAlignment(HAlignment.Center);
iconEndTurn.setVAlignment(VAlignment.Center);
iconEndTurn.setIconSize(new Vector2f(75, 75));
endTurnButton.setIcon(iconEndTurn);
endTurnButton.addClickCommands(s -> ifTopDialog(() -> { endTurnButton.addClickCommands(s -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
if (app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getAccountBalance() < 0) { if (app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getAccountBalance() < 0 && !bankruptPopUp) {
new Bankrupt(app).open(); new Bankrupt(app).open();
bankruptPopUp = true;
} else { } else {
bankruptPopUp = false;
app.getGameLogic().send(new EndTurn()); app.getGameLogic().send(new EndTurn());
receivedEvent(new ButtonStatusEvent(false)); receivedEvent(new ButtonStatusEvent(false));
} }
@@ -196,18 +301,12 @@ public class Toolbar extends Dialog implements GameEventListener {
return endTurnButton; return endTurnButton;
} }
private QuadBackgroundComponent createBackground() {
return new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f));
}
private void startDiceAnimation() { private void startDiceAnimation() {
animatingDice = true;
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
new Thread(() -> { new Thread(() -> {
try { try {
animateDice(startTime); animateDice(startTime);
animatingDice = false;
if (latestDiceRollEvent != null) { if (latestDiceRollEvent != null) {
showFinalDiceResult(latestDiceRollEvent); showFinalDiceResult(latestDiceRollEvent);
} }
@@ -216,7 +315,10 @@ public class Toolbar extends Dialog implements GameEventListener {
} }
}).start(); }).start();
} }
/**
* Animates the dice roll by cycling through dice images.
*/
private void animateDice(long startTime) throws InterruptedException { private void animateDice(long startTime) throws InterruptedException {
int[] currentFace = {1}; int[] currentFace = {1};
while (System.currentTimeMillis() - startTime < 2000) { // Animation duration while (System.currentTimeMillis() - startTime < 2000) { // Animation duration
@@ -233,7 +335,12 @@ public class Toolbar extends Dialog implements GameEventListener {
Thread.sleep(100); // Time between frame updates Thread.sleep(100); // Time between frame updates
} }
} }
/**
* Displays the final dice result after animation.
*
* @param event the dice roll event containing the result
*/
private void showFinalDiceResult(DiceRollEvent event) { private void showFinalDiceResult(DiceRollEvent event) {
app.enqueue(() -> { app.enqueue(() -> {
setDiceIcon(imageLabel, diceToString(event.a())); setDiceIcon(imageLabel, diceToString(event.a()));
@@ -260,11 +367,21 @@ public class Toolbar extends Dialog implements GameEventListener {
} }
} }
/**
* Handles dice roll events by updating the dice display.
*
* @param event the dice roll event containing dice values
*/
@Override @Override
public void receivedEvent(DiceRollEvent event) { public void receivedEvent(DiceRollEvent event) {
latestDiceRollEvent = event; latestDiceRollEvent = event;
} }
/**
* Updates the player view with the latest account and overview data.
*
* @param event the update event for the player view
*/
@Override @Override
public void receivedEvent(UpdatePlayerView event) { public void receivedEvent(UpdatePlayerView event) {
playerHandler = app.getGameLogic().getPlayerHandler(); playerHandler = app.getGameLogic().getPlayerHandler();
@@ -288,7 +405,7 @@ public class Toolbar extends Dialog implements GameEventListener {
for (Player player : playerHandler.getPlayers()) { for (Player player : playerHandler.getPlayers()) {
if (player.getId() != app.getId()) { if (player.getId() != app.getId()) {
// Spielerfarbe abrufen // Spielerfarbe abrufen
ColorRGBA playerColor = (player.getColor().getColor()); ColorRGBA playerColor = (Player.getColor(player.getId()).getColor());
// Label für den Spieler erstellen // Label für den Spieler erstellen
Label playerLabel = new Label( Label playerLabel = new Label(
@@ -306,26 +423,40 @@ public class Toolbar extends Dialog implements GameEventListener {
overviewContainer.setBackground(null); overviewContainer.setBackground(null);
} }
/**
* Updates the enabled status of toolbar buttons based on the event.
*
* @param event the button status event
*/
@Override @Override
public void receivedEvent(ButtonStatusEvent event) { public void receivedEvent(ButtonStatusEvent event) {
boolean enabled = event.buttonsEnabled(); boolean enabled = event.buttonsEnabled();
diceButton.setEnabled(enabled); diceButton.setEnabled(enabled);
tradeButton.setEnabled(enabled); tradeButton.setEnabled(enabled);
propertyMenuButton.setEnabled(enabled); propertyMenuButton.setEnabled(enabled);
endTurnButton.setEnabled(enabled); endTurnButton.setEnabled(false);
} }
/**
* Closes the toolbar and detaches it from the GUI.
*/
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(toolbarContainer); app.getGuiNode().detachChild(toolbarContainer);
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();
} }
/**
* Updates the toolbar by refreshing player information.
*/
@Override @Override
public void update() { public void update() {
receivedEvent(new UpdatePlayerView()); receivedEvent(new UpdatePlayerView());

View File

@@ -1,168 +0,0 @@
package pp.monopoly.client.gui;
import java.util.Random;
import com.jme3.font.BitmapText;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.monopoly.client.MonopolyApp;
/**
* Toolbar Klasse, die am unteren Rand der Szene angezeigt wird.
* Die Buttons bewegen den Würfel auf dem Spielfeld.
*/
public class Toolbar2 {
private final MonopolyApp app;
private final Container toolbarContainer;
private final Geometry cube; // Referenz auf den Würfel
private final BitmapText positionText; // Anzeige für die aktuelle Position
private final float boardLimit = 0.95f; // Grenzen des Bretts
private final float stepSize = 0.18f; // Schrittgröße pro Bewegung
private int currentPosition = 0; // Aktuelle Position auf dem Spielfeld
private final int positionsPerSide = 10; // Anzahl der Positionen pro Seite
private final Random random = new Random(); // Zufallsgenerator für den Würfelwurf
/**
* Konstruktor für die Toolbar.
*
* @param app Die Hauptanwendung (MonopolyApp)
* @param cube Der Würfel, der bewegt werden soll
*/
public Toolbar2(MonopolyApp app, Geometry cube) {
this.app = app;
this.cube = cube;
// Erstelle die Toolbar
toolbarContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
// Setze die Position am unteren Rand und die Breite
toolbarContainer.setLocalTranslation(
0, // Links bündig
100, // Höhe über dem unteren Rand
0 // Z-Ebene
);
toolbarContainer.setPreferredSize(new Vector3f(app.getCamera().getWidth(), 100, 0)); // Volle Breite
// Füge Buttons zur Toolbar hinzu
initializeButtons();
// Füge die Toolbar zur GUI hinzu
app.getGuiNode().attachChild(toolbarContainer);
// Erstelle die Position-Anzeige
positionText = createPositionDisplay();
updatePositionDisplay(); // Initialisiere die Anzeige mit der Startposition
}
/**
* Initialisiert die Buttons in der Toolbar.
*/
private void initializeButtons() {
addButton("Vorwärts", 1); // Bewegung nach vorne
addButton("Rückwärts", -1); // Bewegung nach hinten
addDiceRollButton(); // Würfel-Button
}
/**
* Fügt einen Button mit einer Bewegung hinzu.
*
* @param label Der Text des Buttons
* @param step Schrittweite (+1 für vorwärts, -1 für rückwärts)
*/
private void addButton(String label, int step) {
Button button = new Button(label);
button.setPreferredSize(new Vector3f(150, 50, 0)); // Größe der Buttons
button.addClickCommands(source -> moveCube(step));
toolbarContainer.addChild(button);
}
/**
* Fügt den Würfel-Button hinzu, der die Figur entsprechend der gewürfelten Zahl bewegt.
*/
private void addDiceRollButton() {
Button diceButton = new Button("Würfeln");
diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons
diceButton.addClickCommands(source -> rollDice());
toolbarContainer.addChild(diceButton);
}
/**
* Simuliert einen Würfelwurf und bewegt die Figur entsprechend.
*/
private void rollDice() {
int diceRoll = random.nextInt(6) + 1; // Zahl zwischen 1 und 6
System.out.println("Gewürfelt: " + diceRoll);
moveCube(diceRoll); // Bewege die Figur um die gewürfelte Zahl
}
/**
* Bewegt den Würfel basierend auf der aktuellen Position auf dem Brett.
*
* @param step Schrittweite (+1 für vorwärts, -1 für rückwärts oder andere Werte)
*/
private void moveCube(int step) {
currentPosition = (currentPosition + step + 4 * positionsPerSide) % (4 * positionsPerSide);
Vector3f newPosition = calculatePosition(currentPosition);
cube.setLocalTranslation(newPosition);
updatePositionDisplay(); // Aktualisiere die Positionsanzeige
System.out.println("Würfelposition: " + newPosition + " (Feld-ID: " + currentPosition + ")");
}
/**
* Berechnet die neue Position des Würfels basierend auf der aktuellen Brettseite und Position.
*
* @param position Aktuelle Position auf dem Spielfeld
* @return Die berechnete Position als Vector3f
*/
private Vector3f calculatePosition(int position) {
int side = position / positionsPerSide; // Seite des Bretts (0 = unten, 1 = rechts, 2 = oben, 3 = links)
int offset = position % positionsPerSide; // Position auf der aktuellen Seite
switch (side) {
case 0: // Unten (positive x-Achse)
return new Vector3f(-boardLimit + offset * stepSize, 0.1f, -boardLimit + 0.05f);
case 1: // Rechts (positive z-Achse)
return new Vector3f(boardLimit - 0.05f, 0.1f, -boardLimit + offset * stepSize);
case 2: // Oben (negative x-Achse)
return new Vector3f(boardLimit - offset * stepSize, 0.1f, boardLimit - 0.05f);
case 3: // Links (negative z-Achse)
return new Vector3f(-boardLimit + 0.05f, 0.1f, boardLimit - offset * stepSize);
default:
throw new IllegalArgumentException("Ungültige Position: " + position);
}
}
/**
* Erstellt die Anzeige für die aktuelle Position.
*
* @return Das BitmapText-Objekt für die Anzeige
*/
private BitmapText createPositionDisplay() {
BitmapText text = new BitmapText(app.getAssetManager().loadFont("Interface/Fonts/Default.fnt"), false);
text.setSize(20); // Schriftgröße
text.setLocalTranslation(10, app.getCamera().getHeight() - 10, 0); // Oben links
app.getGuiNode().attachChild(text);
return text;
}
/**
* Aktualisiert die Anzeige für die aktuelle Position.
*/
private void updatePositionDisplay() {
positionText.setText("Feld-ID: " + currentPosition);
}
/**
* Entfernt die Toolbar.
*/
public void remove() {
app.getGuiNode().detachChild(toolbarContainer);
app.getGuiNode().detachChild(positionText);
}
}

View File

@@ -12,31 +12,48 @@ 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 com.simsilica.lemur.text.DocumentModel;
import pp.dialog.Dialog; import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.message.client.TradeOffer; import pp.monopoly.message.client.TradeOffer;
import pp.monopoly.model.TradeHandler; import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/**
* Represents the trade menu dialog in the Monopoly application.
* <p>
* Facilitates trade interactions between players, including selection of properties,
* currency, and special cards for offers and requests.
* </p>
*/
public class TradeMenu extends Dialog { public class TradeMenu extends Dialog {
/** The Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** The trade handler managing trade logic. */
private final TradeHandler tradeHandler; private final TradeHandler tradeHandler;
/** Main container for the trade menu UI. */
private final Container mainContainer; private final Container mainContainer;
/** Background geometry for the menu. */
private Geometry background; private Geometry background;
private Selector<String> leftBuildingSelector, leftSpecialCardSelector; private Selector<String> leftBuildingSelector, leftSpecialCardSelector;
private Selector<String> rightBuildingSelector, rightSpecialCardSelector; private Selector<String> rightBuildingSelector, rightSpecialCardSelector;
private TextField leftSelectionsField, rightSelectionsField; private Label leftSelectionsLabel, rightSelectionsLabel;
private TextField leftCurrencyInput, rightCurrencyInput; private TextField leftCurrencyInput, rightCurrencyInput;
private VersionedReference<Set<Integer>> leftBuildingRef, rightBuildingRef; private VersionedReference<Set<Integer>> leftBuildingRef, rightBuildingRef;
private VersionedReference<DocumentModel> leftCurrencyRef, rightCurrencyRef;
private VersionedReference<Set<Integer>> leftCardRef, rightCardRef; private VersionedReference<Set<Integer>> leftCardRef, rightCardRef;
private Set<String> rightselBuildings = new HashSet<>(); private Set<String> rightselBuildings = new HashSet<>();
@@ -44,6 +61,12 @@ public class TradeMenu extends Dialog {
private static final ColorRGBA TRANSLUCENT_WHITE = new ColorRGBA(1, 1, 1, 0.5f); private static final ColorRGBA TRANSLUCENT_WHITE = new ColorRGBA(1, 1, 1, 0.5f);
/**
* Constructs the trade menu dialog.
*
* @param app the Monopoly application instance
* @param tradeHandler the handler managing trade interactions
*/
public TradeMenu(MonopolyApp app, TradeHandler tradeHandler) { public TradeMenu(MonopolyApp app, TradeHandler tradeHandler) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -57,7 +80,7 @@ public class TradeMenu extends Dialog {
initializeReferences(); initializeReferences();
} }
/** Creates the main container for the trade menu UI. */
private Container createMainContainer() { private Container createMainContainer() {
Container container = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container container = new Container(new SpringGridLayout(Axis.Y, Axis.X));
container.setPreferredSize(new Vector3f(1200, 800, 0)); container.setPreferredSize(new Vector3f(1200, 800, 0));
@@ -67,7 +90,7 @@ public class TradeMenu extends Dialog {
container.addChild(createMainContent()); container.addChild(createMainContent());
return container; return container;
} }
/** Creates the header label for the trade menu. */
private Label createHeader() { private Label createHeader() {
Label header = new Label("Handelsmenü", new ElementId("label-Bold")); Label header = new Label("Handelsmenü", new ElementId("label-Bold"));
header.setFontSize(50); header.setFontSize(50);
@@ -75,7 +98,7 @@ public class TradeMenu extends Dialog {
header.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE)); header.setBackground(new QuadBackgroundComponent(TRANSLUCENT_WHITE));
return header; return header;
} }
/** Creates the main content section of the trade menu. */
private Container createMainContent() { private Container createMainContent() {
Container mainContent = new Container(new SpringGridLayout(Axis.X, Axis.Y)); Container mainContent = new Container(new SpringGridLayout(Axis.X, Axis.Y));
mainContent.setPreferredSize(new Vector3f(1200, 700, 0)); mainContent.setPreferredSize(new Vector3f(1200, 700, 0));
@@ -87,9 +110,12 @@ public class TradeMenu extends Dialog {
return mainContent; return mainContent;
} }
/** Sets the trade data based on the current selections. */
private void setTrades() { private void setTrades() {
tradeHandler.setOfferedAmount(Integer.parseInt(leftCurrencyInput.getText())); String leftCurreny = leftCurrencyInput.getText().equals("")? "0" : leftCurrencyInput.getText();
tradeHandler.setRequestedAmount(Integer.parseInt(rightCurrencyInput.getText())); String rightCurreny = rightCurrencyInput.getText().equals("")? "0" : rightCurrencyInput.getText();
tradeHandler.setOfferedAmount(Integer.parseInt(leftCurreny));
tradeHandler.setRequestedAmount(Integer.parseInt(rightCurreny));
tradeHandler.setOfferedJailCards(Integer.parseInt(leftSpecialCardSelector.getSelectedItem())); tradeHandler.setOfferedJailCards(Integer.parseInt(leftSpecialCardSelector.getSelectedItem()));
tradeHandler.setRequestedJailCards(Integer.parseInt(rightSpecialCardSelector.getSelectedItem())); tradeHandler.setRequestedJailCards(Integer.parseInt(rightSpecialCardSelector.getSelectedItem()));
@@ -107,6 +133,12 @@ public class TradeMenu extends Dialog {
tradeHandler.setRequestedProperties(requestedProperties); tradeHandler.setRequestedProperties(requestedProperties);
} }
/**
* Creates a trade column for either the sender or receiver.
*
* @param label the label text for the column
* @param isLeft true if the column is for the sender; false otherwise
*/
private Container createTradeColumn(String label, boolean isLeft) { private Container createTradeColumn(String label, boolean isLeft) {
Container column = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container column = new Container(new SpringGridLayout(Axis.Y, Axis.X));
column.setBackground(new QuadBackgroundComponent(ColorRGBA.White)); column.setBackground(new QuadBackgroundComponent(ColorRGBA.White));
@@ -132,6 +164,12 @@ public class TradeMenu extends Dialog {
return column; return column;
} }
/**
* Creates a property selector for buildings.
*
* @param isLeft true if the selector is for the sender; false otherwise
* @return the created property selector
*/
private Selector<String> createPropertySelector(boolean isLeft) { private Selector<String> createPropertySelector(boolean isLeft) {
VersionedList<String> properties = new VersionedList<>(); VersionedList<String> properties = new VersionedList<>();
for (PropertyField field : getPropertyFields(isLeft)) { for (PropertyField field : getPropertyFields(isLeft)) {
@@ -142,6 +180,12 @@ public class TradeMenu extends Dialog {
return selector; return selector;
} }
/**
* Creates a selector for special cards.
*
* @param isLeft true if the selector is for the sender; false otherwise
* @return the created special card selector
*/
private Selector<String> createSpecialCardSelector(boolean isLeft) { private Selector<String> createSpecialCardSelector(boolean isLeft) {
VersionedList<String> numbers = new VersionedList<>(); VersionedList<String> numbers = new VersionedList<>();
for (int i = 0; i <= app.getGameLogic().getPlayerHandler().getPlayerById(isLeft ? tradeHandler.getReceiver().getId() : tradeHandler.getSender().getId()).getNumJailCard(); i++) { for (int i = 0; i <= app.getGameLogic().getPlayerHandler().getPlayerById(isLeft ? tradeHandler.getReceiver().getId() : tradeHandler.getSender().getId()).getNumJailCard(); i++) {
@@ -152,31 +196,61 @@ public class TradeMenu extends Dialog {
return selector; return selector;
} }
/**
* Retrieves the property fields owned by the respective player.
*
* @param isLeft true if retrieving fields for the sender; false otherwise
* @return an iterable of property fields
*/
private Iterable<PropertyField> getPropertyFields(boolean isLeft) { private Iterable<PropertyField> getPropertyFields(boolean isLeft) {
return app.getGameLogic() Set<PropertyField> building = app.getGameLogic()
.getBoardManager() .getBoardManager()
.getPropertyFields(app.getGameLogic() .getPropertyFields(app.getGameLogic()
.getPlayerHandler() .getPlayerHandler()
.getPlayerById(isLeft ? tradeHandler.getReceiver().getId() : tradeHandler.getSender().getId()) .getPlayerById(isLeft ? tradeHandler.getSender().getId() : tradeHandler.getReceiver().getId())
.getProperties()); .getProperties())
} .stream()
.filter(p -> p instanceof BuildingProperty)
.map(p -> (BuildingProperty) p)
.filter(p -> p.getHouses() == 0)
.collect(Collectors.toSet());
Set<PropertyField> rest = app.getGameLogic()
.getBoardManager()
.getPropertyFields(app.getGameLogic()
.getPlayerHandler()
.getPlayerById(isLeft ? tradeHandler.getSender().getId() : tradeHandler.getReceiver().getId())
.getProperties())
.stream()
.filter(p -> !(p instanceof BuildingProperty))
.collect(Collectors.toSet());
List<PropertyField> combinedProperties = new ArrayList<>();
combinedProperties.addAll(building);
combinedProperties.addAll(rest);
combinedProperties = combinedProperties.stream().sorted(Comparator.comparingInt(PropertyField::getId)).collect(Collectors.toList());
return combinedProperties;
}
/** Creates a text field for currency input. */
private TextField createCurrencyInput() { private TextField createCurrencyInput() {
TextField currencyInput = new TextField("0"); TextField currencyInput = new TextField("0");
styleTextField(currencyInput); styleTextField(currencyInput);
return currencyInput; return currencyInput;
} }
/** Creates the middle section containing buttons and summary fields. */
private Container createMiddleSection() { private Container createMiddleSection() {
Container middleSection = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container middleSection = new Container(new SpringGridLayout(Axis.Y, Axis.X));
middleSection.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f))); middleSection.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)));
Label middleLabelTop = middleSection.addChild(new Label("Gebäude: Währung: Sonderkarten:")); Label middleLabelTop = middleSection.addChild(new Label("Meine Gebäude:"));
middleLabelTop.setFontSize(24); middleLabelTop.setFontSize(24);
middleLabelTop.setTextVAlignment(VAlignment.Center);
middleLabelTop.setTextHAlignment(HAlignment.Center);
middleLabelTop.setInsets(new Insets3f(5, 5, 5, 5)); middleLabelTop.setInsets(new Insets3f(5, 5, 5, 5));
leftSelectionsField = middleSection.addChild(new TextField("")); leftSelectionsLabel = middleSection.addChild(new Label(""));
leftSelectionsField.setPreferredSize(new Vector3f(600, 50, 0)); leftSelectionsLabel.setPreferredSize(new Vector3f(600, 50, 0));
Container buttons = middleSection.addChild(new Container(new SpringGridLayout())); Container buttons = middleSection.addChild(new Container(new SpringGridLayout()));
Button cancel = new Button("Abbrechen"); Button cancel = new Button("Abbrechen");
@@ -196,26 +270,39 @@ public class TradeMenu extends Dialog {
buttons.addChild(cancel); buttons.addChild(cancel);
buttons.addChild(trade); buttons.addChild(trade);
Label middleLabelBottom = middleSection.addChild(new Label("Gebäude: Währung: Sonderkarten:")); Label middleLabelBottom = middleSection.addChild(new Label("Gebäude des Gegenspielers:"));
middleLabelBottom.setFontSize(24); middleLabelBottom.setFontSize(24);
middleLabelBottom.setTextVAlignment(VAlignment.Center);
middleLabelBottom.setTextHAlignment(HAlignment.Center);
middleLabelBottom.setInsets(new Insets3f(5, 5, 5, 5)); middleLabelBottom.setInsets(new Insets3f(5, 5, 5, 5));
rightSelectionsField = middleSection.addChild(new TextField("")); rightSelectionsLabel = middleSection.addChild(new Label(""));
rightSelectionsField.setPreferredSize(new Vector3f(600, 50, 0)); rightSelectionsLabel.setPreferredSize(new Vector3f(600, 50, 0));
return middleSection; return middleSection;
} }
/** Styles the given selector with insets and background color. */
private void styleSelector(Selector<String> selector) { private void styleSelector(Selector<String> selector) {
selector.setInsets(new Insets3f(5, 10, 5, 10)); selector.setInsets(new Insets3f(5, 10, 5, 10));
selector.setBackground(new QuadBackgroundComponent(ColorRGBA.Black)); selector.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
} }
/** Styles the given text field with insets and background color. */
private void styleTextField(TextField textField) { private void styleTextField(TextField textField) {
textField.setInsets(new Insets3f(5, 10, 5, 10)); textField.setInsets(new Insets3f(5, 10, 5, 10));
textField.setBackground(new QuadBackgroundComponent(ColorRGBA.Black)); textField.setBackground(new QuadBackgroundComponent(ColorRGBA.Black));
textField.setPreferredSize(new Vector3f(300, 30, 0)); textField.setPreferredSize(new Vector3f(300, 30, 0));
} }
/**
* Assigns selectors and input fields to either the left or right column.
*
* @param buildingSelector the building selector
* @param specialCardSelector the special card selector
* @param currencyInput the currency input field
* @param isLeft true if assigning to the left column; false otherwise
*/
private void assignSelectors(Selector<String> buildingSelector, Selector<String> specialCardSelector, TextField currencyInput, boolean isLeft) { private void assignSelectors(Selector<String> buildingSelector, Selector<String> specialCardSelector, TextField currencyInput, boolean isLeft) {
if (isLeft) { if (isLeft) {
leftBuildingSelector = buildingSelector; leftBuildingSelector = buildingSelector;
@@ -227,7 +314,7 @@ public class TradeMenu extends Dialog {
rightCurrencyInput = currencyInput; rightCurrencyInput = currencyInput;
} }
} }
/** Positions the main container at the center of the screen. */
private void positionMainContainer() { private void positionMainContainer() {
mainContainer.setLocalTranslation( mainContainer.setLocalTranslation(
(app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2, (app.getCamera().getWidth() - mainContainer.getPreferredSize().x) / 2,
@@ -235,7 +322,7 @@ public class TradeMenu extends Dialog {
7 7
); );
} }
/** Adds a background image to the trade menu. */
private void addBackgroundImage() { private void addBackgroundImage() {
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(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -246,29 +333,39 @@ public class TradeMenu extends Dialog {
background.setLocalTranslation(0, 0, 6); background.setLocalTranslation(0, 0, 6);
app.getGuiNode().attachChild(background); app.getGuiNode().attachChild(background);
} }
/** Initializes references for tracking UI changes. */
private void initializeReferences() { private void initializeReferences() {
leftBuildingRef = leftBuildingSelector.getSelectionModel().createReference(); leftBuildingRef = leftBuildingSelector.getSelectionModel().createReference();
leftCardRef = leftSpecialCardSelector.getSelectionModel().createReference(); leftCardRef = leftSpecialCardSelector.getSelectionModel().createReference();
leftCurrencyRef = leftCurrencyInput.getDocumentModel().createReference();
rightBuildingRef = rightBuildingSelector.getSelectionModel().createReference(); rightBuildingRef = rightBuildingSelector.getSelectionModel().createReference();
rightCardRef = rightSpecialCardSelector.getSelectionModel().createReference(); rightCardRef = rightSpecialCardSelector.getSelectionModel().createReference();
rightCurrencyRef = rightCurrencyInput.getDocumentModel().createReference();
} }
/**
* Updates the trade menu state, including selected properties and values.
*
* @param delta the time elapsed since the last update
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
if (leftBuildingRef.update() || leftCardRef.update() || leftCurrencyRef.update()) { if (leftBuildingRef.update() || leftCardRef.update()) {
updateSelections(leftSelectionsField, leftBuildingSelector, leftCurrencyInput, leftSpecialCardSelector, true); updateSelections(leftSelectionsLabel, leftBuildingSelector, true);
} }
if (rightBuildingRef.update() || rightCardRef.update() || rightCurrencyRef.update()) { if (rightBuildingRef.update() || rightCardRef.update()) {
updateSelections(rightSelectionsField, rightBuildingSelector, rightCurrencyInput, rightSpecialCardSelector, false); updateSelections(rightSelectionsLabel, rightBuildingSelector, false);
} }
} }
private void updateSelections(TextField target, Selector<String> building, TextField currency, Selector<String> card, boolean isLeft) { /**
* Updates the displayed selections for properties.
*
* @param target the target label to update
* @param building the building selector
* @param isLeft true if updating the left column; false otherwise
*/
private void updateSelections(Label target, Selector<String> building, boolean isLeft) {
StringBuilder buildingText = new StringBuilder(); StringBuilder buildingText = new StringBuilder();
if (isLeft) { if (isLeft) {
if (leftselBuildings.contains(building.getSelectedItem())) { if (leftselBuildings.contains(building.getSelectedItem())) {
@@ -276,8 +373,8 @@ public class TradeMenu extends Dialog {
} else { } else {
leftselBuildings.add(building.getSelectedItem()); // Add if not already selected leftselBuildings.add(building.getSelectedItem()); // Add if not already selected
} }
for (String property : leftselBuildings) { for (String property : leftselBuildings) {
buildingText.append(property); buildingText.append(property).append(", ");
} }
} else { } else {
if (rightselBuildings.contains(building.getSelectedItem())) { if (rightselBuildings.contains(building.getSelectedItem())) {
@@ -285,21 +382,21 @@ public class TradeMenu extends Dialog {
} else { } else {
rightselBuildings.add(building.getSelectedItem()); // Add if not already selected rightselBuildings.add(building.getSelectedItem()); // Add if not already selected
} }
for (String property : rightselBuildings) { for (String property : rightselBuildings) {
buildingText.append(property); buildingText.append(property).append(", ");
} }
} }
String currencyText = currency.getText() != null ? currency.getText().trim() : ""; target.setText(buildingText.toString().replaceAll(", $", ""));
String cardText = card.getSelectedItem() != null ? card.getSelectedItem() : "";
target.setText(String.join(" | ", buildingText, currencyText, cardText));
} }
/** Opens the settings menu when the escape key is pressed. */
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();
} }
/** Closes the trade menu and detaches UI elements. */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(mainContainer); app.getGuiNode().detachChild(mainContainer);

View File

@@ -25,7 +25,7 @@ public class VolumeSlider extends Slider {
} }
/** /**
* when triggered it updates the volume to the value set with the slider * When triggered it updates the volume to the value set with the slider
*/ */
public void update() { public void update() {
if (vol != getModel().getPercent()) { if (vol != getModel().getPercent()) {

View File

@@ -13,19 +13,37 @@ 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.message.server.TradeReply;
import pp.monopoly.notification.Sound;
/** /**
* Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn * Represents a confirmation dialog that appears when a trade is accepted .
* <p>
* Displays a message to the user informing them that the trade they proposed has been accepted,
* along with a confirmation button to close the dialog.
* </p>
*/ */
public class AcceptTrade extends Dialog { public class AcceptTrade extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the dialog. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Container for the warning message content. */
private final Container noMoneyWarningContainer; private final Container noMoneyWarningContainer;
/** Background container providing a border for the dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
public AcceptTrade(MonopolyApp app) { * Constructs the accept trade dialog.
*
* @param app the Monopoly application instance
* @param msg the trade reply message containing details about the trade
*/
public AcceptTrade(MonopolyApp app, TradeReply msg) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -55,7 +73,7 @@ public class AcceptTrade extends Dialog {
// Text, der im Popup steht // Text, der im Popup steht
Container textContainer = noMoneyWarningContainer.addChild(new Container()); Container textContainer = noMoneyWarningContainer.addChild(new Container());
textContainer.addChild(new Label("Du hast Spieler XXX einen Handel vorgeschlagen", new ElementId("label-Text"))); textContainer.addChild(new Label("Du hast Spieler"+ " " + msg.getTradeHandler().getReceiver().getName() + " " + "einen Handel vorgeschlagen", new ElementId("label-Text")));
textContainer.addChild(new Label("", new ElementId("label-Text"))); textContainer.addChild(new Label("", new ElementId("label-Text")));
textContainer.addChild(new Label("Der Handel wurde angenommen", new ElementId("label-Text"))); textContainer.addChild(new Label("Der Handel wurde angenommen", new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
@@ -66,7 +84,10 @@ public class AcceptTrade extends Dialog {
// Beenden-Button // Beenden-Button
Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button"))); Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close()); quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Popup // Zentriere das Popup
@@ -87,9 +108,9 @@ public class AcceptTrade extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the dialog.
* *
* @return Geometrie des Overlays * @return the geometry of the overlay
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -103,7 +124,7 @@ public class AcceptTrade extends Dialog {
} }
/** /**
* Closes the menu and removes the GUI elements. * Closes the dialog and removes the associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -113,6 +134,9 @@ public class AcceptTrade extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape key action by closing the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -18,13 +18,24 @@ import pp.monopoly.client.MonopolyApp;
* Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn * Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn
*/ */
public class Bankrupt extends Dialog { public class Bankrupt extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the popup. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the bankruptcy warning content. */
private final Container bankruptContainer; private final Container bankruptContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs the bankruptcy warning popup.
*
* @param app the Monopoly application instance
*/
public Bankrupt(MonopolyApp app) { public Bankrupt(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -85,9 +96,9 @@ public class Bankrupt extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return the geometry of the overlay
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -111,6 +122,9 @@ public class Bankrupt extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape key action by closing the popup.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -19,10 +19,20 @@ import pp.monopoly.notification.Sound;
* BuildingPropertyCard creates the popup for field information * BuildingPropertyCard creates the popup for field information
*/ */
public class BuildingPropertyCard extends Dialog { public class BuildingPropertyCard extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the building property information. */
private final Container buildingPropertyContainer; private final Container buildingPropertyContainer;
/** Background container providing a border for the property card. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs a property card popup displaying details about the building property.
*
* @param app the Monopoly application instance
*/
public BuildingPropertyCard(MonopolyApp app) { public BuildingPropertyCard(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -67,7 +77,7 @@ public class BuildingPropertyCard extends Dialog {
// Beenden-Button // Beenden-Button
Button quitButton = buildingPropertyContainer.addChild(new Button("Beenden", new ElementId("button"))); Button quitButton = buildingPropertyContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog(() -> { quitButton.addClickCommands(s -> ifTopDialog( () -> {
System.err.println("Button does something?"); System.err.println("Button does something?");
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
@@ -99,7 +109,7 @@ public class BuildingPropertyCard extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the popup and removes the associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -108,6 +118,9 @@ public class BuildingPropertyCard extends Dialog {
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -31,16 +31,35 @@ import java.util.stream.Collectors;
* BuyHouse is a popup which appears when a player clicks on the "Buy House"-button in the BuildingAdminMenu * BuyHouse is a popup which appears when a player clicks on the "Buy House"-button in the BuildingAdminMenu
*/ */
public class BuyHouse extends Dialog { public class BuyHouse extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the "Buy House" popup UI. */
private final Container buyHouseContainer; private final Container buyHouseContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
/** TextField to display selected properties. */
private TextField selectionDisplay;
/** Reference for tracking dropdown selection changes. */
private VersionedReference<Set<Integer>> selectionRef; private VersionedReference<Set<Integer>> selectionRef;
/** Dropdown selector for choosing properties to build houses on. */
private Selector<String> propertySelector; private Selector<String> propertySelector;
/** Set of selected properties for house purchase. */
private Set<String> selectedProperties = new HashSet<>(); private Set<String> selectedProperties = new HashSet<>();
/** Label displaying the total cost of building houses on the selected properties. */
private Label cost = new Label("0", new ElementId("label-Text")); private Label cost = new Label("0", new ElementId("label-Text"));
/**
* Constructs the "Buy House" popup.
*
* @param app the Monopoly application instance
*/
public BuyHouse(MonopolyApp app) { public BuyHouse(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -119,9 +138,9 @@ public class BuyHouse extends Dialog {
} }
/** /**
* Creates a dropdown menu for selecting a property. * Creates a dropdown menu for selecting properties eligible for house construction.
* *
* @return The dropdown container. * @return The container holding the dropdown menu.
*/ */
private Container createPropertyDropdown() { private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
@@ -147,12 +166,18 @@ public class BuyHouse extends Dialog {
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0)); selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection
if (!propertyOptions.isEmpty()) {
onDropdownSelectionChanged(propertySelector);
}
return dropdownContainer; return dropdownContainer;
} }
/** /**
* Retrieves the list of properties owned by the current player. * Retrieves the list of properties owned by the current player that are eligible for house construction.
* *
* @return List of BuildingProperty objects owned by the player. * @return A list of {@link BuildingProperty} objects owned by the player.
*/ */
private List<BuildingProperty> getPlayerProperties() { private List<BuildingProperty> getPlayerProperties() {
Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()); Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
@@ -165,6 +190,11 @@ public class BuyHouse extends Dialog {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Periodically updates the popup, tracking selection changes in the dropdown menu.
*
* @param delta Time since the last update in seconds.
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
if(selectionRef.update()) { if(selectionRef.update()) {
@@ -173,7 +203,9 @@ public class BuyHouse extends Dialog {
} }
/** /**
* Handles property selection changes. * Handles property selection changes in the dropdown menu.
*
* @param playerProperties the dropdown selector for the player's properties
*/ */
private void onDropdownSelectionChanged(Selector<String> playerProperties) { private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem(); String selected = playerProperties.getSelectedItem();
@@ -195,6 +227,9 @@ public class BuyHouse extends Dialog {
this.cost.setText(cost+""); this.cost.setText(cost+"");
} }
/**
* Closes the popup and removes its GUI elements.
*/
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(buyHouseContainer); app.getGuiNode().detachChild(buyHouseContainer);
@@ -202,6 +237,9 @@ public class BuyHouse extends Dialog {
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -11,7 +11,6 @@ import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.client.gui.TradeMenu; import pp.monopoly.client.gui.TradeMenu;
import pp.monopoly.message.client.TradeResponse; import pp.monopoly.message.client.TradeResponse;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.model.TradeHandler; import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.fields.PropertyField; import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
@@ -20,12 +19,23 @@ import pp.monopoly.notification.Sound;
* ConfirmTrade is a popup which appears when a trade is proposed to this certain player. * ConfirmTrade is a popup which appears when a trade is proposed to this certain player.
*/ */
public class ConfirmTrade extends Dialog { public class ConfirmTrade extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the "Confirm Trade" popup UI. */
private final Container confirmTradeContainer; private final Container confirmTradeContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
/** The trade handler managing the details of the trade proposal. */
private TradeHandler tradeHandler; private TradeHandler tradeHandler;
/**
* Constructs the "Confirm Trade" popup.
*
* @param app the Monopoly application instance
*/
public ConfirmTrade(MonopolyApp app) { public ConfirmTrade(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -33,13 +43,12 @@ public class ConfirmTrade extends Dialog {
// Create the background container // Create the background container
backgroundContainer = new Container(); backgroundContainer = new Container();
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)));
attachChild(backgroundContainer); attachChild(backgroundContainer);
// Hauptcontainer für das Bestätigungspopup
confirmTradeContainer = new Container(); confirmTradeContainer = new Container();
float padding = 10; // Passt den backgroundContainer an die Größe des confirmTradeContainer an float padding = 10;
backgroundContainer.setPreferredSize(confirmTradeContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(confirmTradeContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel // Titel
@@ -60,19 +69,18 @@ public class ConfirmTrade extends Dialog {
} }
// Text, der auf der Karte steht // Text, der auf der Karte steht
// Die Werte werden dem Handel entnommen (Iwas auch immer da dann ist)
Container propertyValuesContainer = confirmTradeContainer.addChild(new Container()); Container propertyValuesContainer = confirmTradeContainer.addChild(new Container());
propertyValuesContainer.addChild(new Label("„Spieler " + tradeHandler.getSender().getName() + " möchte:", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("„Spieler " + " " + tradeHandler.getSender().getName() + " " +" möchte:", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("- " + offeredProperties, new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("- " + offeredProperties, new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedAmount() + " EUR", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedAmount() + " EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedJailCards() +" Sonderkaten", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("- " + tradeHandler.getOfferedJailCards() +" Sonderkarten", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("gegen:", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("gegen:", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("- "+ requestedProperties, new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("- "+ requestedProperties, new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedAmount() +" EUR", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedAmount() +" EUR", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedJailCards() +" Sonderkaten", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("- "+ tradeHandler.getRequestedJailCards() +" Sonderkarten", new ElementId("label-Text")));
propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile propertyValuesContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
propertyValuesContainer.addChild(new Label("tauschen, willst du das Angebot annehmen?", new ElementId("label-Text"))); propertyValuesContainer.addChild(new Label("tauschen, willst du das Angebot annehmen?", new ElementId("label-Text")));
propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); propertyValuesContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
@@ -122,15 +130,18 @@ public class ConfirmTrade extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the popup and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(confirmTradeContainer); // Entferne das Menü app.getGuiNode().detachChild(confirmTradeContainer);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer);
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -13,22 +13,34 @@ 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.notification.Sound;
/** /**
* EventCardPopup is a popup which appears when a certain EventCard is triggered by entering a EventCardField * EventCardPopup is a popup which appears when a certain EventCard is triggered by entering a EventCardField
*/ */
public class EventCardPopup extends Dialog { public class EventCardPopup extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the popup. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the event card information. */
private final Container eventCardContainer; private final Container eventCardContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
private final String description;
/**
* Constructs the EventCardPopup to display the details of a triggered event card.
*
* @param app the Monopoly application instance
* @param description the description of the triggered event card
*/
public EventCardPopup(MonopolyApp app, String description) { public EventCardPopup(MonopolyApp app, String description) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
this.description = description;
// Halbtransparentes Overlay hinzufügen // Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground(); overlayBackground = createOverlayBackground();
@@ -39,12 +51,12 @@ public class EventCardPopup 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 die Eventcard
eventCardContainer = new Container(); eventCardContainer = new Container();
eventCardContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); eventCardContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f)));
eventCardContainer.setPreferredSize(new Vector3f(550,400,10)); eventCardContainer.setPreferredSize(new Vector3f(550,400,10));
float padding = 10; // Passt den backgroundContainer an die Größe des eventCardContainers an float padding = 10;
backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(eventCardContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel // Titel
@@ -62,7 +74,10 @@ public class EventCardPopup extends Dialog {
// Beenden-Button // Beenden-Button
Button quitButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button"))); Button quitButton = eventCardContainer.addChild(new Button("Jawohl", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close()); quitButton.addClickCommands(source -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Popup // Zentriere das Popup
eventCardContainer.setLocalTranslation( eventCardContainer.setLocalTranslation(
@@ -82,15 +97,15 @@ public class EventCardPopup extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return the geometry of the overlay
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad); Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f));
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material); overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0); overlay.setLocalTranslation(0, 0, 0);
@@ -98,16 +113,19 @@ public class EventCardPopup extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the popup and removes its associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(eventCardContainer); // Entferne das Menü app.getGuiNode().detachChild(eventCardContainer);
app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay app.getGuiNode().detachChild(overlayBackground);
super.close(); super.close();
} }
/**
* Handles the escape key action by closing the popup.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -22,42 +22,47 @@ import pp.monopoly.notification.Sound;
* FoodFieldCard creates the popup for field information * FoodFieldCard creates the popup for field information
*/ */
public class FoodFieldCard extends Dialog { public class FoodFieldCard extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the popup. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the food field information. */
private final Container foodFieldContainer; private final Container foodFieldContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs a FoodFieldCard popup displaying details about a food field.
*
* @param app the Monopoly application instance
*/
public FoodFieldCard(MonopolyApp app) { public FoodFieldCard(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
//Generate the corresponfing field
int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID(); int index = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()).getFieldID();
FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index); FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index);
// Halbtransparentes Overlay hinzufügen
overlayBackground = createOverlayBackground(); overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground); app.getGuiNode().attachChild(overlayBackground);
// Create the background container
backgroundContainer = new Container(); backgroundContainer = new Container();
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
attachChild(backgroundContainer); attachChild(backgroundContainer);
// Hauptcontainer für die Gebäudekarte
foodFieldContainer = new Container(); foodFieldContainer = new Container();
foodFieldContainer.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)));
float padding = 10; // Passt den backgroundContainer an die Größe des foodFieldContainers an float padding = 10;
backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(foodFieldContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel, bestehend aus dynamischen Namen anhand der ID und der Schriftfarbe/größe
Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold"))); Label settingsTitle = foodFieldContainer.addChild(new Label(field.getName(), new ElementId("label-Bold")));
settingsTitle.setFontSize(48); settingsTitle.setFontSize(48);
settingsTitle.setColor(ColorRGBA.White); settingsTitle.setColor(ColorRGBA.White);
// Text, der auf der Karte steht
// Die Preise werden dynamisch dem BoardManager entnommen
Container propertyValuesContainer = foodFieldContainer.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
@@ -77,7 +82,7 @@ public class FoodFieldCard extends Dialog {
// Beenden-Button // Beenden-Button
Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button"))); Button quitButton = foodFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog(() -> { quitButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
})); }));
@@ -108,9 +113,9 @@ public class FoodFieldCard extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return the geometry of the overlay
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -124,7 +129,7 @@ public class FoodFieldCard extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the popup and removes its associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -134,6 +139,9 @@ public class FoodFieldCard extends Dialog {
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -1,10 +1,6 @@
package pp.monopoly.client.gui.popups; package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
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.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
@@ -21,10 +17,20 @@ import pp.monopoly.notification.Sound;
* GateFieldCard creates the popup for field information * GateFieldCard creates the popup for field information
*/ */
public class GateFieldCard extends Dialog { public class GateFieldCard extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the gate field information. */
private final Container gateFieldContainer; private final Container gateFieldContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs a GateFieldCard popup displaying details about a gate field.
*
* @param app the Monopoly application instance
*/
public GateFieldCard(MonopolyApp app) { public GateFieldCard(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -69,14 +75,14 @@ public class GateFieldCard extends Dialog {
// Beenden-Button // Beenden-Button
Button quitButton = gateFieldContainer.addChild(new Button("Beenden", new ElementId("button"))); Button quitButton = gateFieldContainer.addChild(new Button("Beenden", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(s -> ifTopDialog(() -> { quitButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
close(); close();
})); }));
// Kaufen-Button // Kaufen-Button
Button buyButton = gateFieldContainer.addChild(new Button("Kaufen", new ElementId("button"))); Button buyButton = gateFieldContainer.addChild(new Button("Kaufen", new ElementId("button")));
buyButton.setFontSize(32); buyButton.setFontSize(32);
buyButton.addClickCommands(s -> ifTopDialog(() -> { buyButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
app.getGameLogic().send(new BuyPropertyResponse()); app.getGameLogic().send(new BuyPropertyResponse());
close(); close();
@@ -100,23 +106,7 @@ public class GateFieldCard extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Closes the popup and removes its associated GUI elements.
*
* @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 close() {
@@ -125,6 +115,9 @@ public class GateFieldCard extends Dialog {
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -13,18 +13,32 @@ 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.notification.Sound;
/** /**
* Gulag is a warning popup that is triggered when a certain player enters the "Wache" field * Gulag is a warning popup triggered when a player lands on the "Wache" field in the Monopoly game.
* <p>
* This popup informs the player that they are being sent to the Gulag and includes a confirmation button.
* </p>
*/ */
public class Gulag extends Dialog { public class Gulag extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the popup. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the Gulag warning message. */
private final Container gulagContainer; private final Container gulagContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs the Gulag popup, displaying a warning when a player lands on the "Wache" field.
*
* @param app the Monopoly application instance
*/
public Gulag(MonopolyApp app) { public Gulag(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -54,17 +68,13 @@ public class Gulag extends Dialog {
gateFieldTitle.setFontSize(48); gateFieldTitle.setFontSize(48);
gateFieldTitle.setColor(ColorRGBA.Black); gateFieldTitle.setColor(ColorRGBA.Black);
// Text, der auf der Karte steht
/* Container textContainer = gulagContainer.addChild(new Container());
textContainer.addChild(new Label("Du hast die Verbindung verloren und kannst nichts dagegen machen. Akzeptiere einfach, dass du verloren hast!", new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(gulagContainer.getPreferredSize().addLocal(-250,-200,0));
*/
// Beenden-Button // Beenden-Button
Button quitButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button"))); Button quitButton = gulagContainer.addChild(new Button("Jawohl Gulag", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close()); quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Popup // Zentriere das Popup
@@ -85,9 +95,9 @@ public class Gulag extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent overlay background for the popup.
* *
* @return Geometrie des Overlays * @return the geometry of the overlay
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -101,7 +111,7 @@ public class Gulag extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the popup and removes its associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -111,6 +121,9 @@ public class Gulag extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the popup.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -13,14 +13,27 @@ import pp.monopoly.message.client.NotificationAnswer;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* ConfirmTrade is a popup which appears when a trade is proposed to this certain player. * GulagInfo is a popup that provides options for a player who is stuck in the "Gulag" (jail) field.
* <p>
* This dialog offers multiple actions, including paying a bribe, using a "Get Out of Jail" card, or waiting.
* </p>
*/ */
public class GulagInfo extends Dialog { public class GulagInfo extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the Gulag information dialog. */
private final Container gulagInfoContainer; private final Container gulagInfoContainer;
/** Background container providing a styled border around the dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs a GulagInfo popup that provides the player with options for getting out of the "Gulag" field.
*
* @param app the Monopoly application instance
* @param trys the number of failed attempts to roll doubles for release
*/
public GulagInfo(MonopolyApp app, int trys) { public GulagInfo(MonopolyApp app, int trys) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -104,7 +117,7 @@ public class GulagInfo extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the GulagInfo popup and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -113,6 +126,9 @@ public class GulagInfo extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the GulagInfo dialog.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -16,10 +16,23 @@ import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/**
* LooserPopUp is a dialog that appears when a player loses the game.
* <p>
* This popup provides a message of encouragement and an option to quit the game.
* </p>
*/
public class LooserPopUp extends Dialog { public class LooserPopUp extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the dialog. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the "Looser" dialog UI. */
private final Container LooserContainer; private final Container LooserContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
@@ -95,9 +108,9 @@ public class LooserPopUp extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return The overlay geometry.
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -111,7 +124,7 @@ public class LooserPopUp extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the LooserPopUp dialog and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -121,6 +134,9 @@ public class LooserPopUp extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -13,18 +13,35 @@ 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.notification.Sound;
/** /**
* Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn * NoMoneyWarning is a warning popup that appears when a player tries to perform
* an action they cannot afford due to insufficient funds, such as attempting
* to purchase a property or building.
* <p>
* This dialog notifies the player of their lack of funds and provides a single
* confirmation button to close the dialog.
* </p>
*/ */
public class NoMoneyWarning extends Dialog { public class NoMoneyWarning extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the warning popup. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the NoMoneyWarning dialog UI. */
private final Container noMoneyWarningContainer; private final Container noMoneyWarningContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs a new NoMoneyWarning dialog.
*
* @param app The MonopolyApp instance.
*/
public NoMoneyWarning(MonopolyApp app) { public NoMoneyWarning(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -61,10 +78,13 @@ public class NoMoneyWarning extends Dialog {
// Passt den textContainer an die Größe des bankruptContainers an // Passt den textContainer an die Größe des bankruptContainers an
textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0)); textContainer.setPreferredSize(noMoneyWarningContainer.getPreferredSize().addLocal(-250,-200,0));
// Beenden-Button // Bestätigen-Button
Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button"))); Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close()); quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Popup // Zentriere das Popup
@@ -85,9 +105,9 @@ public class NoMoneyWarning extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent overlay background for the dialog.
* *
* @return Geometrie des Overlays * @return The geometry representing the overlay background.
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -111,6 +131,9 @@ public class NoMoneyWarning extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -0,0 +1,166 @@
package pp.monopoly.client.gui.popups;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.simsilica.lemur.Button;
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.notification.Sound;
/**
* Rent is a popup that is triggered when a player lands on a property owned by another player
* and needs to pay rent in the Monopoly application.
* <p>
* Displays the rent amount and the recipient player's name, with an option to confirm the payment.
* </p>
*/
public class ReceivedRent extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app;
/** Semi-transparent overlay background for the popup. */
private final Geometry overlayBackground;
/** Main container for the rent information and action. */
private final Container rentContainer;
/** Background container providing a border for the rent popup. */
private final Container backgroundContainer;
/**
* Constructs the Rent popup displaying the rent amount and recipient player.
*
* @param app the Monopoly application instance
* @param playerName the name of the player to whom the rent is owed
* @param amount the amount of rent to be paid
*/
public ReceivedRent(MonopolyApp app, String playerName, int amount) {
super(app.getDialogManager());
this.app = app;
// Create the overlay
overlayBackground = createOverlayBackground();
app.getGuiNode().attachChild(overlayBackground);
// Create and position the background container
backgroundContainer = createBackgroundContainer();
app.getGuiNode().attachChild(backgroundContainer);
// Create and position the rent container
rentContainer = createRentContainer(playerName, amount);
app.getGuiNode().attachChild(rentContainer);
centerContainers();
}
/**
* Creates a semi-transparent overlay background.
*
* @return the overlay geometry
*/
private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry overlay = new Geometry("Overlay", quad);
Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Semi-transparent black
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
overlay.setMaterial(material);
overlay.setLocalTranslation(0, 0, 0);
return overlay;
}
/**
* Creates the background container with styling.
*
* @return the styled background container
*/
private Container createBackgroundContainer() {
Container container = new Container();
container.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Light gray background
return container;
}
/**
* Creates the main rent container with title, text, and button.
*
* @param playerName the name of the player to whom the rent is owed
* @param amount the rent amount
* @return the rent container
*/
private Container createRentContainer(String playerName, int amount) {
Container container = new Container();
container.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
container.setPreferredSize(new Vector3f(550, 250, 10));
// Title
Label title = container.addChild(new Label("Miete!", new ElementId("warning-title")));
title.setFontSize(48);
title.setColor(ColorRGBA.Black);
// Rent message
Container textContainer = container.addChild(new Container());
textContainer.addChild(new Label(playerName+ " zahlt dir " + amount + " EUR Miete",
new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));
// Payment button
Button payButton = container.addChild(new Button("Bestätigen", new ElementId("button")));
payButton.setFontSize(32);
payButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
return container;
}
/**
* Centers the rent and background containers on the screen.
*/
private void centerContainers() {
float padding = 10;
// Center rent container
rentContainer.setLocalTranslation(
(app.getCamera().getWidth() - rentContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + rentContainer.getPreferredSize().y) / 2,
8
);
// Center background container with padding
backgroundContainer.setPreferredSize(rentContainer.getPreferredSize().addLocal(padding, padding, 0));
backgroundContainer.setLocalTranslation(
(app.getCamera().getWidth() - backgroundContainer.getPreferredSize().x) / 2,
(app.getCamera().getHeight() + backgroundContainer.getPreferredSize().y) / 2,
7
);
}
/**
* Closes the popup and removes GUI elements.
*/
@Override
public void close() {
app.getGuiNode().detachChild(rentContainer);
app.getGuiNode().detachChild(backgroundContainer);
app.getGuiNode().detachChild(overlayBackground);
super.close();
}
/**
* Handles the escape action to close the dialog.
*/
@Override
public void escape() {
close();
}
}

View File

@@ -13,19 +13,38 @@ 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.message.server.TradeReply;
import pp.monopoly.notification.Sound;
/** /**
* Bankrupt is a Warning-Popup which appears when the balance is negative at the end of a player´s turn * RejectTrade is a popup that appears when a trade proposal is rejected by another player
* in the Monopoly application.
* <p>
* Displays a message indicating that the proposed trade has been declined, along with
* details of the involved players and provides an option to close the popup.
* </p>
*/ */
public class RejectTrade extends Dialog { public class RejectTrade extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the popup. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the rejection message content. */
private final Container noMoneyWarningContainer; private final Container noMoneyWarningContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
public RejectTrade(MonopolyApp app) { * Constructs the RejectTrade popup displaying the rejection of a trade proposal.
*
* @param app the Monopoly application instance
* @param msg the trade reply message containing details about the rejected trade
*/
public RejectTrade(MonopolyApp app, TradeReply msg) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -55,7 +74,7 @@ public class RejectTrade extends Dialog {
// Text, der im Popup steht // Text, der im Popup steht
Container textContainer = noMoneyWarningContainer.addChild(new Container()); Container textContainer = noMoneyWarningContainer.addChild(new Container());
textContainer.addChild(new Label("Du hast Spieler XXX einen Handel vorgeschlagen", new ElementId("label-Text"))); textContainer.addChild(new Label("Du hast Spieler"+ " " + msg.getTradeHandler().getReceiver().getName() + " " + "einen Handel vorgeschlagen", new ElementId("label-Text")));
textContainer.addChild(new Label("", new ElementId("label-Text"))); textContainer.addChild(new Label("", new ElementId("label-Text")));
textContainer.addChild(new Label("Der Handel wurde abgelehnt", new ElementId("label-Text"))); textContainer.addChild(new Label("Der Handel wurde abgelehnt", new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
@@ -66,7 +85,10 @@ public class RejectTrade extends Dialog {
// Beenden-Button // Beenden-Button
Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button"))); Button quitButton = noMoneyWarningContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close()); quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Popup // Zentriere das Popup
@@ -87,9 +109,9 @@ public class RejectTrade extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return the geometry of the overlay
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -113,6 +135,9 @@ public class RejectTrade extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape key action by closing the popup.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -16,14 +16,32 @@ import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/** /**
* Rent popup is triggered when a player enters a field owned by another player and needs to pay rent. * Rent is a popup that is triggered when a player lands on a property owned by another player
* and needs to pay rent in the Monopoly application.
* <p>
* Displays the rent amount and the recipient player's name, with an option to confirm the payment.
* </p>
*/ */
public class Rent extends Dialog { public class Rent extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the popup. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the rent information and action. */
private final Container rentContainer; private final Container rentContainer;
/** Background container providing a border for the rent popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs the Rent popup displaying the rent amount and recipient player.
*
* @param app the Monopoly application instance
* @param playerName the name of the player to whom the rent is owed
* @param amount the amount of rent to be paid
*/
public Rent(MonopolyApp app, String playerName, int amount) { public Rent(MonopolyApp app, String playerName, int amount) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -89,7 +107,7 @@ public class Rent extends Dialog {
// Rent message // Rent message
Container textContainer = container.addChild(new Container()); Container textContainer = container.addChild(new Container());
textContainer.addChild(new Label("Du musst Spieler " + playerName + " " + amount + " EUR Miete zahlen", textContainer.addChild(new Label("Du musst " + amount + " EUR Miete an " + playerName + " zahlen",
new ElementId("label-Text"))); new ElementId("label-Text")));
textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); textContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0)); textContainer.setPreferredSize(container.getPreferredSize().addLocal(-250, -200, 0));

View File

@@ -6,7 +6,6 @@ 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.ListBox;
import com.simsilica.lemur.Selector; import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField; import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
@@ -18,8 +17,9 @@ import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.model.fields.BoardManager; import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.BuildingProperty; import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
import java.util.HashSet; import java.util.HashSet;
@@ -28,20 +28,43 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* RepayMortage is a popup which appears when a player clicks on the "Repay Mortage"-button in the BuildingAdminMenu * RepayMortage is a popup that appears when a player selects the "Repay Mortgage" option
* in the Building Administration Menu.
* <p>
* This popup allows the player to select mortgaged properties and repay their mortgages,
* showing the total cost of the repayment. Includes options to confirm or cancel the repayment.
* </p>
*/ */
public class RepayMortage extends Dialog { public class RepayMortage extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the mortgage repayment menu. */
private final Container repayMortageContainer; private final Container repayMortageContainer;
/** Background container providing a border for the popup. */
private final Container backgroundContainer; private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
/** Text field to display selected properties. */
private TextField selectionDisplay;
/** Reference to track property selections in the dropdown menu. */
private VersionedReference<Set<Integer>> selectionRef; private VersionedReference<Set<Integer>> selectionRef;
/** Dropdown menu for selecting mortgaged properties. */
private Selector<String> propertySelector; private Selector<String> propertySelector;
/** Set of selected properties for mortgage repayment. */
private Set<String> selectedProperties = new HashSet<>(); private Set<String> selectedProperties = new HashSet<>();
/** Label displaying the total repayment cost. */
private Label cost = new Label("0", new ElementId("label-Text")); private Label cost = new Label("0", new ElementId("label-Text"));
/**
* Constructs the RepayMortage popup for handling mortgage repayment.
*
* @param app the Monopoly application instance
*/
public RepayMortage(MonopolyApp app) { public RepayMortage(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -69,7 +92,7 @@ public class RepayMortage extends Dialog {
Container downContainer = repayMortageContainer.addChild(new Container()); Container downContainer = repayMortageContainer.addChild(new Container());
// Text, der auf der Karte steht // Text, der auf der Karte steht
upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text"))); //TODO hier überall die entsprechenden Variablen einfügen upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
@@ -95,9 +118,10 @@ public class RepayMortage extends Dialog {
confirmButton.setFontSize(32); confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog( () -> { confirmButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
// Send the "alter building" message to the server AlterProperty msg = new AlterProperty("RepayMortage");
//app.getGameLogic().sendMessage(new AlterBuildingMessage(selected.getId(), false)); TODO Message an Server msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
app.getGameLogic().send(msg);
close();
})); }));
// Zentriere das Popup // Zentriere das Popup
@@ -128,10 +152,10 @@ public class RepayMortage extends Dialog {
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange)); dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
VersionedList<String> propertyOptions = new VersionedList<>(); VersionedList<String> propertyOptions = new VersionedList<>();
List<BuildingProperty> playerProperties = getPlayerProperties(); List<PropertyField> playerProperties = getPlayerProperties();
// Populate the dropdown with property names // Populate the dropdown with property names
for (BuildingProperty property : playerProperties) { for (PropertyField property : playerProperties) {
propertyOptions.add(property.getName()); propertyOptions.add(property.getName());
} }
@@ -146,23 +170,35 @@ public class RepayMortage extends Dialog {
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0)); selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection
if (!propertyOptions.isEmpty()) {
onDropdownSelectionChanged(propertySelector);
}
return dropdownContainer; return dropdownContainer;
} }
/** /**
* Retrieves the list of properties owned by the current player. * Retrieves the list of properties owned by the current player.
* *
* @return List of BuildingProperty objects owned by the player. * @return List of PropertyField objects owned by the player.
*/ */
private List<BuildingProperty> getPlayerProperties() { private List<PropertyField> getPlayerProperties() {
Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()); Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
BoardManager boardManager = app.getGameLogic().getBoardManager(); BoardManager boardManager = app.getGameLogic().getBoardManager();
return boardManager.getPropertyFields(self.getProperties()).stream() return boardManager.getPropertyFields(self.getProperties()).stream()
.filter(property -> property instanceof BuildingProperty) .filter(property -> property instanceof PropertyField)
.map(property -> (BuildingProperty) property) .map(property -> (PropertyField) property)
.filter(p -> p.isMortgaged())
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Updates the UI based on selection changes in the dropdown menu.
*
* @param delta the time elapsed since the last update
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
if(selectionRef.update()) { if(selectionRef.update()) {
@@ -171,7 +207,9 @@ public class RepayMortage extends Dialog {
} }
/** /**
* Handles property selection changes. * Handles changes in the property selection and updates the total repayment cost.
*
* @param playerProperties the dropdown menu for selecting properties
*/ */
private void onDropdownSelectionChanged(Selector<String> playerProperties) { private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem(); String selected = playerProperties.getSelectedItem();
@@ -184,7 +222,7 @@ public class RepayMortage extends Dialog {
int cost = 0; int cost = 0;
for (String s : selectedProperties) { for (String s : selectedProperties) {
cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice(); cost += ((PropertyField) app.getGameLogic().getBoardManager().getFieldByName(s)).getHypo();
} }
String display = String.join(" | ", selectedProperties); String display = String.join(" | ", selectedProperties);
@@ -194,7 +232,7 @@ public class RepayMortage extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the popup and removes its associated GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -203,6 +241,9 @@ public class RepayMortage extends Dialog {
super.close(); super.close();
} }
/**
* Opens the settings menu when the escape key is pressed.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -1,17 +1,13 @@
package pp.monopoly.client.gui.popups; package pp.monopoly.client.gui.popups;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.simsilica.lemur.Axis; import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button; import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Container; import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label; import com.simsilica.lemur.Label;
import com.simsilica.lemur.ListBox;
import com.simsilica.lemur.Selector; import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField; import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.core.VersionedList; import com.simsilica.lemur.core.VersionedList;
@@ -21,7 +17,7 @@ import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.BuyPropertyResponse; import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.model.fields.BoardManager; import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.BuildingProperty; import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
@@ -32,20 +28,43 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* SellHouse is a popup which appears when a player clicks on the "demolish"-button in the BuildingAdminMenu * SellHouse is a popup that appears when a player clicks on the "Demolish" button
* in the BuildingAdminMenu.
* <p>
* This dialog allows players to select their properties and demolish houses or hotels
* for a partial refund of their purchase cost.
* </p>
*/ */
public class SellHouse extends Dialog { public class SellHouse extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the SellHouse dialog UI. */
private final Container sellhouseContainer; private final Container sellhouseContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
/** Text field to display selected properties. */
private TextField selectionDisplay;
/** Reference to track selection changes in the property selector. */
private VersionedReference<Set<Integer>> selectionRef; private VersionedReference<Set<Integer>> selectionRef;
/** Dropdown selector for displaying available properties. */
private Selector<String> propertySelector; private Selector<String> propertySelector;
/** Set of properties selected for selling. */
private Set<String> selectedProperties = new HashSet<>(); private Set<String> selectedProperties = new HashSet<>();
/** Label to display the total refund amount for the selected properties. */
private Label cost = new Label("0", new ElementId("label-Text")); private Label cost = new Label("0", new ElementId("label-Text"));
/**
* Constructs a new SellHouse dialog.
*
* @param app The MonopolyApp instance.
*/
public SellHouse(MonopolyApp app) { public SellHouse(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -73,7 +92,7 @@ public class SellHouse extends Dialog {
Container downContainer = sellhouseContainer.addChild(new Container()); Container downContainer = sellhouseContainer.addChild(new Container());
// Text, der auf der Karte steht // Text, der auf der Karte steht
upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text"))); //TODO hier überall die entsprechenden Variablen einfügen upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
@@ -99,9 +118,16 @@ public class SellHouse extends Dialog {
confirmButton.setFontSize(32); confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog( () -> { confirmButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
// Send the "alter building" message to the server AlterProperty msg = new AlterProperty("SellHouse");
//app.getGameLogic().sendMessage(new AlterBuildingMessage(selected.getId(), false)); TODO Message an Server for (String string : selectedProperties) {
System.out.println(string);
}
msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
for (Integer integer : msg.getProperties()) {
System.out.println("ID des verkaufs: "+integer);
}
app.getGameLogic().send(msg);
close();
})); }));
// Zentriere das Popup // Zentriere das Popup
@@ -149,6 +175,11 @@ public class SellHouse extends Dialog {
selectionDisplay = new TextField(""); // Create TextField for displaying selections selectionDisplay = new TextField(""); // Create TextField for displaying selections
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0)); selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection
if (!propertyOptions.isEmpty()) {
onDropdownSelectionChanged(propertySelector);
}
return dropdownContainer; return dropdownContainer;
} }
@@ -164,9 +195,15 @@ public class SellHouse extends Dialog {
return boardManager.getPropertyFields(self.getProperties()).stream() return boardManager.getPropertyFields(self.getProperties()).stream()
.filter(property -> property instanceof BuildingProperty) .filter(property -> property instanceof BuildingProperty)
.map(property -> (BuildingProperty) property) .map(property -> (BuildingProperty) property)
.filter(p -> app.getGameLogic().getBoardManager().canSell(p))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Updates the dialog UI, tracking changes in the property selection.
*
* @param delta Time since the last update.
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
if(selectionRef.update()) { if(selectionRef.update()) {
@@ -175,7 +212,9 @@ public class SellHouse extends Dialog {
} }
/** /**
* Handles property selection changes. * Handles changes to the property selection.
*
* @param playerProperties The dropdown menu's selection state.
*/ */
private void onDropdownSelectionChanged(Selector<String> playerProperties) { private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem(); String selected = playerProperties.getSelectedItem();
@@ -188,7 +227,7 @@ public class SellHouse extends Dialog {
int cost = 0; int cost = 0;
for (String s : selectedProperties) { for (String s : selectedProperties) {
cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice(); cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice() / 2;
} }
String display = String.join(" | ", selectedProperties); String display = String.join(" | ", selectedProperties);
@@ -198,7 +237,7 @@ public class SellHouse extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the dialog and removes GUI elements from the screen.
*/ */
@Override @Override
public void close() { public void close() {
@@ -207,6 +246,9 @@ public class SellHouse extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -6,7 +6,6 @@ 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.ListBox;
import com.simsilica.lemur.Selector; import com.simsilica.lemur.Selector;
import com.simsilica.lemur.TextField; import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.QuadBackgroundComponent;
@@ -18,8 +17,10 @@ import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.client.gui.SettingsMenu; import pp.monopoly.client.gui.SettingsMenu;
import pp.monopoly.game.server.Player; import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.model.fields.BoardManager; import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.BuildingProperty; import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.PropertyField;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
import java.util.HashSet; import java.util.HashSet;
@@ -28,20 +29,43 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* TakeMortage is a popup which appears when a player clicks on the "TakeMortage"-button in the BuildingAdminMenu * TakeMortage is a popup that appears when a player clicks on the "Take Mortage" button
* in the BuildingAdminMenu.
* <p>
* This popup allows the player to select properties and take a mortgage on them
* to gain financial benefit during gameplay.
* </p>
*/ */
public class TakeMortage extends Dialog { public class TakeMortage extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Main container for the TakeMortage dialog UI. */
private final Container takeMortageContainer; private final Container takeMortageContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
private TextField selectionDisplay; // TextField to display selections
/** Text field to display selected properties. */
private TextField selectionDisplay;
/** Reference to track selection changes in the property selector. */
private VersionedReference<Set<Integer>> selectionRef; private VersionedReference<Set<Integer>> selectionRef;
/** Dropdown selector for displaying available properties. */
private Selector<String> propertySelector; private Selector<String> propertySelector;
/** Set of properties selected for mortgaging. */
private Set<String> selectedProperties = new HashSet<>(); private Set<String> selectedProperties = new HashSet<>();
/** Label to display the total mortgage amount. */
private Label cost = new Label("0", new ElementId("label-Text")); private Label cost = new Label("0", new ElementId("label-Text"));
/**
* Constructs a new TakeMortage dialog.
*
* @param app The MonopolyApp instance.
*/
public TakeMortage(MonopolyApp app) { public TakeMortage(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -69,7 +93,7 @@ public class TakeMortage extends Dialog {
Container downContainer = takeMortageContainer.addChild(new Container()); Container downContainer = takeMortageContainer.addChild(new Container());
// Text, der auf der Karte steht // Text, der auf der Karte steht
upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text"))); //TODO hier überall die entsprechenden Variablen einfügen upContainer.addChild(new Label("„Grundstück wählen:", new ElementId("label-Text")));
upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile upContainer.addChild(new Label("", new ElementId("label-Text")));// Leerzeile
upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); upContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f)));
@@ -95,8 +119,10 @@ public class TakeMortage extends Dialog {
confirmButton.setFontSize(32); confirmButton.setFontSize(32);
confirmButton.addClickCommands(s -> ifTopDialog( () -> { confirmButton.addClickCommands(s -> ifTopDialog( () -> {
app.getGameLogic().playSound(Sound.BUTTON); app.getGameLogic().playSound(Sound.BUTTON);
// Send the "alter building" message to the server AlterProperty msg = new AlterProperty("TakeMortage");
//app.getGameLogic().sendMessage(new AlterBuildingMessage(selected.getId(), false)); TODO Message an Server msg.setProperties(selectedProperties.stream().map(p -> app.getGameLogic().getBoardManager().getFieldByName(p).getId()).map(p -> (Integer) p).collect(Collectors.toSet()));
app.getGameLogic().send(msg);
close();
})); }));
// Zentriere das Popup // Zentriere das Popup
@@ -119,7 +145,7 @@ public class TakeMortage extends Dialog {
/** /**
* Creates a dropdown menu for selecting a property. * Creates a dropdown menu for selecting a property.
* *
* @return The dropdown container. * @return The dropdown container with property options.
*/ */
private Container createPropertyDropdown() { private Container createPropertyDropdown() {
Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X)); Container dropdownContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X));
@@ -127,10 +153,15 @@ public class TakeMortage extends Dialog {
dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange)); dropdownContainer.setBackground(new QuadBackgroundComponent(ColorRGBA.Orange));
VersionedList<String> propertyOptions = new VersionedList<>(); VersionedList<String> propertyOptions = new VersionedList<>();
List<BuildingProperty> playerProperties = getPlayerProperties(); List<PropertyField> playerProperties = getPlayerProperties();
// Populate the dropdown with property names // Populate the dropdown with property names
for (BuildingProperty property : playerProperties) { for (PropertyField property : playerProperties) {
if(property instanceof BuildingProperty) {
if (((BuildingProperty)property).getHouses()!=0) {
break;
}
}
propertyOptions.add(property.getName()); propertyOptions.add(property.getName());
} }
@@ -145,23 +176,38 @@ public class TakeMortage extends Dialog {
selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0)); selectionDisplay.setPreferredSize(new Vector3f(300, 30, 0));
dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container dropdownContainer.addChild(selectionDisplay); // Add it to the dropdown container
// Set initial selection
if (!propertyOptions.isEmpty()) {
onDropdownSelectionChanged(propertySelector);
}
return dropdownContainer; return dropdownContainer;
} }
/** /**
* Retrieves the list of properties owned by the current player. * Retrieves the list of properties owned by the current player.
* <p>
* Only properties that are not currently mortgaged are included.
* </p>
* *
* @return List of BuildingProperty objects owned by the player. * @return List of eligible PropertyField objects owned by the player.
*/ */
private List<BuildingProperty> getPlayerProperties() { private List<PropertyField> getPlayerProperties() {
Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId()); Player self = app.getGameLogic().getPlayerHandler().getPlayerById(app.getId());
BoardManager boardManager = app.getGameLogic().getBoardManager(); BoardManager boardManager = app.getGameLogic().getBoardManager();
return boardManager.getPropertyFields(self.getProperties()).stream() return boardManager.getPropertyFields(self.getProperties()).stream()
.filter(property -> property instanceof BuildingProperty) .filter(property -> property instanceof PropertyField)
.map(property -> (BuildingProperty) property) .map(property -> (PropertyField) property)
.filter(p -> !p.isMortgaged())
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/**
* Updates the dialog UI, tracking changes in the property selection.
*
* @param delta Time since the last update.
*/
@Override @Override
public void update(float delta) { public void update(float delta) {
if(selectionRef.update()) { if(selectionRef.update()) {
@@ -170,7 +216,9 @@ public class TakeMortage extends Dialog {
} }
/** /**
* Handles property selection changes. * Handles changes to the property selection.
*
* @param playerProperties The dropdown menu's selection state.
*/ */
private void onDropdownSelectionChanged(Selector<String> playerProperties) { private void onDropdownSelectionChanged(Selector<String> playerProperties) {
String selected = playerProperties.getSelectedItem(); String selected = playerProperties.getSelectedItem();
@@ -183,7 +231,7 @@ public class TakeMortage extends Dialog {
int cost = 0; int cost = 0;
for (String s : selectedProperties) { for (String s : selectedProperties) {
cost += ((BuildingProperty) app.getGameLogic().getBoardManager().getFieldByName(s)).getHousePrice(); cost += ((PropertyField) app.getGameLogic().getBoardManager().getFieldByName(s)).getHypo();
} }
String display = String.join(" | ", selectedProperties); String display = String.join(" | ", selectedProperties);
@@ -193,7 +241,7 @@ public class TakeMortage extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the dialog and removes GUI elements from the screen.
*/ */
@Override @Override
public void close() { public void close() {
@@ -202,6 +250,9 @@ public class TakeMortage extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
new SettingsMenu(app).open(); new SettingsMenu(app).open();

View File

@@ -14,19 +14,31 @@ 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; import pp.monopoly.notification.Sound;
import static pp.monopoly.Resources.lookup;
/** /**
* TimeOut is a warning popup that is triggered when the connection to the server is interrupted. * TimeOut is a warning popup triggered when the connection to the server is interrupted.
* <p>
* This popup informs the user about the loss of connection and provides an option to acknowledge it.
* </p>
*/ */
public class TimeOut extends Dialog { public class TimeOut extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
/** Semi-transparent overlay background for the dialog. */
private final Geometry overlayBackground; private final Geometry overlayBackground;
/** Main container for the TimeOut dialog UI. */
private final Container timeOutContainer; private final Container timeOutContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer; private final Container backgroundContainer;
/**
* Constructs a new TimeOut dialog to notify the user about a connection loss.
*
* @param app The MonopolyApp instance.
*/
public TimeOut(MonopolyApp app) { public TimeOut(MonopolyApp app) {
super(app.getDialogManager()); super(app.getDialogManager());
this.app = app; this.app = app;
@@ -65,7 +77,10 @@ public class TimeOut extends Dialog {
// Beenden-Button // Beenden-Button
Button quitButton = timeOutContainer.addChild(new Button("Bestätigen", new ElementId("button"))); Button quitButton = timeOutContainer.addChild(new Button("Bestätigen", new ElementId("button")));
quitButton.setFontSize(32); quitButton.setFontSize(32);
quitButton.addClickCommands(source -> close()); quitButton.addClickCommands(source -> ifTopDialog(() -> {
app.getGameLogic().playSound(Sound.BUTTON);
close();
}));
// Zentriere das Popup // Zentriere das Popup
@@ -86,9 +101,9 @@ public class TimeOut extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return The overlay geometry.
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -102,8 +117,9 @@ public class TimeOut extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the TimeOut dialog and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
app.getGuiNode().detachChild(timeOutContainer); // Entferne das Menü app.getGuiNode().detachChild(timeOutContainer); // Entferne das Menü
@@ -112,6 +128,9 @@ public class TimeOut extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

View File

@@ -16,12 +16,24 @@ import pp.dialog.Dialog;
import pp.monopoly.client.MonopolyApp; import pp.monopoly.client.MonopolyApp;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
/**
* WinnerPopUp is a dialog displayed when a player wins the Monopoly game.
* <p>
* This popup congratulates the player for their victory and provides an option to quit the game.
* </p>
*/
public class WinnerPopUp extends Dialog { public class WinnerPopUp extends Dialog {
/** Reference to the Monopoly application instance. */
private final MonopolyApp app; private final MonopolyApp app;
private final Geometry overlayBackground;
private final Container WinnerContainer;
private final Container backgroundContainer;
/** Semi-transparent overlay background for the dialog. */
private final Geometry overlayBackground;
/** Main container for the "Winner" dialog UI. */
private final Container WinnerContainer;
/** Background container providing a styled border around the main dialog. */
private final Container backgroundContainer;
/** /**
* Constructs a new WinnerPopUp dialog. * Constructs a new WinnerPopUp dialog.
@@ -53,7 +65,7 @@ public class WinnerPopUp extends Dialog {
backgroundContainer.setPreferredSize(WinnerContainer.getPreferredSize().addLocal(padding, padding, 0)); backgroundContainer.setPreferredSize(WinnerContainer.getPreferredSize().addLocal(padding, padding, 0));
// Titel // Titel
Label winnerTitle = WinnerContainer.addChild(new Label("Herlichen Glückwunsch, du bist der neue Monopoly Champion!", new ElementId("header"))); Label winnerTitle = WinnerContainer.addChild(new Label("Herzlichen Glückwunsch, du bist der neue Monopoly Champion!", new ElementId("header")));
winnerTitle.setFontSize(25); winnerTitle.setFontSize(25);
// winnerTitle.setColor(ColorRGBA.Black); // winnerTitle.setColor(ColorRGBA.Black);
// Create the image container // Create the image container
@@ -94,9 +106,9 @@ public class WinnerPopUp extends Dialog {
} }
/** /**
* Erstellt einen halbtransparenten Hintergrund für das Menü. * Creates a semi-transparent background overlay for the popup.
* *
* @return Geometrie des Overlays * @return The overlay geometry.
*/ */
private Geometry createOverlayBackground() { private Geometry createOverlayBackground() {
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
@@ -110,7 +122,7 @@ public class WinnerPopUp extends Dialog {
} }
/** /**
* Schließt das Menü und entfernt die GUI-Elemente. * Closes the WinnerPopUp dialog and removes its GUI elements.
*/ */
@Override @Override
public void close() { public void close() {
@@ -120,6 +132,9 @@ public class WinnerPopUp extends Dialog {
super.close(); super.close();
} }
/**
* Handles the escape action to close the dialog.
*/
@Override @Override
public void escape() { public void escape() {
close(); close();

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -1,8 +1,40 @@
package pp.monopoly.game.client; package pp.monopoly.game.client;
public class ActiveState extends ClientState{ import pp.monopoly.game.server.Player;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.ViewAssetsResponse;
/**
* Represents the active client state in the Monopoly game.
* Extends {@link ClientState}.
*/
public class ActiveState extends ClientState {
/**
* Constructs an ActiveState with the specified game logic.
*
* @param logic the client-side game logic associated with this state
* used to manage game interactions and transitions
*/
ActiveState(ClientGameLogic logic) { ActiveState(ClientGameLogic logic) {
super(logic); super(logic);
} }
}
@Override
boolean isTurn() {
return true;
}
@Override
void recivedNextPlayerTurn(NextPlayerTurn msg) {
logic.getBoard().clear();
for (Player player : logic.getPlayerHandler().getPlayers()) {
logic.getBoard().add(player.getFigure());
}
}
@Override
void recivedViewAssetsResponse(ViewAssetsResponse msg) {
}
}

View File

@@ -5,8 +5,10 @@ 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.game.server.PlayerHandler; import pp.monopoly.game.server.PlayerHandler;
import pp.monopoly.message.client.ClientMessage; import pp.monopoly.message.client.ClientMessage;
import pp.monopoly.message.server.BuildInfo;
import pp.monopoly.message.server.BuyPropertyRequest; import pp.monopoly.message.server.BuyPropertyRequest;
import pp.monopoly.message.server.DiceResult; import pp.monopoly.message.server.DiceResult;
import pp.monopoly.message.server.EventDrawCard; import pp.monopoly.message.server.EventDrawCard;
@@ -22,9 +24,11 @@ import pp.monopoly.message.server.TradeReply;
import pp.monopoly.message.server.TradeRequest; 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.Hotel;
import pp.monopoly.model.House;
import pp.monopoly.model.TradeHandler; import pp.monopoly.model.TradeHandler;
import pp.monopoly.model.fields.BoardManager; import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.notification.ClientStateEvent; import pp.monopoly.notification.ClientStateEvent;
import pp.monopoly.notification.DiceRollEvent; import pp.monopoly.notification.DiceRollEvent;
import pp.monopoly.notification.ButtonStatusEvent; import pp.monopoly.notification.ButtonStatusEvent;
@@ -33,6 +37,7 @@ import pp.monopoly.notification.GameEvent;
import pp.monopoly.notification.GameEventBroker; import pp.monopoly.notification.GameEventBroker;
import pp.monopoly.notification.GameEventListener; import pp.monopoly.notification.GameEventListener;
import pp.monopoly.notification.InfoTextEvent; import pp.monopoly.notification.InfoTextEvent;
import pp.monopoly.notification.ItemAddedEvent;
import pp.monopoly.notification.PopUpEvent; import pp.monopoly.notification.PopUpEvent;
import pp.monopoly.notification.Sound; import pp.monopoly.notification.Sound;
import pp.monopoly.notification.SoundEvent; import pp.monopoly.notification.SoundEvent;
@@ -54,7 +59,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
private final List<GameEventListener> listeners = new ArrayList<>(); private final List<GameEventListener> listeners = new ArrayList<>();
/** The game board representing the player's current state. */ /** The game board representing the player's current state. */
private Board board; private Board board = new Board(10, 10, this);
/** 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);
@@ -121,15 +126,6 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
return tradeHandler; return tradeHandler;
} }
/**
* Moves the preview figure to the specified position.
*
* @param pos the new position for the preview figure
*/
public void movePreview(IntPoint pos) {
state.movePreview(pos);
}
/** /**
* Sets the informational text to be displayed to the player. * Sets the informational text to be displayed to the player.
* *
@@ -204,32 +200,21 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
state.update(delta); state.update(delta);
} }
/** public boolean isTurn() {
* Handles the result of a dice roll. return state.isTurn();
* }
* @param msg the message containing the dice roll result
*/
@Override @Override
public void received(DiceResult msg) { public void received(DiceResult msg) {
playSound(Sound.DICE_ROLL); playSound(Sound.DICE_ROLL);
notifyListeners(new DiceRollEvent(msg.getRollResult().get(0), msg.getRollResult().get(1))); notifyListeners(new DiceRollEvent(msg.getRollResult().get(0), msg.getRollResult().get(1)));
} }
/**
* Handles drawing an event card.
*
* @param msg the message containing the drawn card details
*/
@Override @Override
public void received(EventDrawCard msg) { public void received(EventDrawCard msg) {
notifyListeners(new EventCardEvent(msg.getCardDescription())); notifyListeners(new EventCardEvent(msg.getCardDescription()));
} }
/**
* Handles the game over message.
*
* @param msg the message containing game over details
*/
@Override @Override
public void received(GameOver msg) { public void received(GameOver msg) {
if (msg.isWinner()) { if (msg.isWinner()) {
@@ -241,23 +226,17 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
} }
} }
/**
* Handles the start of the game.
*
* @param msg the game start message
*/
@Override @Override
public void received(GameStart msg) { public void received(GameStart msg) {
playerHandler = msg.getPlayerHandler(); playerHandler = msg.getPlayerHandler();
setState(new WaitForTurnState(this)); setState(new WaitForTurnState(this));
for (Player player : playerHandler.getPlayers()) {
board.add(player.getFigure());
}
notifyListeners(new ButtonStatusEvent(false)); notifyListeners(new ButtonStatusEvent(false));
notifyListeners(new UpdatePlayerView());
} }
/**
* Handles jail-related events.
*
* @param msg the message containing jail event details
*/
@Override @Override
public void received(JailEvent msg) { public void received(JailEvent msg) {
if (msg.isGoingToJail()) { if (msg.isGoingToJail()) {
@@ -266,11 +245,6 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
} }
} }
/**
* Updates the status of a player.
*
* @param msg the message containing player status update details
*/
@Override @Override
public void received(PlayerStatusUpdate msg) { public void received(PlayerStatusUpdate msg) {
playerHandler = msg.getPlayerHandler(); playerHandler = msg.getPlayerHandler();
@@ -278,60 +252,37 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
notifyListeners(new UpdatePlayerView()); notifyListeners(new UpdatePlayerView());
} }
/**
* Handles timeout warnings.
*
* @param msg the message containing timeout warning details
*/
@Override @Override
public void received(TimeOutWarning msg) { public void received(TimeOutWarning msg) {
notifyListeners(new PopUpEvent("timeout", msg)); notifyListeners(new PopUpEvent("timeout", msg));
} }
/**
* Displays the player's assets in response to a server query.
*
* @param msg the message containing the player's assets
*/
@Override @Override
public void received(ViewAssetsResponse msg) { public void received(ViewAssetsResponse msg) {
boardManager = msg.getboard(); boardManager = msg.getboard();
} }
/**
* Handles trade replies from other players.
*
* @param msg the message containing the trade reply
*/
@Override @Override
public void received(TradeReply msg) { public void received(TradeReply msg) {
if (msg.isAccepted()) { if (msg.isAccepted()) {
playSound(Sound.TRADE_ACCEPTED); playSound(Sound.TRADE_ACCEPTED);
notifyListeners(new PopUpEvent("tradepos", msg));
} else { } else {
playSound(Sound.TRADE_REJECTED); playSound(Sound.TRADE_REJECTED);
notifyListeners(new PopUpEvent("tradeneg", msg));
} }
} }
/**
* Handles trade requests from other players.
*
* @param msg the message containing the trade request details
*/
@Override @Override
public void received(TradeRequest msg) { public void received(TradeRequest msg) {
tradeHandler = msg.getTradeHandler(); tradeHandler = msg.getTradeHandler();
notifyListeners(new PopUpEvent("tradeRequest", msg)); notifyListeners(new PopUpEvent("tradeRequest", msg));
} }
/**
* Handles the transition to the next player's turn.
*
* @param msg the message indicating it's the next player's turn
*/
@Override @Override
public void received(NextPlayerTurn msg) { public void received(NextPlayerTurn msg) {
notifyListeners(new ButtonStatusEvent(true));
setState(new ActiveState(this)); setState(new ActiveState(this));
notifyListeners(new ButtonStatusEvent(true));
} }
@Override @Override
@@ -343,14 +294,31 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
public void received(NotificationMessage msg) { public void received(NotificationMessage msg) {
if (msg.getKeyWord().equals("rent")) { if (msg.getKeyWord().equals("rent")) {
notifyListeners(new PopUpEvent("rent", msg)); notifyListeners(new PopUpEvent("rent", msg));
playSound(Sound.MONEY_LOST);
} else if (msg.getKeyWord().equals("jailpay")) { } else if (msg.getKeyWord().equals("jailpay")) {
playSound(Sound.MONEY_LOST);
notifyListeners(new PopUpEvent(msg.getKeyWord(), msg)); notifyListeners(new PopUpEvent(msg.getKeyWord(), msg));
} else if(msg.getKeyWord().equals("NoMoneyWarning")) { } else if(msg.getKeyWord().equals("NoMoneyWarning")) {
notifyListeners(new PopUpEvent("NoMoneyWarning", msg)); notifyListeners(new PopUpEvent("NoMoneyWarning", msg));
} else if (msg.getKeyWord().equals("jailpay")) {
notifyListeners(new PopUpEvent("jailpay", msg));
} else if (msg.getKeyWord().equals("jailtryagain")) { } else if (msg.getKeyWord().equals("jailtryagain")) {
notifyListeners(new PopUpEvent("jailtryagain", msg)); notifyListeners(new PopUpEvent("jailtryagain", msg));
} else if(msg.getKeyWord().equals("ReceivedRent")) {
playSound(Sound.MONEY_COLLECTED);
notifyListeners(new PopUpEvent("ReceivedRent", msg));
} }
} }
@Override
public void received(BuildInfo msg) {
System.out.println("TRIGGER BUILD INFO");
if (msg.isAdded()) {
BuildingProperty property = ((BuildingProperty)boardManager.getFieldAtIndex(msg.getId()));
if (property.getHotel() == 1 ) {
board.add(new Hotel(property.getId()));
} else {
board.add(new House( property.getHouses(), property.getId()));
}
}
}
} }

View File

@@ -6,24 +6,29 @@
//////////////////////////////////////// ////////////////////////////////////////
package pp.monopoly.game.client; package pp.monopoly.game.client;
import pp.monopoly.model.IntPoint;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.System.Logger.Level; import java.lang.System.Logger.Level;
import pp.monopoly.message.server.GameStart;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.NotificationMessage;
import pp.monopoly.message.server.PlayerStatusUpdate;
import pp.monopoly.message.server.ViewAssetsResponse;
/** /**
* Defines the behavior and state transitions for the client-side game logic. * Defines the behavior and state transitions for the client-side game logic in Monopoly.
* Different states of the game logic implement this interface to handle various game events and actions. * Different states of the game logic implement this abstract class to handle various game events and actions.
*/ */
abstract class ClientState { abstract class ClientState {
/** /**
* The game logic object. * The game logic object managing the client-side state.
*/ */
final ClientGameLogic logic; final ClientGameLogic logic;
/** /**
* Constructs a client state of the specified game logic. * Constructs a client state for the specified game logic.
* *
* @param logic the game logic * @param logic the game logic
*/ */
@@ -49,31 +54,53 @@ abstract class ClientState {
} }
/** /**
* Checks if the battle state should be shown. * Checks if the player's turn should be shown in the current state.
* *
* @return true if the battle state should be shown, false otherwise * @return true if the player's turn should be shown, false otherwise
*/ */
boolean showTurn() { boolean isTurn() {
return false; return false;
} }
/** /**
* Moves the preview figure to the specified position. * Starts the battle based on the server message.
* *
* @param pos the new position for the preview figure * @param msg the message indicating whose turn it is to shoot
*/ */
void movePreview(IntPoint pos) { void receivedGameStart(GameStart msg) {
ClientGameLogic.LOGGER.log(Level.DEBUG, "movePreview has no effect in {0}", getName()); //NON-NLS ClientGameLogic.LOGGER.log(Level.ERROR, "receivedGameStart not allowed in {0}", getName()); //NON-NLS
} }
/** /**
* Loads a map from the specified file. * Updateds the view based on the new player status.
* *
* @param file the file to load the map from * @param msg the message containing the new player status
* @throws IOException if the map cannot be loaded in the current state
*/ */
void loadMap(File file) throws IOException { void recivedPlayerStatusUpdate(PlayerStatusUpdate msg) {
throw new IOException("You are not allowed to load a map in this state of the game"); ClientGameLogic.LOGGER.log(Level.ERROR, "recivedPlayerStatusUpdate not allowed in {0}", getName()); //NON-NLS
}
void recivedNextPlayerTurn(NextPlayerTurn msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "recivedNextPlayerTurn not allowed in {0}", getName()); //NON-NLS
}
void recivedNotificationMessage(NotificationMessage msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "recivedNotificationMessage not allowed in {0}", getName()); //NON-NLS
}
void recivedViewAssetsResponse(ViewAssetsResponse msg) {
ClientGameLogic.LOGGER.log(Level.ERROR, "recivedViewAssetsResponse not allowed in {0}", getName()); //NON-NLS
}
/**
* Loads a game configuration from the specified file.
*
* @param file the file to load the game configuration from
* @throws IOException if the configuration cannot be loaded in the current state
*/
void loadGameConfig(File file) throws IOException {
throw new IOException("You are not allowed to load a game configuration in this state of the game.");
} }
/** /**
@@ -81,5 +108,7 @@ abstract class ClientState {
* *
* @param delta time in seconds since the last update call * @param delta time in seconds since the last update call
*/ */
void update(float delta) { /* do nothing by default */ } void update(float delta) {
// Default implementation does nothing
}
} }

View File

@@ -1,8 +1,24 @@
package pp.monopoly.game.client; package pp.monopoly.game.client;
public class LobbyState extends ClientState{ import pp.monopoly.message.server.GameStart;
/**
* Represents the lobby state of the client in the Monopoly game.
* Extends {@link ClientState}.
*/
public class LobbyState extends ClientState {
/**
* Constructs a LobbyState with the specified game logic.
*
* @param logic the client-side game logic
*/
LobbyState(ClientGameLogic logic) { LobbyState(ClientGameLogic logic) {
super(logic); super(logic);
} }
@Override
void receivedGameStart(GameStart msg) {
logic.setState(new WaitForTurnState(logic));
}
} }

View File

@@ -1,8 +1,29 @@
package pp.monopoly.game.client; package pp.monopoly.game.client;
public class WaitForTurnState extends ClientState{ import pp.monopoly.message.server.NextPlayerTurn;
/**
* Represents the state where the client is waiting for their turn in the Monopoly game.
* Extends {@link ClientState}.
*/
public class WaitForTurnState extends ClientState {
/**
* Constructs a WaitForTurnState with the specified game logic.
*
* @param logic the client-side game logic
*/
WaitForTurnState(ClientGameLogic logic) { WaitForTurnState(ClientGameLogic logic) {
super(logic); super(logic);
} }
@Override
boolean isTurn() {
return true;
}
@Override
void recivedNextPlayerTurn(NextPlayerTurn msg) {
logic.setState(new ActiveState(logic));
}
} }

View File

@@ -90,7 +90,7 @@ public class Player implements FieldVisitor<Void>{
return figure; return figure;
} }
public PlayerColor getColor() { public static PlayerColor getColor(int id) {
switch ((id%6)+1) { switch ((id%6)+1) {
case 1: return PlayerColor.CYAN; case 1: return PlayerColor.CYAN;
case 2: return PlayerColor.YELLOW; case 2: return PlayerColor.YELLOW;
@@ -246,7 +246,7 @@ public class Player implements FieldVisitor<Void>{
*/ */
public void sellProperty(PropertyField property) { public void sellProperty(PropertyField property) {
if (property.getOwner() == this) { if (property.getOwner() == this) {
properties.remove(property); properties.remove(property.getId());
property.setOwner(null); property.setOwner(null);
} }
} }
@@ -331,6 +331,13 @@ public class Player implements FieldVisitor<Void>{
state.useJailCard(); state.useJailCard();
} }
private void sendRentNotification(String keyword, Player player, int amount) {
NotificationMessage msg = new NotificationMessage(keyword);
msg.setRentAmount(amount);
msg.setRentOwnerId(player.getName());
getHandler().getLogic().send(player, msg);
}
@Override @Override
public Void visit(BuildingProperty field) { public Void visit(BuildingProperty field) {
if(field.getOwner() == null) { if(field.getOwner() == null) {
@@ -340,10 +347,8 @@ public class Player implements FieldVisitor<Void>{
int rent = field.calcRent(); int rent = field.calcRent();
field.getOwner().earnMoney(rent); field.getOwner().earnMoney(rent);
pay(rent); pay(rent);
NotificationMessage msg = new NotificationMessage("rent"); sendRentNotification("ReceivedRent", field.getOwner(), rent);
msg.setRentAmount(rent); sendRentNotification("rent", this, rent);
msg.setRentOwnerId(field.getOwner().getName());
getHandler().getLogic().send(this, msg);
} }
return null; return null;
} }
@@ -352,18 +357,16 @@ public class Player implements FieldVisitor<Void>{
public Void visit(FoodField field) { public Void visit(FoodField field) {
if(field.getOwner() == null) { if(field.getOwner() == null) {
if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest()); if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest());
} else { } else if (field.getOwner() != this){
int factor = 4; int factor = 40;
if (field.getOwner().getNumProp(field) == 2) { if (field.getOwner().getNumProp(field) == 2) {
factor = 10; factor = 100;
} }
int rent = rollResult.calcTotal()*factor; int rent = rollResult.calcTotal()*factor;
field.getOwner().earnMoney(rent); field.getOwner().earnMoney(rent);
pay(rent); pay(rent);
NotificationMessage msg = new NotificationMessage("rent"); sendRentNotification("ReceivedRent", field.getOwner(), rent);
msg.setRentAmount(rent); sendRentNotification("rent", this, rent);
msg.setRentOwnerId(field.getOwner().getName());
getHandler().getLogic().send(this, msg);
} }
return null; return null;
} }
@@ -372,15 +375,13 @@ public class Player implements FieldVisitor<Void>{
public Void visit(GateField field) { public Void visit(GateField field) {
if(field.getOwner() == null) { if(field.getOwner() == null) {
if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest()); if (field.getPrice() <= accountBalance) getHandler().getLogic().send(this, new BuyPropertyRequest());
} else { } else if (field.getOwner() != this){
int rent = field.calcRent() * field.getOwner().getNumProp(field); int rent = field.calcRent() * field.getOwner().getNumProp(field);
field.getOwner().earnMoney(rent); field.getOwner().earnMoney(rent);
pay(rent); pay(rent);
NotificationMessage msg = new NotificationMessage("rent"); sendRentNotification("ReceivedRent", field.getOwner(), rent);
msg.setRentAmount(rent); sendRentNotification("rent", this, rent);
msg.setRentOwnerId(field.getOwner().getName());
getHandler().getLogic().send(this, msg);
} }
return null; return null;
} }
@@ -445,6 +446,11 @@ public class Player implements FieldVisitor<Void>{
handler.getLogic().send(this, new JailEvent(true)); handler.getLogic().send(this, new JailEvent(true));
} }
void jail() {
state = new JailState();
fieldID = 10;
}
/** /**
* Return the number of Properties of the speciefied fild type * Return the number of Properties of the speciefied fild type
* @param field the type of field to search for * @param field the type of field to search for
@@ -482,8 +488,8 @@ public class Player implements FieldVisitor<Void>{
} }
return total; return total;
} }
// private static int c = 0; // private static int c = 0;
/** /**
* Inner class for dice functionality in the game. * Inner class for dice functionality in the game.
* Rolls random dice values. * Rolls random dice values.
@@ -498,8 +504,8 @@ public class Player implements FieldVisitor<Void>{
*/ */
private static int rollDice() { private static int rollDice() {
return random.nextInt(6) + 1; return random.nextInt(6) + 1;
// c++; // c++;
// return (c%2 == 0)? 3: 2;
// if(c < 7) { // if(c < 7) {
// return 3; // return 3;
// } else { // } else {
@@ -521,12 +527,13 @@ public class Player implements FieldVisitor<Void>{
for (PropertyField field : getPropertyFields()) { for (PropertyField field : getPropertyFields()) {
field.setOwner(null); field.setOwner(null);
} }
properties.clear();
} }
/** /**
* A interface representing the PlayerStates * A interface representing the PlayerStates
*/ */
private interface PlayerState { interface PlayerState {
/** /**
* Handles the logic for rolling Dice * Handles the logic for rolling Dice
* @return the {@link DiceResult} of this the DiceRoll * @return the {@link DiceResult} of this the DiceRoll
@@ -619,6 +626,7 @@ public class Player implements FieldVisitor<Void>{
if (rollResult.isDoublets()) { if (rollResult.isDoublets()) {
handler.getLogic().send(Player.this, new JailEvent(false)); handler.getLogic().send(Player.this, new JailEvent(false));
state = new ActiveState(); state = new ActiveState();
getHandler().getLogic().send(Player.this, new NextPlayerTurn());
} else { } else {
remainingAttempts--; remainingAttempts--;
} }
@@ -630,6 +638,7 @@ public class Player implements FieldVisitor<Void>{
public void payBail() { public void payBail() {
pay(500); pay(500);
state = new ActiveState(); state = new ActiveState();
getHandler().getLogic().send(Player.this, new NextPlayerTurn());
} }
@Override @Override

View File

@@ -6,22 +6,24 @@ import com.jme3.math.ColorRGBA;
* Enum representing six distinct colors for players in the game. * Enum representing six distinct colors for players in the game.
*/ */
public enum PlayerColor { public enum PlayerColor {
CYAN(new ColorRGBA(1 / 255f, 190 / 255f, 254 / 255f, 1)), CYAN(new ColorRGBA(1 / 255f, 190 / 255f, 254 / 255f, 1), "Cyan"),
YELLOW(new ColorRGBA(255 / 255f, 255 / 255f, 0 / 255f, 1)), YELLOW(new ColorRGBA(255 / 255f, 255 / 255f, 0 / 255f, 1), "Gelb"),
RED(new ColorRGBA(255 / 255f, 0 / 255f, 0 / 255f, 1)), RED(new ColorRGBA(255 / 255f, 0 / 255f, 0 / 255f, 1), "Rot"),
PINK(new ColorRGBA(255 / 255f, 77 / 255f, 166 / 255f, 1)), PINK(new ColorRGBA(255 / 255f, 77 / 255f, 166 / 255f, 1), "Pink"),
GREEN(new ColorRGBA(0 / 255f, 204 / 255f, 0 / 255f, 1)), GREEN(new ColorRGBA(0 / 255f, 204 / 255f, 0 / 255f, 1), "Grün"),
PURPLE(new ColorRGBA(143 / 255f, 0 / 255f, 255 / 255f, 1)); PURPLE(new ColorRGBA(143 / 255f, 0 / 255f, 255 / 255f, 1), "Lila");
private final ColorRGBA color; private final ColorRGBA color;
private final String colorName;
/** /**
* Constructs a PlayerColor with the specified ColorRGBA value. * Constructs a PlayerColor with the specified ColorRGBA value.
* *
* @param color the ColorRGBA value associated with the player color * @param color the ColorRGBA value associated with the player color
*/ */
PlayerColor(ColorRGBA color) { PlayerColor(ColorRGBA color, String colorName) {
this.color = color; this.color = color;
this.colorName = colorName;
} }
/** /**
@@ -32,4 +34,13 @@ public enum PlayerColor {
public ColorRGBA getColor() { public ColorRGBA getColor() {
return color; return color;
} }
/**
* Gets the Name of the Color
*
* @return a String with re corresponing name
*/
public String getColorName() {
return colorName;
}
} }

View File

@@ -4,11 +4,11 @@ import java.lang.System.Logger;
import java.lang.System.Logger.Level; import java.lang.System.Logger.Level;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.jme3.math.Vector3f;
import pp.monopoly.MonopolyConfig; import pp.monopoly.MonopolyConfig;
import pp.monopoly.message.client.AlterProperty; import pp.monopoly.message.client.AlterProperty;
import pp.monopoly.message.client.BuyPropertyResponse; import pp.monopoly.message.client.BuyPropertyResponse;
@@ -20,6 +20,7 @@ import pp.monopoly.message.client.RollDice;
import pp.monopoly.message.client.TradeOffer; import pp.monopoly.message.client.TradeOffer;
import pp.monopoly.message.client.TradeResponse; import pp.monopoly.message.client.TradeResponse;
import pp.monopoly.message.client.ViewAssetsRequest; import pp.monopoly.message.client.ViewAssetsRequest;
import pp.monopoly.message.server.BuildInfo;
import pp.monopoly.message.server.GameOver; import pp.monopoly.message.server.GameOver;
import pp.monopoly.message.server.GameStart; import pp.monopoly.message.server.GameStart;
import pp.monopoly.message.server.NextPlayerTurn; import pp.monopoly.message.server.NextPlayerTurn;
@@ -97,6 +98,17 @@ public class ServerGameLogic implements ClientInterpreter {
} }
} }
/**
* Sends a message to all players in the game.
*
* @param msg the ServerMessage to send
*/
void sendAll(ServerMessage msg) {
for (Player player : playerHandler.getPlayers()) {
send(player, msg);
}
}
/** /**
* Adds a new player to the game if the game is in the LOBBY state and the maximum * Adds a new player to the game if the game is in the LOBBY state and the maximum
* player limit has not been reached. * player limit has not been reached.
@@ -208,9 +220,12 @@ public class ServerGameLogic implements ClientInterpreter {
} }
if (player != null) { if (player != null) {
player.setName(msg.getName()); String name = msg.getName();
player.setFigure(new Figure(1, -10, -10, Rotation.LEFT, msg.getFigure())); String truc = name.length() > 10 ? name.substring(0, 15) : name;
//TODO add figure to the map player.setName(truc);
Figure figure = new Figure(new Vector3f(0, 1, 0), Rotation.NORTH, msg.getFigure());
player.setFigure(figure);
// board.addFigure(figure);
playerHandler.setPlayerReady(player, true); playerHandler.setPlayerReady(player, true);
LOGGER.log(Level.DEBUG, "Player {0} is ready", player.getName()); LOGGER.log(Level.DEBUG, "Player {0} is ready", player.getName());
} }
@@ -298,7 +313,7 @@ public class ServerGameLogic implements ClientInterpreter {
receiver.addJailCard(); receiver.addJailCard();
} }
for (int i = 0; i < tradeHandler.getRequestedAmount(); i++) { for (int i = 0; i < tradeHandler.getRequestedJailCards(); i++) {
sender.addJailCard(); sender.addJailCard();
receiver.removeJailCard(); receiver.removeJailCard();
} }
@@ -382,49 +397,65 @@ public class ServerGameLogic implements ClientInterpreter {
public void received(AlterProperty msg, int from) { public void received(AlterProperty msg, int from) {
Player sender = playerHandler.getPlayerById(from); Player sender = playerHandler.getPlayerById(from);
Set<PropertyField> properties = new HashSet<>();
for (Integer integer : msg.getProperties()) {
properties.add( (PropertyField)boardManager.getFieldAtIndex(integer));
}
if (msg.getKeyword().equals("TakeMortage")) { if (msg.getKeyword().equals("TakeMortage")) {
for (PropertyField field : sender.getPropertyFields()) { for (PropertyField field : properties) {
if(field instanceof BuildingProperty) {
if (((BuildingProperty)field).getHouses()!=0) {
break;
}
}
field.setMortgaged(true); field.setMortgaged(true);
sender.earnMoney(field.getHypo()); sender.earnMoney(field.getHypo());
} }
} else if (msg.getKeyword().equals("RepayMortage")) { } else if (msg.getKeyword().equals("RepayMortage")) {
for (PropertyField field : sender.getPropertyFields()) { for (PropertyField field : properties) {
if(sender.getAccountBalance() >= field.getHypo()) { if(sender.getAccountBalance() >= field.getHypo()) {
field.setMortgaged(false); field.setMortgaged(false);
sender.pay(field.getHypo()); sender.pay(field.getHypo());
} }
} }
} else if(msg.getKeyword().equals("BuyHouse")) { } else if(msg.getKeyword().equals("BuyHouse")) {
for (BuildingProperty field : sender.getPropertyFields().stream().filter(p -> p instanceof BuildingProperty).map(p -> (BuildingProperty) p).collect(Collectors.toList())) { for (BuildingProperty field : properties.stream().map(p -> (BuildingProperty) p).collect(Collectors.toList())) {
if (boardManager.canBuild(field) && sender.getAccountBalance() >= field.getHousePrice()) { if (boardManager.canBuild(field) && sender.getAccountBalance() >= field.getHousePrice()) {
field.build(); field.build();
updateAllPlayers();
sendAll( new BuildInfo(field.getId(), true));
sender.pay(field.getHousePrice()); sender.pay(field.getHousePrice());
} }
} }
} else if(msg.getKeyword().equals("SellHouse")) { } else if(msg.getKeyword().equals("SellHouse")) {
for (BuildingProperty field : sender.getPropertyFields().stream().filter(p -> p instanceof BuildingProperty).map(p -> (BuildingProperty) p).collect(Collectors.toList())) { for (BuildingProperty field : properties.stream().map(p -> (BuildingProperty) p).collect(Collectors.toList())) {
if (boardManager.canSell(field)) { if (boardManager.canSell(field)) {
field.sell(); field.sell();
sender.earnMoney(field.getHousePrice()); updateAllPlayers();
sendAll( new BuildInfo(field.getId(), false));
sender.earnMoney(field.getHousePrice() / 2);
} }
} }
} }
updateAllPlayers(); updateAllPlayers();
} }
@Override @Override
public void received(NotificationAnswer msg, int from) { public void received(NotificationAnswer msg, int from) {
if(msg.getA().equals("UseJailCard")) { if(msg.getKeyword().equals("UseJailCard")) {
playerHandler.getPlayerById(from).useJailCard(); playerHandler.getPlayerById(from).useJailCard();
} else if (msg.getA().equals("PayJail")) { } else if (msg.getKeyword().equals("PayJail")) {
playerHandler.getPlayerById(from).payBail(); playerHandler.getPlayerById(from).payBail();
} else if(msg.getA().equals("hack")) { } else if(msg.getKeyword().equals("hack")) {
System.out.println("HAck ausgeführt"); // for (BuildingProperty bp : boardManager.getPropertyFields( List.of(1,3)).stream().filter(p -> p instanceof BuildingProperty).map(p -> (BuildingProperty) p).collect(Collectors.toList())) {
for (BuildingProperty bp : boardManager.getPropertyFields( List.of(1,3)).stream().filter(p -> p instanceof BuildingProperty).map(p -> (BuildingProperty) p).collect(Collectors.toList())) { // bp.build();
bp.setOwner(playerHandler.getPlayerById(0)); // }
playerHandler.getPlayerById(0).addProperty(bp.getId()); for(PropertyField field : boardManager.getBoard().stream().filter(p -> p instanceof PropertyField).map(p -> (PropertyField) p).collect(Collectors.toList())) {
field.setOwner(playerHandler.getPlayerById(0));
playerHandler.getPlayerById(0).addProperty(field.getId());
} }
playerHandler.getPlayerById(0).earnMoney(20000);
} }
updateAllPlayers(); updateAllPlayers();

View File

@@ -9,9 +9,8 @@ import com.jme3.network.serializing.Serializable;
public class BuyPropertyResponse extends ClientMessage{ public class BuyPropertyResponse extends ClientMessage{
/** /**
* Constructs a BuyPropertyRequest with the specified property ID. * Constructs a BuyPropertyRequest
* *
* @param propertyId the ID of the property to buy
*/ */
public BuyPropertyResponse() {} public BuyPropertyResponse() {}

Some files were not shown because too many files have changed in this diff Show More